From a6288f98111d3212580a2c9ee9fce21cebead312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:57:11 -0300 Subject: [PATCH 01/25] state to lexicalNode --- packages/lexical/src/LexicalNode.ts | 39 ++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index 0aa1d1ca487..d39db3ea387 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -54,6 +54,7 @@ export type NodeMap = Map; export type SerializedLexicalNode = { type: string; version: number; + state?: State; }; /** @internal */ @@ -171,6 +172,8 @@ export type DOMExportOutput = { export type NodeKey = string; +export type State = {[Key in string]?: string | number | boolean | State}; + export class LexicalNode { // Allow us to look up the type including static props ['constructor']!: KlassConstructor; @@ -185,6 +188,25 @@ export class LexicalNode { __prev: null | NodeKey; /** @internal */ __next: null | NodeKey; + /** @internal */ + __state: State = {}; + + getState(key: keyof T): T[keyof T] | undefined { + const self = this.getLatest(); + return (self.__state as T)[key]; + } + + setState( + key: keyof T, + value: T[keyof T] | undefined, + ) { + const self = this.getWritable(); + if (value === undefined) { + delete (self.__state as T)[key]; + return; + } + (self.__state as T)[key] = value; + } // Flow doesn't support abstract classes unfortunately, so we can't _force_ // subclasses of Node to implement statics. All subclasses of Node should have @@ -869,7 +891,11 @@ export class LexicalNode { * * */ exportJSON(): SerializedLexicalNode { - invariant(false, 'exportJSON: base method not extended'); + return { + type: this.constructor.getType(), + version: 1, + ...(objetcIsEmpty(this.__state) ? {} : {state: this.__state}), + }; } /** @@ -1238,3 +1264,14 @@ export function insertRangeAfter( currentNode = currentNode.insertAfter(nodeToInsert); } } + +/** + * The best way to check if an object is empty in O(1) + * @see https://stackoverflow.com/a/59787784/10476393 + */ +function objetcIsEmpty(obj: object) { + for (const key in obj) { + return false; + } + return true; +} From a90a719bf28d3e39704febef4b3f083999072472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 30 Jan 2025 10:23:28 -0300 Subject: [PATCH 02/25] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a62a1a64e764a607935527c63bf8393d126084d1 Author: James Fitzsimmons <119275535+james-atticus@users.noreply.github.com> Date: Thu Jan 30 19:13:35 2025 +1100 [lexical-mark] Feature: include inline decorator nodes in marks (#7086) commit 881c7fe726a59b6bff6d87114ebe5140c48536ad Author: Bob Ippolito Date: Thu Jan 30 00:13:00 2025 -0800 [lexical-utils] Fix: Modify $reverseDfs to be a right-to-left variant of $dfs (#7112) commit ce2bb4538624ff4b181284ae716c10dc1c465492 Author: Nigel Gutzmann Date: Wed Jan 29 14:41:12 2025 -0800 [lexical-utils] Feature: add reverse dfs iterator (#7107) commit 3a140d205ac9ee5d2faa3b5696047ac67bab1d01 Author: mohammed shaheer kp <72137242+mshaheerz@users.noreply.github.com> Date: Tue Jan 28 06:19:45 2025 +0530 [lexical-playground] Bug Fix: Ensure Delete Node handles all node types (#7096) Co-authored-by: shaheerkpzaigo commit 8e2ede2b164026f1329c64bb6c7b137e313ba174 Author: Adam Pugh Date: Mon Jan 27 18:49:38 2025 -0600 Listeners Lexical: 3 updates to spelling and grammar - Update listeners.md (#7100) commit 9fcc494578edf04e850f0df2e41ab0910d6a4ba5 Author: Adam Pugh Date: Mon Jan 27 18:49:34 2025 -0600 Lexical Docs: 2 updates to spelling README.md (#7102) commit 946a6dfbdad12a2b62dc6d6625fd9ea961913c81 Author: Adam Pugh Date: Mon Jan 27 18:49:29 2025 -0600 Selection | Lexical: 1 Spelling Update Update selection.md (#7103) commit ce93ea6acd93fee2df9b651969154c4f9a04a1a6 Author: Adam Pugh Date: Mon Jan 27 18:49:25 2025 -0600 Creating a React Plugin: 1 Grammar Update - Update create_plugin.md (#7104) commit ed29d896d7cc6975dbcf1a11265c857e74d5128d Author: Adam Pugh Date: Mon Jan 27 18:49:21 2025 -0600 Working with DOM Events: 2 Spelling and Grammar Updates Update dom-ev… (#7105) commit 212b70ffa6dca2f29292845e506b963081180c9b Author: James Fitzsimmons <119275535+james-atticus@users.noreply.github.com> Date: Mon Jan 27 08:48:09 2025 +1100 [lexical-yjs] Bug Fix: handle text node being split by Yjs redo (#7098) commit 6a98a477436bf6bc6ac988a8473ec647f7eab38e Author: Torleif Berger Date: Fri Jan 24 21:46:45 2025 +0100 [lexical-react] Bug Fix: Import `JSX` type from React to prevent "Cannot find namespace 'JSX'"-error when type-checking with React 19 (#7080) commit f8e5968cff9c0c1a3e5ec3529d3e127888f557d6 Author: Tetsuya <62472294+EruditionTu@users.noreply.github.com> Date: Sat Jan 25 04:06:57 2025 +0800 [lexical] Chore: Rename variable and add comments for Safari compositing workaround (#7092) commit 81c9ab6d81e8e3ae80bbfd547abc8e63332468a1 Author: Mateo Vuković <195247756+hellovuki@users.noreply.github.com> Date: Fri Jan 24 18:44:05 2025 +0100 Fix: Use already defined RegisteredNodes type (#7085) commit 63958a2f715aea80287ac1e94f8264f44a824674 Author: Sherry Date: Tue Jan 21 18:15:21 2025 +0800 [playground] Bug fix: prevent growing whitespaces in markdown table toggle (#7041) Co-authored-by: Bob Ippolito commit d9f9924357d0ab981023609411940062bd09015a Author: Sherry Date: Tue Jan 21 14:58:08 2025 +0800 Unrevert [Breaking Change][lexical] Bug Fix: Commit updates on editor.setRootElement(null) #7023 (#7068) commit 92fa0a304f56d25f8e7a489ad42bc4c3534910fa Author: mohammed shaheer kp <72137242+mshaheerz@users.noreply.github.com> Date: Tue Jan 21 06:23:24 2025 +0530 [lexical-playground] plugins TableOfContent Scroll smooth behaviour A… (#7069) commit 2e4a63e372c51336a32f786817cafeafbda1ffa5 Author: Ivaylo Pavlov Date: Mon Jan 20 02:37:34 2025 +0000 [lexical-playground] Fix Columns Layout Item Overflow (#7066) commit d319b07bc474d8a7caecc7ee601336f9cc211a71 Author: Bob Ippolito Date: Sun Jan 19 14:45:41 2025 -0800 Change fork modules to use production only when NODE_ENV explicitly set to production (#7065) commit 46c9c2f9d738f974cc9b7cacf7088c168edba78c Author: CityHunter <62472294+EruditionTu@users.noreply.github.com> Date: Sat Jan 18 13:00:38 2025 +0800 [lexical] Bug Fix: In the Safari browser, during the compositing event process, the delete key exhibits unexpected behavior. (#7061) Co-authored-by: 涂博闻 commit 92a1cd704b7e1642349f487be3e2026b88a63457 Author: Violet Rosenzweig Date: Thu Jan 16 18:44:11 2025 -0500 docs: Change "here" link to more descriptive text (#7058) commit f6377a360ad15fb0f040f786dbfc918ba41862ed Author: Aman Harwara Date: Fri Jan 17 02:08:17 2025 +0530 [lexical-table] Bug Fix: Prevent error if pasted table has empty row (#7057) commit 083502979201aa0a7c9f58af3d8f56e2ec56b05b Author: Aman Harwara Date: Fri Jan 17 00:18:08 2025 +0530 [lexical-list] Bug Fix: Prevent error when calling formatList when selection is at root (#6994) commit 940435d30da0a2f09d5e3eda2e0a1eeb73923554 Author: Brayden <1311325+redstar504@users.noreply.github.com> Date: Wed Jan 15 16:10:01 2025 -0800 fix: iOS Autocorrect strips formatting by reporting wrong dataType (#5789) Co-authored-by: Bob Ippolito commit 136a56558695b0506269b4584bacc330961f5fc7 Author: Aman Harwara Date: Thu Jan 16 04:48:32 2025 +0530 [lexical-yjs] Feature: Allow passing in custom `syncCursorPositions` function to collab hook (#7053) commit 415c5761f0bb734b35b1eb93e77b9012e3d8e2be Author: Maksim Horbachevsky Date: Wed Jan 15 18:18:03 2025 -0500 fix: triple click around inline elements (links) (#7055) commit a3ef4f39afb34b1c2acd84a3347eb88184e5c30d Author: Ivaylo Pavlov Date: Wed Jan 15 23:15:39 2025 +0000 [lexical-table] Support table alignment (#7044) commit 29d733c28ff7dca52d9293ed71ea1c0be9e7372e Author: Sherry Date: Wed Jan 15 21:50:07 2025 +0800 Revert [Breaking Change][lexical] Bug Fix: Commit updates on editorSetRootElement(null) (#7023) (#7052) commit 65ce66afeb2e6f67e40f6c0e2e43bdcf06f17320 Author: Bob Ippolito Date: Tue Jan 14 14:57:54 2025 -0800 [lexical] Bug Fix: Normalize selection after applyDOMRange to account for Firefox differences (#7050) commit bbc07afa4eaccfba2c28fbe4f9deafd1d503f001 Author: Bob Ippolito Date: Tue Jan 14 08:55:46 2025 -0800 [*] Bug Fix: Use GITHUB_OUTPUT instead of GITHUB_ENV for size-limit action (#7051) commit c8f27ed77d59cb2f462217ed3cf6ea5de4cb73c6 Author: Bob Ippolito Date: Tue Jan 14 06:36:13 2025 -0800 [Breaking Change][*] Chore: Use terser for optimizing cjs prod build (#7047) commit 8bd22d5339c0dda7e11a3946389258c78a940037 Author: Bob Ippolito Date: Mon Jan 13 07:09:31 2025 -0800 [lexical] Bug Fix: Handle MutationObserver/input event re-ordering when using contentEditable inside of an iframe (#7045) commit 930629cc0555e11aba196cc434c36c9dbf236960 Author: Ivaylo Pavlov Date: Sat Jan 11 06:03:30 2025 +0000 Clean up nested editor update (#7039) commit bd874a3edae21e4b89ba54be8c23c00ef83feb17 Author: Bob Ippolito Date: Fri Jan 10 15:23:54 2025 -0800 [Breaking Change][lexical][lexical-selection][lexical-list] Bug Fix: Fix infinite loop when splitting invalid ListItemNode (#7037) commit 541fa432854495bb167510cd2157495cdb4bc54b Author: Bob Ippolito Date: Thu Jan 9 12:42:23 2025 -0800 v0.23.1 (#7035) Co-authored-by: Lexical GitHub Actions Bot <> commit d7abafde785fbb18c2018260fcc77766863a9c43 Author: Bob Ippolito Date: Thu Jan 9 08:33:12 2025 -0800 [Breaking Change][lexical] Bug Fix: Commit updates on editor.setRootElement(null) (#7023) commit 6add5152339a0569c75606cb16012e3fce4094b1 Author: Bob Ippolito Date: Wed Jan 8 17:27:15 2025 -0800 [lexical] Fix TabNode deserialization regression (#7031) commit 33e36779a335d1f4fcdb9969f59275b7a5629337 Author: Maksim Horbachevsky Date: Wed Jan 8 14:59:03 2025 -0500 [lexical-react] Feature: Merge TabIndentionPlugin and ListMaxIndentLevelPlugin plugins (#7018) commit 7de86e4dc9331faaf358c03c46ff07785d9d708a Author: James Fitzsimmons <119275535+james-atticus@users.noreply.github.com> Date: Wed Jan 8 09:45:25 2025 +1100 [lexical-mark] Bug Fix: reverse ternary in MarkNode.addID (#7020) commit 796113090d2f85892b2a45bf478a15917acb40e0 Author: Bob Ippolito Date: Sun Jan 5 13:55:25 2025 -0800 v0.23.0 (#7017) Co-authored-by: Lexical GitHub Actions Bot <> commit 2b4252d9360e1196199f0709fdf25974b64d5e6f Author: Aman Harwara Date: Sat Jan 4 11:31:19 2025 +0530 [lexical-yjs] Feature: Expose function to get anchor and focus nodes for given user awareness state (#6942) commit 8100d6d07576217fc3b1331b4b0693725a41c4e0 Author: Ivaylo Pavlov Date: Sat Jan 4 01:12:04 2025 +0000 [lexical-playground] Fix table hover actions button position (#7011) commit bd1ef2a2b6a58d217700d6b70fde093c46df3246 Author: Bob Ippolito Date: Fri Jan 3 14:25:31 2025 -0800 [lexical] Bug Fix: Fix registerNodeTransform regression introduced in #6894 (#7016) commit 85c08b6000530106b69516eae7e5bc3d5357b17e Author: Christian Grøngaard Date: Thu Jan 2 00:20:20 2025 +0100 [lexical-playground] Refactor: switch headings test file names (#7008) commit 7c21d4ff39a6ede7dcbe061af17ec11b0ed48b2c Author: Bob Ippolito Date: Wed Jan 1 12:48:12 2025 -0800 [Breaking Change][lexical] Feature: Add updateFromJSON and move more textFormat/textStyle to ElementNode (#6970) commit aaa90099506d95f2cef7c97184817ea91e9da2a3 Author: Bob Ippolito Date: Wed Jan 1 07:50:39 2025 -0800 [lexical] Bug Fix: Fix getNodes over-selection (#7006) commit 803391ddc751461b8bfe42c66a628b9a028a3674 Author: Sherry Date: Tue Dec 31 11:26:17 2024 +0800 [__test__] npm upgrade astro (#7001) commit 684352b7c6048349e79b2165032dfde425226ac6 Author: Christian Grøngaard Date: Mon Dec 30 05:12:45 2024 +0100 Documentation: Fix typo "nest nest"->"nest" in README.md (#7000) Co-authored-by: Bob Ippolito commit 27b75cc8be6a485cb40cffa2f36bbb48afdab606 Author: Sherry Date: Fri Dec 27 11:06:29 2024 +0800 [__tests__] npm upgrade next (#6996) commit 05ddbcc3a2d43d340a9b1619376467fda05f9bd9 Author: Simon Date: Thu Dec 26 03:37:50 2024 +0100 [lexical] Bug Fix: Flow is missing some variables and functions (#6977) commit e79c946c8b10fc33cef44b3247b6d87e2bdd12da Author: Sherry Date: Tue Dec 24 09:54:46 2024 +0800 v0.22.0 (#6993) Co-authored-by: Lexical GitHub Actions Bot <> commit c415f7a09bfa2b34f14c78fe5d284597d234448d Author: Sam Zhou Date: Mon Dec 23 10:31:36 2024 -0800 [lexical-react] Refactor: Replace `React$MixedElement` and `React$Node` with `React.MixedElement` and `React.Node` (#6984) commit c844a4dcc14b831624ea5579e524ad7f3123f9b3 Author: Sherry Date: Tue Dec 24 02:30:52 2024 +0800 [lexical] Fix flow error: change this to any (#6992) commit 619003383da4c72c3a351fe4c48601e2b926ed33 Author: Germán Jabloñski <43938777+GermanJablo@users.noreply.github.com> Date: Mon Dec 23 05:19:27 2024 -0300 Refactor: exportJSON (#6983) commit e0dafb8df7b95959b38ea69d10dda6cf554a8ee2 Author: Germán Jabloñski <43938777+GermanJablo@users.noreply.github.com> Date: Sat Dec 21 13:59:01 2024 -0300 feature: expose forEachSelectedTextNode (#6981) Co-authored-by: Bob Ippolito commit 23715f52b565159b3c6ae62f07e39992c98215b6 Author: Alex Date: Fri Dec 20 18:23:27 2024 +0300 [lexical][lexical-table] Bug fix: TablePlugin: - check is current selection in target table node (#6979) Co-authored-by: alazarev --- .eslintrc.js | 2 +- .github/workflows/size-limit.yml | 68 + .size-limit.js | 7 +- CHANGELOG.md | 67 + README.md | 2 +- examples/react-plain-text/package.json | 6 +- .../src/plugins/TreeViewPlugin.tsx | 2 + examples/react-rich-collab/package.json | 8 +- .../src/plugins/TreeViewPlugin.tsx | 2 + examples/react-rich/package.json | 6 +- .../react-rich/src/plugins/TreeViewPlugin.tsx | 2 + examples/react-table/package.json | 6 +- .../src/plugins/TreeViewPlugin.tsx | 2 + examples/vanilla-js-iframe/README.md | 8 + examples/vanilla-js-iframe/index.html | 33 + examples/vanilla-js-iframe/package-lock.json | 960 +++ examples/vanilla-js-iframe/package.json | 23 + examples/vanilla-js-iframe/src/main.ts | 52 + .../src/prepopulatedRichText.ts | 41 + examples/vanilla-js-iframe/src/styles.css | 27 + examples/vanilla-js-iframe/src/vite-env.d.ts | 1 + examples/vanilla-js-iframe/tsconfig.json | 23 + .../vanilla-js-iframe/vite.monorepo.config.ts | 80 + examples/vanilla-js-plugin/package.json | 12 +- .../src/emoji-plugin/EmojiNode.ts | 1 - examples/vanilla-js/package.json | 12 +- package-lock.json | 680 +-- package.json | 3 +- packages/lexical-clipboard/package.json | 12 +- packages/lexical-clipboard/src/clipboard.ts | 16 +- packages/lexical-code/package.json | 6 +- .../lexical-code/src/CodeHighlightNode.ts | 31 +- packages/lexical-code/src/CodeNode.ts | 22 +- .../__tests__/unit/LexicalCodeNode.test.ts | 29 + packages/lexical-devtools-core/package.json | 14 +- .../lexical-devtools-core/src/TreeView.tsx | 1 + packages/lexical-devtools/package.json | 6 +- packages/lexical-dragon/package.json | 4 +- packages/lexical-eslint-plugin/package.json | 2 +- packages/lexical-file/package.json | 4 +- packages/lexical-hashtag/package.json | 6 +- .../lexical-hashtag/src/LexicalHashtagNode.ts | 25 +- packages/lexical-headless/package.json | 4 +- packages/lexical-history/package.json | 6 +- .../__tests__/unit/LexicalHistory.test.tsx | 5 +- packages/lexical-html/package.json | 8 +- packages/lexical-link/package.json | 6 +- packages/lexical-link/src/index.ts | 77 +- packages/lexical-list/README.md | 8 +- .../lexical-list/flow/LexicalList.js.flow | 8 +- packages/lexical-list/package.json | 6 +- .../lexical-list/src/LexicalListItemNode.ts | 37 +- packages/lexical-list/src/LexicalListNode.ts | 32 +- .../__tests__/unit/LexicalListNode.test.ts | 6 +- .../src/__tests__/unit/formatList.test.ts | 101 + packages/lexical-list/src/formatList.ts | 226 +- packages/lexical-list/src/index.ts | 45 +- .../__tests__/unit/LexicalMarkNode.test.ts | 185 + packages/lexical-mark/package.json | 6 +- packages/lexical-mark/src/MarkNode.ts | 71 +- packages/lexical-mark/src/index.ts | 11 +- packages/lexical-markdown/package.json | 16 +- packages/lexical-offset/package.json | 4 +- packages/lexical-overflow/package.json | 4 +- packages/lexical-overflow/src/index.ts | 15 +- packages/lexical-plain-text/package.json | 10 +- .../__tests__/e2e/Collaboration.spec.mjs | 252 + .../html/TablesHTMLCopyAndPaste.spec.mjs | 54 + .../e2e/Headings/HeadingsEnterAtEnd.spec.mjs | 21 +- .../Headings/HeadingsEnterInMiddle.spec.mjs | 21 +- .../__tests__/e2e/Indentation.spec.mjs | 127 + .../__tests__/e2e/Links.spec.mjs | 62 + .../__tests__/e2e/List.spec.mjs | 53 +- .../__tests__/e2e/ListMaxIndentLevel.spec.mjs | 128 - .../__tests__/e2e/Selection.spec.mjs | 47 + .../6974-delete-character-backward.spec.mjs | 88 + packages/lexical-playground/package.json | 32 +- packages/lexical-playground/src/App.tsx | 2 + packages/lexical-playground/src/Editor.tsx | 6 +- packages/lexical-playground/src/Settings.tsx | 2 + .../src/context/FlashMessageContext.tsx | 2 + .../src/context/SettingsContext.tsx | 1 + .../src/context/SharedHistoryContext.tsx | 1 + .../src/context/ToolbarContext.tsx | 3 + .../lexical-playground/src/hooks/useModal.tsx | 2 + .../src/nodes/AutocompleteNode.tsx | 11 +- .../src/nodes/EmojiNode.tsx | 10 +- .../src/nodes/EquationComponent.tsx | 2 + .../src/nodes/EquationNode.tsx | 9 +- .../ExcalidrawNode/ExcalidrawComponent.tsx | 13 +- .../nodes/ExcalidrawNode/ExcalidrawImage.tsx | 2 + .../src/nodes/ExcalidrawNode/index.tsx | 6 +- .../src/nodes/FigmaNode.tsx | 9 +- .../src/nodes/ImageComponent.tsx | 13 +- .../src/nodes/ImageNode.tsx | 18 +- .../InlineImageNode/InlineImageComponent.tsx | 13 +- .../nodes/InlineImageNode/InlineImageNode.tsx | 19 +- .../src/nodes/KeywordNode.ts | 21 +- .../src/nodes/LayoutContainerNode.ts | 21 +- .../src/nodes/LayoutItemNode.ts | 12 +- .../src/nodes/MentionNode.ts | 28 +- .../src/nodes/PageBreakNode/index.tsx | 24 +- .../src/nodes/PollComponent.tsx | 13 +- .../lexical-playground/src/nodes/PollNode.tsx | 11 +- .../src/nodes/SpecialTextNode.tsx | 25 +- .../src/nodes/StickyComponent.tsx | 1 + .../src/nodes/StickyNode.tsx | 15 +- .../src/nodes/TweetNode.tsx | 7 +- .../src/nodes/YouTubeNode.tsx | 9 +- .../src/plugins/ActionsPlugin/index.tsx | 1 + .../src/plugins/AutoEmbedPlugin/index.tsx | 1 + .../src/plugins/AutoLinkPlugin/index.tsx | 2 + .../src/plugins/AutocompletePlugin/index.tsx | 1 + .../plugins/CodeActionMenuPlugin/index.tsx | 2 + .../src/plugins/CodeHighlightPlugin/index.ts | 2 + .../CollapsibleContainerNode.ts | 7 +- .../CollapsibleContentNode.ts | 10 +- .../CollapsiblePlugin/CollapsibleTitleNode.ts | 10 +- .../src/plugins/CommentPlugin/index.tsx | 1 + .../plugins/ComponentPickerPlugin/index.tsx | 2 + .../src/plugins/ContextMenuPlugin/index.tsx | 11 + .../src/plugins/DocsPlugin/index.tsx | 3 + .../plugins/DraggableBlockPlugin/index.tsx | 2 + .../src/plugins/EmojisPlugin/index.ts | 1 + .../src/plugins/EquationsPlugin/index.tsx | 2 + .../src/plugins/ExcalidrawPlugin/index.tsx | 1 + .../src/plugins/FigmaPlugin/index.tsx | 2 + .../FloatingLinkEditorPlugin/index.tsx | 2 + .../FloatingTextFormatToolbarPlugin/index.tsx | 2 + .../src/plugins/ImagesPlugin/index.tsx | 14 +- .../src/plugins/InlineImagePlugin/index.tsx | 12 +- .../src/plugins/KeywordsPlugin/index.ts | 1 + .../LayoutPlugin/InsertLayoutDialog.tsx | 3 + .../src/plugins/LinkPlugin/index.tsx | 2 + .../plugins/ListMaxIndentLevelPlugin/index.ts | 85 - .../plugins/MarkdownShortcutPlugin/index.tsx | 2 + .../src/plugins/MarkdownTransformers/index.ts | 7 +- .../src/plugins/MentionsPlugin/index.tsx | 2 + .../src/plugins/PageBreakPlugin/index.tsx | 3 + .../src/plugins/PasteLogPlugin/index.tsx | 2 + .../src/plugins/PollPlugin/index.tsx | 2 + .../src/plugins/SpecialTextPlugin/index.ts | 1 + .../src/plugins/StickyPlugin/index.ts | 2 + .../plugins/TableActionMenuPlugin/index.tsx | 1 + .../src/plugins/TableCellResizer/index.tsx | 1 + .../plugins/TableHoverActionsPlugin/index.tsx | 25 +- .../plugins/TableOfContentsPlugin/index.tsx | 3 +- .../src/plugins/TablePlugin.tsx | 2 + .../src/plugins/TestRecorderPlugin/index.tsx | 1 + .../src/plugins/ToolbarPlugin/index.tsx | 2 + .../src/plugins/TreeViewPlugin/index.tsx | 2 + .../src/plugins/TwitterPlugin/index.ts | 2 + .../src/plugins/TypingPerfPlugin/index.ts | 2 + .../src/plugins/YouTubePlugin/index.ts | 2 + .../src/themes/PlaygroundEditorTheme.css | 17 +- .../src/themes/PlaygroundEditorTheme.ts | 4 + packages/lexical-playground/src/ui/Button.tsx | 2 + .../lexical-playground/src/ui/ColorPicker.tsx | 2 + .../src/ui/ContentEditable.tsx | 2 + packages/lexical-playground/src/ui/Dialog.tsx | 2 + .../lexical-playground/src/ui/DropDown.tsx | 2 + .../src/ui/EquationEditor.tsx | 2 +- .../src/ui/ExcalidrawModal.tsx | 2 + .../lexical-playground/src/ui/FileInput.tsx | 2 + .../src/ui/FlashMessage.tsx | 2 + .../src/ui/ImageResizer.tsx | 1 + .../src/ui/KatexEquationAlterer.tsx | 2 + .../src/ui/KatexRenderer.tsx | 2 + packages/lexical-playground/src/ui/Modal.tsx | 2 + packages/lexical-playground/src/ui/Select.tsx | 2 + packages/lexical-playground/src/ui/Switch.tsx | 2 + .../lexical-playground/src/ui/TextInput.tsx | 2 + .../flow/LexicalAutoLinkPlugin.js.flow | 2 +- .../LexicalBlockWithAlignableContents.js.flow | 4 +- .../flow/LexicalCharacterLimitPlugin.js.flow | 2 +- .../flow/LexicalClearEditorPlugin.js.flow | 2 +- .../flow/LexicalCollaborationPlugin.js.flow | 2 +- .../flow/LexicalComposer.js.flow | 4 +- .../flow/LexicalContentEditable.js.flow | 4 +- .../flow/LexicalDraggableBlockPlugin.js.flow | 2 +- .../flow/LexicalErrorBoundary.js.flow | 4 +- .../flow/LexicalHashtagPlugin.js.flow | 2 +- .../flow/LexicalHistoryPlugin.js.flow | 2 +- .../flow/LexicalHorizontalRuleNode.js.flow | 4 +- .../LexicalMarkdownShortcutPlugin.js.flow | 2 +- .../flow/LexicalNestedComposer.js.flow | 4 +- .../flow/LexicalPlainTextPlugin.js.flow | 8 +- .../flow/LexicalRichTextPlugin.js.flow | 8 +- .../flow/LexicalTabIndentationPlugin.js.flow | 7 +- .../flow/LexicalTableOfContentsPlugin.js.flow | 4 +- .../flow/LexicalTreeView.js.flow | 2 +- packages/lexical-react/package.json | 40 +- .../src/LexicalAutoEmbedPlugin.tsx | 1 + .../src/LexicalAutoLinkPlugin.ts | 1 + .../src/LexicalBlockWithAlignableContents.tsx | 13 +- .../src/LexicalCharacterLimitPlugin.tsx | 2 + .../src/LexicalClearEditorPlugin.ts | 2 + .../src/LexicalCollaborationPlugin.tsx | 1 + .../lexical-react/src/LexicalComposer.tsx | 1 + .../src/LexicalContentEditable.tsx | 1 + .../src/LexicalContextMenuPlugin.tsx | 1 + .../src/LexicalDecoratorBlockNode.ts | 16 +- .../src/LexicalDraggableBlockPlugin.tsx | 2 + .../src/LexicalErrorBoundary.tsx | 2 + .../lexical-react/src/LexicalHashtagPlugin.ts | 1 + .../src/LexicalHorizontalRuleNode.tsx | 22 +- .../src/LexicalNestedComposer.tsx | 1 + .../src/LexicalNodeMenuPlugin.tsx | 1 + .../src/LexicalPlainTextPlugin.tsx | 2 + .../src/LexicalRichTextPlugin.tsx | 2 + .../src/LexicalTabIndentationPlugin.tsx | 74 +- .../src/LexicalTableOfContentsPlugin.tsx | 2 + .../lexical-react/src/LexicalTablePlugin.ts | 2 + .../lexical-react/src/LexicalTreeView.tsx | 1 + .../src/LexicalTypeaheadMenuPlugin.tsx | 1 + .../shared/LexicalContentEditableElement.tsx | 1 + .../lexical-react/src/shared/LexicalMenu.ts | 2 + .../src/shared/useDecorators.tsx | 1 + .../src/shared/useYjsCollaboration.tsx | 15 +- packages/lexical-rich-text/package.json | 10 +- .../__tests__/unit/LexicalHeadingNode.test.ts | 19 +- packages/lexical-rich-text/src/index.ts | 48 +- packages/lexical-selection/package.json | 4 +- .../src/__tests__/utils/index.ts | 10 +- packages/lexical-selection/src/index.ts | 2 + .../lexical-selection/src/lexical-node.ts | 38 +- .../lexical-selection/src/range-selection.ts | 59 +- packages/lexical-table/package.json | 8 +- .../lexical-table/src/LexicalTableCellNode.ts | 26 +- .../lexical-table/src/LexicalTableNode.ts | 67 +- .../lexical-table/src/LexicalTableObserver.ts | 3 - .../lexical-table/src/LexicalTableRowNode.ts | 21 +- .../src/LexicalTableSelectionHelpers.ts | 28 + .../lexical-table/src/LexicalTableUtils.ts | 2 +- .../__tests__/unit/LexicalTableNode.test.tsx | 67 + .../unit/LexicalTableSelection.test.tsx | 2 + packages/lexical-text/package.json | 4 +- packages/lexical-utils/package.json | 10 +- .../__tests__/unit/LexicalNodeHelpers.test.ts | 338 +- ...xicalUtilsInsertNodeToNearestRoot.test.tsx | 14 +- packages/lexical-utils/src/index.ts | 107 +- .../docs/concepts/dom-events.md | 4 +- .../docs/concepts/listeners.md | 6 +- .../docs/concepts/selection.md | 2 +- .../docs/concepts/serialization.md | 134 +- .../docs/getting-started/creating-plugin.md | 3 +- .../docs/react/create_plugin.md | 2 +- packages/lexical-website/package.json | 2 +- packages/lexical-yjs/package.json | 8 +- packages/lexical-yjs/src/CollabElementNode.ts | 28 +- packages/lexical-yjs/src/SyncCursors.ts | 152 +- packages/lexical-yjs/src/SyncEditorStates.ts | 4 +- packages/lexical-yjs/src/index.ts | 6 +- packages/lexical/README.md | 4 +- packages/lexical/flow/Lexical.js.flow | 20 +- packages/lexical/package.json | 2 +- packages/lexical/src/LexicalConstants.ts | 2 + packages/lexical/src/LexicalEditor.ts | 82 +- packages/lexical/src/LexicalEvents.ts | 296 +- packages/lexical/src/LexicalMutations.ts | 28 +- packages/lexical/src/LexicalNode.ts | 50 +- packages/lexical/src/LexicalNormalization.ts | 2 + packages/lexical/src/LexicalReconciler.ts | 11 +- packages/lexical/src/LexicalSelection.ts | 178 +- packages/lexical/src/LexicalUpdates.ts | 34 +- packages/lexical/src/LexicalUtils.ts | 87 +- .../__tests__/unit/HTMLCopyAndPaste.test.ts | 30 + .../src/__tests__/unit/LexicalEditor.test.tsx | 31 +- .../__tests__/unit/LexicalEditorState.test.ts | 4 + .../__tests__/unit/LexicalListPlugin.test.tsx | 88 + .../src/__tests__/unit/LexicalNode.test.ts | 36 +- .../__tests__/unit/LexicalSelection.test.ts | 8 +- .../unit/LexicalSerialization.test.ts | 11 +- .../src/__tests__/unit/LexicalUtils.test.ts | 24 +- .../lexical/src/__tests__/utils/index.tsx | 97 +- packages/lexical/src/index.ts | 5 + .../lexical/src/nodes/LexicalDecoratorNode.ts | 4 - .../lexical/src/nodes/LexicalElementNode.ts | 81 +- .../lexical/src/nodes/LexicalLineBreakNode.ts | 21 +- .../lexical/src/nodes/LexicalParagraphNode.ts | 70 +- packages/lexical/src/nodes/LexicalRootNode.ts | 17 +- packages/lexical/src/nodes/LexicalTabNode.ts | 37 +- packages/lexical/src/nodes/LexicalTextNode.ts | 54 +- .../__tests__/unit/LexicalTabNode.test.tsx | 26 + packages/shared/package.json | 4 +- .../lexical-esm-astro-react/package-lock.json | 5314 +++++++---------- .../lexical-esm-astro-react/package.json | 8 +- .../src/components/plugins/TreeViewPlugin.tsx | 2 + .../app/plugins/TreeViewPlugin.tsx | 2 + .../lexical-esm-nextjs/package-lock.json | 431 +- .../fixtures/lexical-esm-nextjs/package.json | 8 +- .../package.json | 12 +- scripts/build.js | 31 +- scripts/error-codes/codes.json | 10 +- 294 files changed, 7683 insertions(+), 5822 deletions(-) create mode 100644 examples/vanilla-js-iframe/README.md create mode 100644 examples/vanilla-js-iframe/index.html create mode 100644 examples/vanilla-js-iframe/package-lock.json create mode 100644 examples/vanilla-js-iframe/package.json create mode 100644 examples/vanilla-js-iframe/src/main.ts create mode 100644 examples/vanilla-js-iframe/src/prepopulatedRichText.ts create mode 100644 examples/vanilla-js-iframe/src/styles.css create mode 100644 examples/vanilla-js-iframe/src/vite-env.d.ts create mode 100644 examples/vanilla-js-iframe/tsconfig.json create mode 100644 examples/vanilla-js-iframe/vite.monorepo.config.ts create mode 100644 packages/lexical-list/src/__tests__/unit/formatList.test.ts create mode 100644 packages/lexical-mark/__tests__/unit/LexicalMarkNode.test.ts delete mode 100644 packages/lexical-playground/__tests__/e2e/ListMaxIndentLevel.spec.mjs create mode 100644 packages/lexical-playground/__tests__/regression/6974-delete-character-backward.spec.mjs delete mode 100644 packages/lexical-playground/src/plugins/ListMaxIndentLevelPlugin/index.ts diff --git a/.eslintrc.js b/.eslintrc.js index 314fcffc887..c0cd4c5817e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -82,7 +82,7 @@ module.exports = { // @lexical/yjs 'createBinding', ], - isLexicalProvider: ['updateEditor'], + isLexicalProvider: ['updateEditor', 'updateEditorSync'], isSafeDollarFunction: '$createRootNode', }), ], diff --git a/.github/workflows/size-limit.yml b/.github/workflows/size-limit.yml index 35467b538d8..27194d79116 100644 --- a/.github/workflows/size-limit.yml +++ b/.github/workflows/size-limit.yml @@ -9,7 +9,75 @@ jobs: env: CI_JOB_NUMBER: 1 steps: + # See also: + # https://github.com/facebook/lexical/issues/6852 + # https://github.com/NixOS/nixpkgs/blob/c8db8bd9656ee3d373ce9445063c25c47f442118/.github/workflows/check-by-name.yml#L31-L92 + # https://github.com/getsentry/sentry/issues/22432 + # https://github.com/getsentry/sentry/pull/22344 + # This step has to be in this file, + # because it's needed to determine which revision of the repository to fetch, + # and we can only use other files from the repository once it's fetched. + - id: merge-commit + name: Resolving the merge commit + env: + GH_TOKEN: ${{ github.token }} + run: | + # This checks for mergeability of a pull request as recommended in + # https://docs.github.com/en/rest/guides/using-the-rest-api-to-interact-with-your-git-database?apiVersion=2022-11-28#checking-mergeability-of-pull-requests + + # Retry the API query this many times + retryCount=3 + # Start with 5 seconds, but double every retry + retryInterval=5 + while true; do + echo "Checking whether the pull request can be merged" + prInfo=$(gh api \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/"$GITHUB_REPOSITORY"/pulls/${{ github.event.pull_request.number }}) + mergeable=$(jq -r .mergeable <<< "$prInfo") + mergedSha=$(jq -r .merge_commit_sha <<< "$prInfo") + + if [[ "$mergeable" == "null" ]]; then + if (( retryCount == 0 )); then + echo "Not retrying anymore, probably GitHub is having internal issues" + exit 1 + else + (( retryCount -= 1 )) || true + + # null indicates that GitHub is still computing whether it's mergeable + # Wait a couple seconds before trying again + echo "GitHub is still computing whether this PR can be merged, waiting $retryInterval seconds before trying again ($retryCount retries left)" + sleep "$retryInterval" + + (( retryInterval *= 2 )) || true + fi + else + break + fi + done + + if [[ "$mergeable" == "true" ]]; then + echo "The PR can be merged, checking the merge commit $mergedSha" + else + echo "The PR cannot be merged, it has a merge conflict, cancelling the workflow.." + gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/"$GITHUB_REPOSITORY"/actions/runs/"$GITHUB_RUN_ID"/cancel + sleep 60 + # If it's still not canceled after a minute, something probably went wrong, just exit + exit 1 + fi + echo "mergedSha=$mergedSha" >> "$GITHUB_OUTPUT" - uses: actions/checkout@v4 + with: + # pull_request_target checks out the base branch by default + ref: ${{ steps.merge-commit.outputs.mergedSha }} + # Fetches the merge commit and its parents + fetch-depth: 2 - uses: andresz1/size-limit-action@v1 with: github_token: ${{ secrets.GITHUB_TOKEN }} + build_script: build-prod diff --git a/.size-limit.js b/.size-limit.js index 2061cdfaf00..7d6c634c20c 100644 --- a/.size-limit.js +++ b/.size-limit.js @@ -24,12 +24,9 @@ const path = require('node:path'); * Looks like: * * { - * lexical: 'packages/lexical/dist/index.js', - * '@lexical/rich-text': 'packages/lexical-rich-text/dist/index.js', + * lexical: 'packages/lexical/dist/Lexical.js', + * '@lexical/rich-text': 'packages/lexical-rich-text/dist/LexicalRichText.js', * } - * - * Currently this alias map points at the cjs version of the build product, - * as that is what was measured previously in #3600. */ const {packagesManager} = require('./scripts/shared/packagesManager'); const getAliasType = (type) => diff --git a/CHANGELOG.md b/CHANGELOG.md index 3eee8677fe9..25cd6d664c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,70 @@ +## v0.23.1 (2025-01-09) + +- lexical Fix TabNode deserialization regression (#7031) Bob Ippolito +- lexical-react Feature Merge TabIndentionPlugin and ListMaxIndentLevelPlugin plugins (#7018) Maksim Horbachevsky +- lexical-mark Bug Fix reverse ternary in MarkNode.addID (#7020) James Fitzsimmons +- v0.23.0 (#7017) Bob Ippolito +- v0.23.0 Lexical GitHub Actions Bot + +## v0.23.0 (2025-01-04) + +- lexical-playground Fix table hover actions button position (#7011) Ivaylo Pavlov +- lexical Bug Fix Fix registerNodeTransform regression introduced in #6894 (#7016) Bob Ippolito +- lexical-playground Refactor switch headings test file names (#7008) Christian Grngaard +- Breaking Changelexical Feature Add updateFromJSON and move more textFormattextStyle to ElementNode (#6970) Bob Ippolito +- lexical Bug Fix Fix getNodes over-selection (#7006) Bob Ippolito +- test npm upgrade astro (#7001) Sherry +- Documentation Fix typo nest nest-nest in README.md (#7000) Christian Grngaard +- tests npm upgrade next (#6996) Sherry +- lexical Bug Fix Flow is missing some variables and functions (#6977) Simon +- v0.22.0 (#6993) Sherry +- v0.22.0 Lexical GitHub Actions Bot + +## v0.22.0 (2024-12-23) + +- lexical Fix flow error change this to any (#6992) Sherry +- Refactor exportJSON (#6983) Germn Jabloski +- feature expose forEachSelectedTextNode (#6981) Germn Jabloski +- lexicallexical-table Bug fix TablePlugin - check is current selection in target table node (#6979) Alex +- Documentationlexical-website Documentation for useLexical node selection hook (#6976) Ajaezo Kingsley +- lexical-table Feature Support google docs colgroup import (via deprecated col width attribute) (#6971) Bob Ippolito +- lexical-markdown Bug Fix preserve the order of markdown tags for markdown combinations, and close the tags when the outmost tag is closed (#5758) yhw5 +- lexical-utils Bug Fix Refactor markSelection for getDOMSlot and not using updateDOM (#6961) Bob Ippolito +- lexicallexical-table Bug Fix Allow TableSelection to be preserved during contextmenu events (#6964) Bob Ippolito +- lexical-website Add Discord to the community section of the footer (#6967) Bob Ippolito +- lexicallexical-rich-textlexical-playground Feature Support capitalization format (#6897) Bedru Umer +- lexical-playground Bug Fix Allow scrolling if the table cell content overflows (#6966) Parasaran +- lexical-tablelexical-playground Fix Insertion of multiple rows (#6963) Vinay Kushwaha +- Breaking Changelexical Feature New update tag skip-dom-selection, onUpdate now always called (#6894) Bob Ippolito +- Test234 (#6958) Tranquiliz00 +- Revert Test comment for pr testing (#6953) (#6957) bailey-meta +- Revert lexical-onboarding testing sev mitigation (#6952) (#6956) Niels Y. +- Create a test PR (#6955) Tranquiliz00 +- Test comment for pr testing (#6953) bailey-meta +- lexical-onboarding testing sev mitigation (#6952) Niels Y. +- lexical-list Revert PR 6912 (#6944) Sherry +- scripts-integration-fixtures Address GitHub detected a vulnerability in the sveltejskit dependency (#6943) Luis Silva +- lexical-table Fix Delete table row in merge cells (#6922) Vinay Kushwaha +- lexical-list Bug Fix Ensure new paragraph node retains selection styling when exiting list (#6917) Aleksandr Lapukin +- lexical-reactBug Fix the location of draggable-block-menu cannot be calculated #6818 (#6915) lin-mt +- lexical-playground Refactor editor styles should in PlaygroundEditorTheme.css (#6934) Syed Umar Anis +- lexical-playground Fix tabs do not show strikethroughunderline (#6811) Oluwasanya Olaoluwa +- Breaking Changelexical-list Fix Preserve original format after indenting list item (#6912) C. +- Bug Fix add mergegroup to the tests workflow (#6932) Bob Ippolito +- Update core-tests workflow triggers (#6928) Gerard Rovira +- Doc nits (#6927) Gerard Rovira +- lexical-playground Chore Update Prettier to v3 (#6920) daichan132 +- lexical-playground Fix empty layout item causes 100 CPU usage (#6906) Basile Savouret +- lexicallexicalselection Feature Unify selectAll Implementations (#6902) Hadi Elghoul +- lexical-tablelexical-utilslexical-react Bug Fix Enforce table integrity with transforms and move non-React plugin code to lexicaltable (#6914) Bob Ippolito +- lexical-website Fix docsreact next button links to itself (#6911) Oluwasanya Olaoluwa +- Warn about display flex container for the editor (#6901) Maksim Horbachevsky +- lexical-websitelexical-react Documentation Update documentation for LexicalTreeView plugin (#6898) Ajaezo Kingsley +- lexical-link Bug Fix Preserve the startend of the selection for non-text points when creating a LinkNode (#6883) Bob Ippolito +- v0.21.0 (#6896) Sherry +- Documentation Update Add release protocol to maintainers-guide.md (#6895) Sherry +- v0.21.0 Lexical GitHub Actions Bot + ## v0.21.0 (2024-12-01) - Fix selected table colors (#6892) Gerard Rovira diff --git a/README.md b/README.md index 26fd8abc127..0823f845f73 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ Node Transforms and Command Listeners are called with an implicit `editor.update It is permitted to do nested updates, or nested reads, but an update should not be nested in a read or vice versa. For example, `editor.update(() => editor.update(() => {...}))` is allowed. It is permitted -to nest nest an `editor.read` at the end of an `editor.update`, but this will immediately flush the update +to nest an `editor.read` at the end of an `editor.update`, but this will immediately flush the update and any additional update in that callback will throw an error. All Lexical Nodes are dependent on the associated Editor State. With few exceptions, you should only call methods diff --git a/examples/react-plain-text/package.json b/examples/react-plain-text/package.json index a1c8041a371..01566e639f8 100644 --- a/examples/react-plain-text/package.json +++ b/examples/react-plain-text/package.json @@ -1,7 +1,7 @@ { "name": "@lexical/react-plain-text-example", "private": true, - "version": "0.21.0", + "version": "0.23.1", "type": "module", "scripts": { "dev": "vite", @@ -9,8 +9,8 @@ "preview": "vite preview" }, "dependencies": { - "@lexical/react": "0.21.0", - "lexical": "0.21.0", + "@lexical/react": "0.23.1", + "lexical": "0.23.1", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/examples/react-plain-text/src/plugins/TreeViewPlugin.tsx b/examples/react-plain-text/src/plugins/TreeViewPlugin.tsx index 3f8980b7e86..2eb6f2bb365 100644 --- a/examples/react-plain-text/src/plugins/TreeViewPlugin.tsx +++ b/examples/react-plain-text/src/plugins/TreeViewPlugin.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {TreeView} from '@lexical/react/LexicalTreeView'; diff --git a/examples/react-rich-collab/package.json b/examples/react-rich-collab/package.json index d8726826edf..629c193a8f9 100644 --- a/examples/react-rich-collab/package.json +++ b/examples/react-rich-collab/package.json @@ -1,7 +1,7 @@ { "name": "@lexical/react-rich-collab-example", "private": true, - "version": "0.21.0", + "version": "0.23.1", "type": "module", "scripts": { "dev": "vite", @@ -12,9 +12,9 @@ "server:webrtc": "cross-env HOST=localhost PORT=1235 npx y-webrtc" }, "dependencies": { - "@lexical/react": "0.21.0", - "@lexical/yjs": "0.21.0", - "lexical": "0.21.0", + "@lexical/react": "0.23.1", + "@lexical/yjs": "0.23.1", + "lexical": "0.23.1", "react": "^18.2.0", "react-dom": "^18.2.0", "y-webrtc": "^10.3.0", diff --git a/examples/react-rich-collab/src/plugins/TreeViewPlugin.tsx b/examples/react-rich-collab/src/plugins/TreeViewPlugin.tsx index 3f8980b7e86..2eb6f2bb365 100644 --- a/examples/react-rich-collab/src/plugins/TreeViewPlugin.tsx +++ b/examples/react-rich-collab/src/plugins/TreeViewPlugin.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {TreeView} from '@lexical/react/LexicalTreeView'; diff --git a/examples/react-rich/package.json b/examples/react-rich/package.json index 0529b88d472..a072ab11727 100644 --- a/examples/react-rich/package.json +++ b/examples/react-rich/package.json @@ -1,7 +1,7 @@ { "name": "@lexical/react-rich-example", "private": true, - "version": "0.21.0", + "version": "0.23.1", "type": "module", "scripts": { "dev": "vite", @@ -9,8 +9,8 @@ "preview": "vite preview" }, "dependencies": { - "@lexical/react": "0.21.0", - "lexical": "0.21.0", + "@lexical/react": "0.23.1", + "lexical": "0.23.1", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/examples/react-rich/src/plugins/TreeViewPlugin.tsx b/examples/react-rich/src/plugins/TreeViewPlugin.tsx index 3f8980b7e86..2eb6f2bb365 100644 --- a/examples/react-rich/src/plugins/TreeViewPlugin.tsx +++ b/examples/react-rich/src/plugins/TreeViewPlugin.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {TreeView} from '@lexical/react/LexicalTreeView'; diff --git a/examples/react-table/package.json b/examples/react-table/package.json index 94aa0b6a434..c4eefa59b10 100644 --- a/examples/react-table/package.json +++ b/examples/react-table/package.json @@ -1,7 +1,7 @@ { "name": "@lexical/react-table-example", "private": true, - "version": "0.21.0", + "version": "0.23.1", "type": "module", "scripts": { "dev": "vite", @@ -9,8 +9,8 @@ "preview": "vite preview" }, "dependencies": { - "@lexical/react": "0.21.0", - "lexical": "0.21.0", + "@lexical/react": "0.23.1", + "lexical": "0.23.1", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/examples/react-table/src/plugins/TreeViewPlugin.tsx b/examples/react-table/src/plugins/TreeViewPlugin.tsx index 3f8980b7e86..2eb6f2bb365 100644 --- a/examples/react-table/src/plugins/TreeViewPlugin.tsx +++ b/examples/react-table/src/plugins/TreeViewPlugin.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {TreeView} from '@lexical/react/LexicalTreeView'; diff --git a/examples/vanilla-js-iframe/README.md b/examples/vanilla-js-iframe/README.md new file mode 100644 index 00000000000..4069a5b7d5a --- /dev/null +++ b/examples/vanilla-js-iframe/README.md @@ -0,0 +1,8 @@ +# Vanilla JS example in an iframe + +Here we have simplest Lexical setup in rich text configuration (`@lexical/rich-text`) with history (`@lexical/history`) and accessibility (`@lexical/dragon`) features enabled using an iframe +for the contentEditable surface. + +**Run it locally:** `npm i && npm run dev` + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/facebook/lexical/tree/main/examples/vanilla-js-iframe?file=src/main.ts) diff --git a/examples/vanilla-js-iframe/index.html b/examples/vanilla-js-iframe/index.html new file mode 100644 index 00000000000..a730616c401 --- /dev/null +++ b/examples/vanilla-js-iframe/index.html @@ -0,0 +1,33 @@ + + + + + + Lexical Basic - Vanilla JS iframe + + + + + + + diff --git a/examples/vanilla-js-iframe/package-lock.json b/examples/vanilla-js-iframe/package-lock.json new file mode 100644 index 00000000000..ec39bb13579 --- /dev/null +++ b/examples/vanilla-js-iframe/package-lock.json @@ -0,0 +1,960 @@ +{ + "name": "@lexical/vanilla-js-iframe", + "version": "0.23.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@lexical/vanilla-js-iframe", + "version": "0.23.0", + "dependencies": { + "@lexical/dragon": "0.23.0", + "@lexical/history": "0.23.0", + "@lexical/rich-text": "0.23.0", + "@lexical/utils": "0.23.0", + "lexical": "0.23.0" + }, + "devDependencies": { + "typescript": "^5.2.2", + "vite": "^5.2.11" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@lexical/clipboard": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.23.0.tgz", + "integrity": "sha512-+MEdOajIXFp/5Q3dS3tj3PD3E6SCzf91E2AkNfN3oeeogDf04WG4e5Gx8NuXSGzpEZ8Rog28QDP6xQ8fCzwaTg==", + "dependencies": { + "@lexical/html": "0.23.0", + "@lexical/list": "0.23.0", + "@lexical/selection": "0.23.0", + "@lexical/utils": "0.23.0", + "lexical": "0.23.0" + } + }, + "node_modules/@lexical/dragon": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@lexical/dragon/-/dragon-0.23.0.tgz", + "integrity": "sha512-EIwnH8eZIkYTyb4rY9cPKrzPv7a4t9cip6JBeTsysGB3k2K3nTaWCW4k89kUZ4Jy4olB+d7FDLRjEUMwV7MoDg==", + "dependencies": { + "lexical": "0.23.0" + } + }, + "node_modules/@lexical/history": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@lexical/history/-/history-0.23.0.tgz", + "integrity": "sha512-s76kbrGYw/duLjN3OpPiYtpzl1F9ddbTbFL7KxWG6FHhAXXPF5caY9Ajg+OB6327r2jSxUbZSautd5zbwFxbWA==", + "dependencies": { + "@lexical/utils": "0.23.0", + "lexical": "0.23.0" + } + }, + "node_modules/@lexical/html": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.23.0.tgz", + "integrity": "sha512-kHCmjATl88CeaeJoWbycHT1XQjwYgscjZSmgSmOahRvCsBee4lJ/h+cuMLVDj9gj21IAnzYd8Gx+EHka/yECgA==", + "dependencies": { + "@lexical/selection": "0.23.0", + "@lexical/utils": "0.23.0", + "lexical": "0.23.0" + } + }, + "node_modules/@lexical/list": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.23.0.tgz", + "integrity": "sha512-YcvnyqER400XWYtjruIRs1ggMKqQbBupejMx2SHrXRzL/7dByHtmfGL6Bzn/1Y3BRWBYSFHy2LFs+OCFuChEIw==", + "dependencies": { + "@lexical/utils": "0.23.0", + "lexical": "0.23.0" + } + }, + "node_modules/@lexical/rich-text": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.23.0.tgz", + "integrity": "sha512-X5f+as0dItxo5GGwwExHo7cGgG1erf/02mqhFNbMvOnl+VJVOvy3c+wp2W3JEWRDTaLdqxaw/m4LrfN6m79cEg==", + "dependencies": { + "@lexical/clipboard": "0.23.0", + "@lexical/selection": "0.23.0", + "@lexical/utils": "0.23.0", + "lexical": "0.23.0" + } + }, + "node_modules/@lexical/selection": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.23.0.tgz", + "integrity": "sha512-ypyLRkzRiVA8JIlIZu58FepkBxl8ilysigjJefyMEuFUS8/F3d9nujznWi6BhplWmBCd/lNzFjvLvmsvYAK1XQ==", + "dependencies": { + "lexical": "0.23.0" + } + }, + "node_modules/@lexical/table": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.23.0.tgz", + "integrity": "sha512-R8WHuyrefQyrwMkIGuj/2CnQDf5f3yljHABy77URvoBjmVONEM/vqQ9ZLCtDP4fIaxhdf2Fq3Agt6e3tMNs/vQ==", + "dependencies": { + "@lexical/clipboard": "0.23.0", + "@lexical/utils": "0.23.0", + "lexical": "0.23.0" + } + }, + "node_modules/@lexical/utils": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.23.0.tgz", + "integrity": "sha512-vhcwR7ymkvXGrnoANxiBR55UlNwR4KcRNTzbbKgtQRdo+ATXbX6/KROVPJ6nkvYah+f6fcqw9Crj7RtzSOYhiQ==", + "dependencies": { + "@lexical/list": "0.23.0", + "@lexical/selection": "0.23.0", + "@lexical/table": "0.23.0", + "lexical": "0.23.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz", + "integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz", + "integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz", + "integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz", + "integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz", + "integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz", + "integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz", + "integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz", + "integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz", + "integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz", + "integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz", + "integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz", + "integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz", + "integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz", + "integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz", + "integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz", + "integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz", + "integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz", + "integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz", + "integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/lexical": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.23.0.tgz", + "integrity": "sha512-xkRJqPrdcAkUKP9NiJcmOayKpvou9C8H9y2O8fIWM9tW0KAJub1gkuw9q9VexwvqgCZbf2ep2ufFwC1rY7caSw==" + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz", + "integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.30.1", + "@rollup/rollup-android-arm64": "4.30.1", + "@rollup/rollup-darwin-arm64": "4.30.1", + "@rollup/rollup-darwin-x64": "4.30.1", + "@rollup/rollup-freebsd-arm64": "4.30.1", + "@rollup/rollup-freebsd-x64": "4.30.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.30.1", + "@rollup/rollup-linux-arm-musleabihf": "4.30.1", + "@rollup/rollup-linux-arm64-gnu": "4.30.1", + "@rollup/rollup-linux-arm64-musl": "4.30.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.30.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.30.1", + "@rollup/rollup-linux-riscv64-gnu": "4.30.1", + "@rollup/rollup-linux-s390x-gnu": "4.30.1", + "@rollup/rollup-linux-x64-gnu": "4.30.1", + "@rollup/rollup-linux-x64-musl": "4.30.1", + "@rollup/rollup-win32-arm64-msvc": "4.30.1", + "@rollup/rollup-win32-ia32-msvc": "4.30.1", + "@rollup/rollup-win32-x64-msvc": "4.30.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/typescript": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "5.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", + "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", + "dev": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + } + } +} diff --git a/examples/vanilla-js-iframe/package.json b/examples/vanilla-js-iframe/package.json new file mode 100644 index 00000000000..9c2a8775708 --- /dev/null +++ b/examples/vanilla-js-iframe/package.json @@ -0,0 +1,23 @@ +{ + "name": "@lexical/vanilla-js-iframe", + "private": true, + "version": "0.23.0", + "type": "module", + "scripts": { + "dev": "vite", + "monorepo:dev": "vite -c vite.monorepo.config.ts", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@lexical/dragon": "0.23.0", + "@lexical/history": "0.23.0", + "@lexical/rich-text": "0.23.0", + "@lexical/utils": "0.23.0", + "lexical": "0.23.0" + }, + "devDependencies": { + "typescript": "^5.2.2", + "vite": "^5.2.11" + } +} diff --git a/examples/vanilla-js-iframe/src/main.ts b/examples/vanilla-js-iframe/src/main.ts new file mode 100644 index 00000000000..089ffc6178c --- /dev/null +++ b/examples/vanilla-js-iframe/src/main.ts @@ -0,0 +1,52 @@ +/** + * 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 './styles.css'; + +import {registerDragonSupport} from '@lexical/dragon'; +import {createEmptyHistoryState, registerHistory} from '@lexical/history'; +import {HeadingNode, QuoteNode, registerRichText} from '@lexical/rich-text'; +import {mergeRegister} from '@lexical/utils'; +import {createEditor} from 'lexical'; + +import prepopulatedRichText from './prepopulatedRichText'; + +const template = document.querySelector('#app-template')!; +const iframe = document.querySelector('#app-iframe')!; +const iframeDoc = iframe.contentDocument!; +iframeDoc.body.replaceChildren(iframeDoc.importNode(template.content, true)); +const editorRef = iframeDoc.querySelector('#lexical-editor')!; +const stateRef = + iframeDoc.querySelector('#lexical-state')!; + +const initialConfig = { + namespace: 'Vanilla JS Demo', + // Register nodes specific for @lexical/rich-text + nodes: [HeadingNode, QuoteNode], + onError: (error: Error) => { + throw error; + }, + theme: { + // Adding styling to Quote node, see styles.css + quote: 'PlaygroundEditorTheme__quote', + }, +}; +const editor = createEditor(initialConfig); +editor.setRootElement(editorRef); + +// Registring Plugins +mergeRegister( + registerRichText(editor), + registerDragonSupport(editor), + registerHistory(editor, createEmptyHistoryState(), 300), +); + +editor.update(prepopulatedRichText, {tag: 'history-merge'}); + +editor.registerUpdateListener(({editorState}) => { + stateRef!.value = JSON.stringify(editorState.toJSON(), undefined, 2); +}); diff --git a/examples/vanilla-js-iframe/src/prepopulatedRichText.ts b/examples/vanilla-js-iframe/src/prepopulatedRichText.ts new file mode 100644 index 00000000000..b0ceaf4a1f5 --- /dev/null +++ b/examples/vanilla-js-iframe/src/prepopulatedRichText.ts @@ -0,0 +1,41 @@ +/** + * 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 {$createHeadingNode, $createQuoteNode} from '@lexical/rich-text'; +import {$createParagraphNode, $createTextNode, $getRoot} from 'lexical'; + +export default function $prepopulatedRichText() { + const root = $getRoot(); + if (root.getFirstChild() !== null) { + return; + } + + const heading = $createHeadingNode('h1'); + heading.append( + $createTextNode('Welcome to the IFrame Vanilla JS Lexical Demo!'), + ); + root.append(heading); + const quote = $createQuoteNode(); + quote.append( + $createTextNode( + `In case you were wondering what the text area at the bottom is – it's the debug view, showing the current state of the editor. `, + ), + ); + root.append(quote); + const paragraph = $createParagraphNode(); + paragraph.append( + $createTextNode('This is a demo environment built with '), + $createTextNode('lexical').toggleFormat('code'), + $createTextNode('.'), + $createTextNode(' Try typing in '), + $createTextNode('some text').toggleFormat('bold'), + $createTextNode(' with '), + $createTextNode('different').toggleFormat('italic'), + $createTextNode(' formats.'), + ); + root.append(paragraph); +} diff --git a/examples/vanilla-js-iframe/src/styles.css b/examples/vanilla-js-iframe/src/styles.css new file mode 100644 index 00000000000..73636e09051 --- /dev/null +++ b/examples/vanilla-js-iframe/src/styles.css @@ -0,0 +1,27 @@ +/** + * 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. + * + */ + +.editor-wrapper { + border: 2px solid gray; +} +#lexical-state { + width: 100%; + height: 300px; +} + +.PlaygroundEditorTheme__quote { + margin: 0; + margin-left: 20px; + margin-bottom: 10px; + font-size: 15px; + color: rgb(101, 103, 107); + border-left-color: rgb(206, 208, 212); + border-left-width: 4px; + border-left-style: solid; + padding-left: 16px; +} diff --git a/examples/vanilla-js-iframe/src/vite-env.d.ts b/examples/vanilla-js-iframe/src/vite-env.d.ts new file mode 100644 index 00000000000..11f02fe2a00 --- /dev/null +++ b/examples/vanilla-js-iframe/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/vanilla-js-iframe/tsconfig.json b/examples/vanilla-js-iframe/tsconfig.json new file mode 100644 index 00000000000..75abdef2659 --- /dev/null +++ b/examples/vanilla-js-iframe/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/examples/vanilla-js-iframe/vite.monorepo.config.ts b/examples/vanilla-js-iframe/vite.monorepo.config.ts new file mode 100644 index 00000000000..c6dbd2b59ac --- /dev/null +++ b/examples/vanilla-js-iframe/vite.monorepo.config.ts @@ -0,0 +1,80 @@ +/** + * 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 babel from '@rollup/plugin-babel'; +import {createRequire} from 'node:module'; +import {defineConfig} from 'vite'; +import {replaceCodePlugin} from 'vite-plugin-replace'; + +import moduleResolution from '../../packages/shared/viteModuleResolution'; + +const require = createRequire(import.meta.url); + +// https://vitejs.dev/config/ +export default defineConfig(({command}) => { + return { + build: { + outDir: 'build', + rollupOptions: { + input: { + main: new URL('./index.html', import.meta.url).pathname, + split: new URL('./split/index.html', import.meta.url).pathname, + }, + onwarn(warning, warn) { + if ( + warning.code === 'EVAL' && + warning.id && + /[\\/]node_modules[\\/]@excalidraw\/excalidraw[\\/]/.test( + warning.id, + ) + ) { + return; + } + warn(warning); + }, + }, + }, + define: { + 'process.env.IS_PREACT': process.env.IS_PREACT, + }, + plugins: [ + replaceCodePlugin({ + replacements: [ + { + from: /__DEV__/g, + to: 'true', + }, + { + from: 'process.env.LEXICAL_VERSION', + to: JSON.stringify(`${process.env.npm_package_version}+git`), + }, + ], + }), + babel({ + babelHelpers: 'bundled', + babelrc: false, + configFile: false, + exclude: '/**/node_modules/**', + extensions: ['jsx', 'js', 'ts', 'tsx', 'mjs'], + plugins: [ + '@babel/plugin-transform-flow-strip-types', + [ + require('../../scripts/error-codes/transform-error-messages'), + { + noMinify: true, + }, + ], + ], + presets: [['@babel/preset-react', {runtime: 'automatic'}]], + }), + ], + resolve: { + alias: moduleResolution(command === 'serve' ? 'source' : 'development'), + }, + }; +}); diff --git a/examples/vanilla-js-plugin/package.json b/examples/vanilla-js-plugin/package.json index 0cd7c243361..0a24651a3af 100644 --- a/examples/vanilla-js-plugin/package.json +++ b/examples/vanilla-js-plugin/package.json @@ -1,7 +1,7 @@ { "name": "@lexical/vanilla-js-plugin-example", "private": true, - "version": "0.21.0", + "version": "0.23.1", "type": "module", "scripts": { "dev": "vite", @@ -9,12 +9,12 @@ "preview": "vite preview" }, "dependencies": { - "@lexical/dragon": "0.21.0", - "@lexical/history": "0.21.0", - "@lexical/rich-text": "0.21.0", - "@lexical/utils": "0.21.0", + "@lexical/dragon": "0.23.1", + "@lexical/history": "0.23.1", + "@lexical/rich-text": "0.23.1", + "@lexical/utils": "0.23.1", "emoji-datasource-facebook": "15.1.2", - "lexical": "0.21.0" + "lexical": "0.23.1" }, "devDependencies": { "typescript": "^5.2.2", diff --git a/examples/vanilla-js-plugin/src/emoji-plugin/EmojiNode.ts b/examples/vanilla-js-plugin/src/emoji-plugin/EmojiNode.ts index 8c4da075173..5717a9c86b8 100644 --- a/examples/vanilla-js-plugin/src/emoji-plugin/EmojiNode.ts +++ b/examples/vanilla-js-plugin/src/emoji-plugin/EmojiNode.ts @@ -60,7 +60,6 @@ export class EmojiNode extends TextNode { exportJSON(): SerializedEmojiNode { return { ...super.exportJSON(), - type: 'emoji', unifiedID: this.__unifiedID, }; } diff --git a/examples/vanilla-js/package.json b/examples/vanilla-js/package.json index 37bc8356971..ec304b9ca93 100644 --- a/examples/vanilla-js/package.json +++ b/examples/vanilla-js/package.json @@ -1,7 +1,7 @@ { "name": "@lexical/vanilla-js-example", "private": true, - "version": "0.21.0", + "version": "0.23.1", "type": "module", "scripts": { "dev": "vite", @@ -9,11 +9,11 @@ "preview": "vite preview" }, "dependencies": { - "@lexical/dragon": "0.21.0", - "@lexical/history": "0.21.0", - "@lexical/rich-text": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/dragon": "0.23.1", + "@lexical/history": "0.23.1", + "@lexical/rich-text": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" }, "devDependencies": { "typescript": "^5.2.2", diff --git a/package-lock.json b/package-lock.json index 4488fab50c5..04863bf15dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@lexical/monorepo", - "version": "0.21.0", + "version": "0.23.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@lexical/monorepo", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "workspaces": [ "packages/*" @@ -15,7 +15,6 @@ "yjs": "^13.5.42" }, "devDependencies": { - "@ampproject/rollup-plugin-closure-compiler": "^0.27.0", "@babel/core": "^7.24.5", "@babel/eslint-parser": "^7.24.5", "@babel/plugin-transform-optional-catch-binding": "^7.24.1", @@ -657,121 +656,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@ampproject/remapping": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-0.2.0.tgz", - "integrity": "sha512-a4EztS9/GOVQjX5Ol+Iz33TFhaXvYBF7aB6D8+Qz0/SCIxOm3UNRhGZiwcCuJ8/Ifc6NCogp3S48kc5hFxRpUw==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "1.0.0", - "sourcemap-codec": "1.4.8" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@ampproject/rollup-plugin-closure-compiler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@ampproject/rollup-plugin-closure-compiler/-/rollup-plugin-closure-compiler-0.27.0.tgz", - "integrity": "sha512-stpAOn2ZZEJuAV39HFw9cnKJYNhEeHtcsoa83orpLDhSxsxSbVEKwHaWlFBaQYpQRSOdapC4eJhJnCzocZxnqg==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "0.2.0", - "acorn": "7.3.1", - "acorn-walk": "7.1.1", - "estree-walker": "2.0.1", - "google-closure-compiler": "20210808.0.0", - "magic-string": "0.25.7", - "uuid": "8.1.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "rollup": ">=1.27" - } - }, - "node_modules/@ampproject/rollup-plugin-closure-compiler/node_modules/google-closure-compiler": { - "version": "20210808.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler/-/google-closure-compiler-20210808.0.0.tgz", - "integrity": "sha512-+R2+P1tT1lEnDDGk8b+WXfyVZgWjcCK9n1mmZe8pMEzPaPWxqK7GMetLVWnqfTDJ5Q+LRspOiFBv3Is+0yuhCA==", - "dev": true, - "dependencies": { - "chalk": "2.x", - "google-closure-compiler-java": "^20210808.0.0", - "minimist": "1.x", - "vinyl": "2.x", - "vinyl-sourcemaps-apply": "^0.2.0" - }, - "bin": { - "google-closure-compiler": "cli.js" - }, - "engines": { - "node": ">=10" - }, - "optionalDependencies": { - "google-closure-compiler-linux": "^20210808.0.0", - "google-closure-compiler-osx": "^20210808.0.0", - "google-closure-compiler-windows": "^20210808.0.0" - } - }, - "node_modules/@ampproject/rollup-plugin-closure-compiler/node_modules/google-closure-compiler-java": { - "version": "20210808.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-java/-/google-closure-compiler-java-20210808.0.0.tgz", - "integrity": "sha512-7dEQfBzOdwdjwa/Pq8VAypNBKyWRrOcKjnNYOO9gEg2hjh8XVMeQzTqw4uANfVvvANGdE/JjD+HF6zHVgLRwjg==", - "dev": true - }, - "node_modules/@ampproject/rollup-plugin-closure-compiler/node_modules/google-closure-compiler-linux": { - "version": "20210808.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-linux/-/google-closure-compiler-linux-20210808.0.0.tgz", - "integrity": "sha512-byKi5ITUiWRvEIcQo76i1siVnOwrTmG+GNcBG4cJ7x8IE6+4ki9rG5pUe4+DOYHkfk52XU6XHt9aAAgCcFDKpg==", - "cpu": [ - "x64", - "x86" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@ampproject/rollup-plugin-closure-compiler/node_modules/google-closure-compiler-osx": { - "version": "20210808.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-osx/-/google-closure-compiler-osx-20210808.0.0.tgz", - "integrity": "sha512-iwyAY6dGj1FrrBdmfwKXkjtTGJnqe8F+9WZbfXxiBjkWLtIsJt2dD1+q7g/sw3w8mdHrGQAdxtDZP/usMwj/Rg==", - "cpu": [ - "x64", - "x86", - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@ampproject/rollup-plugin-closure-compiler/node_modules/google-closure-compiler-windows": { - "version": "20210808.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-windows/-/google-closure-compiler-windows-20210808.0.0.tgz", - "integrity": "sha512-VI+UUYwtGWDYwpiixrWRD8EklHgl6PMbiEaHxQSrQbH8PDXytwaOKqmsaH2lWYd5Y/BOZie2MzjY7F5JI69q1w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@ampproject/rollup-plugin-closure-compiler/node_modules/uuid": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz", - "integrity": "sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/@babel/code-frame": { "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", @@ -6754,15 +6638,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-1.0.0.tgz", - "integrity": "sha512-9oLAnygRMi8Q5QkYEU4XWK04B+nuoXoxjRvRxgjuChkLZFBja0YPSgdZ7dZtwhncLBcQe/I/E+fLuk5qxcYVJA==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/set-array": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", @@ -10310,15 +10185,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", - "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/address": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/address/-/address-1.2.0.tgz", @@ -18079,12 +17945,6 @@ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, - "node_modules/estree-walker": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz", - "integrity": "sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg==", - "dev": true - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -38927,28 +38787,28 @@ } }, "packages/lexical": { - "version": "0.21.0", + "version": "0.23.1", "license": "MIT" }, "packages/lexical-clipboard": { "name": "@lexical/clipboard", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/html": "0.21.0", - "@lexical/list": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/html": "0.23.1", + "@lexical/list": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "packages/lexical-code": { "name": "@lexical/code", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1", "prismjs": "^1.27.0" }, "devDependencies": { @@ -38957,7 +38817,7 @@ }, "packages/lexical-devtools": { "name": "@lexical/devtools", - "version": "0.21.0", + "version": "0.23.1", "hasInstallScript": true, "dependencies": { "@chakra-ui/react": "^2.8.2", @@ -38974,12 +38834,12 @@ "devDependencies": { "@babel/plugin-transform-flow-strip-types": "^7.24.7", "@babel/preset-react": "^7.24.7", - "@lexical/devtools-core": "0.21.0", + "@lexical/devtools-core": "0.23.1", "@rollup/plugin-babel": "^6.0.4", "@types/react": "^18.2.46", "@types/react-dom": "^18.2.18", "@vitejs/plugin-react": "^4.2.1", - "lexical": "0.21.0", + "lexical": "0.23.1", "typescript": "^5.4.5", "vite": "^5.2.2", "wxt": "^0.17.0" @@ -38987,15 +38847,15 @@ }, "packages/lexical-devtools-core": { "name": "@lexical/devtools-core", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/html": "0.21.0", - "@lexical/link": "0.21.0", - "@lexical/mark": "0.21.0", - "@lexical/table": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/html": "0.23.1", + "@lexical/link": "0.23.1", + "@lexical/mark": "0.23.1", + "@lexical/table": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" }, "peerDependencies": { "react": ">=17.x", @@ -39004,15 +38864,15 @@ }, "packages/lexical-dragon": { "name": "@lexical/dragon", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "packages/lexical-eslint-plugin": { "name": "@lexical/eslint-plugin", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "devDependencies": { "@types/eslint": "^8.56.9" @@ -39023,136 +38883,136 @@ }, "packages/lexical-file": { "name": "@lexical/file", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "packages/lexical-hashtag": { "name": "@lexical/hashtag", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "packages/lexical-headless": { "name": "@lexical/headless", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "packages/lexical-history": { "name": "@lexical/history", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "packages/lexical-html": { "name": "@lexical/html", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/selection": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/selection": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "packages/lexical-link": { "name": "@lexical/link", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "packages/lexical-list": { "name": "@lexical/list", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "packages/lexical-mark": { "name": "@lexical/mark", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "packages/lexical-markdown": { "name": "@lexical/markdown", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/code": "0.21.0", - "@lexical/link": "0.21.0", - "@lexical/list": "0.21.0", - "@lexical/rich-text": "0.21.0", - "@lexical/text": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/code": "0.23.1", + "@lexical/link": "0.23.1", + "@lexical/list": "0.23.1", + "@lexical/rich-text": "0.23.1", + "@lexical/text": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "packages/lexical-offset": { "name": "@lexical/offset", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "packages/lexical-overflow": { "name": "@lexical/overflow", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "packages/lexical-plain-text": { "name": "@lexical/plain-text", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/clipboard": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/clipboard": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "packages/lexical-playground": { - "version": "0.21.0", + "version": "0.23.1", "dependencies": { "@excalidraw/excalidraw": "^0.17.0", - "@lexical/clipboard": "0.21.0", - "@lexical/code": "0.21.0", - "@lexical/file": "0.21.0", - "@lexical/hashtag": "0.21.0", - "@lexical/link": "0.21.0", - "@lexical/list": "0.21.0", - "@lexical/mark": "0.21.0", - "@lexical/overflow": "0.21.0", - "@lexical/plain-text": "0.21.0", - "@lexical/react": "0.21.0", - "@lexical/rich-text": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/table": "0.21.0", - "@lexical/utils": "0.21.0", + "@lexical/clipboard": "0.23.1", + "@lexical/code": "0.23.1", + "@lexical/file": "0.23.1", + "@lexical/hashtag": "0.23.1", + "@lexical/link": "0.23.1", + "@lexical/list": "0.23.1", + "@lexical/mark": "0.23.1", + "@lexical/overflow": "0.23.1", + "@lexical/plain-text": "0.23.1", + "@lexical/react": "0.23.1", + "@lexical/rich-text": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/table": "0.23.1", + "@lexical/utils": "0.23.1", "katex": "^0.16.10", - "lexical": "0.21.0", + "lexical": "0.23.1", "lodash-es": "^4.17.21", "prettier": "^3.4.2", "react": "^18.2.0", @@ -39191,28 +39051,28 @@ }, "packages/lexical-react": { "name": "@lexical/react", - "version": "0.21.0", - "license": "MIT", - "dependencies": { - "@lexical/clipboard": "0.21.0", - "@lexical/code": "0.21.0", - "@lexical/devtools-core": "0.21.0", - "@lexical/dragon": "0.21.0", - "@lexical/hashtag": "0.21.0", - "@lexical/history": "0.21.0", - "@lexical/link": "0.21.0", - "@lexical/list": "0.21.0", - "@lexical/mark": "0.21.0", - "@lexical/markdown": "0.21.0", - "@lexical/overflow": "0.21.0", - "@lexical/plain-text": "0.21.0", - "@lexical/rich-text": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/table": "0.21.0", - "@lexical/text": "0.21.0", - "@lexical/utils": "0.21.0", - "@lexical/yjs": "0.21.0", - "lexical": "0.21.0", + "version": "0.23.1", + "license": "MIT", + "dependencies": { + "@lexical/clipboard": "0.23.1", + "@lexical/code": "0.23.1", + "@lexical/devtools-core": "0.23.1", + "@lexical/dragon": "0.23.1", + "@lexical/hashtag": "0.23.1", + "@lexical/history": "0.23.1", + "@lexical/link": "0.23.1", + "@lexical/list": "0.23.1", + "@lexical/mark": "0.23.1", + "@lexical/markdown": "0.23.1", + "@lexical/overflow": "0.23.1", + "@lexical/plain-text": "0.23.1", + "@lexical/rich-text": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/table": "0.23.1", + "@lexical/text": "0.23.1", + "@lexical/utils": "0.23.1", + "@lexical/yjs": "0.23.1", + "lexical": "0.23.1", "react-error-boundary": "^3.1.4" }, "peerDependencies": { @@ -39222,55 +39082,55 @@ }, "packages/lexical-rich-text": { "name": "@lexical/rich-text", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/clipboard": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/clipboard": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "packages/lexical-selection": { "name": "@lexical/selection", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "packages/lexical-table": { "name": "@lexical/table", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/clipboard": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/clipboard": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "packages/lexical-text": { "name": "@lexical/text", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "packages/lexical-utils": { "name": "@lexical/utils", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/list": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/table": "0.21.0", - "lexical": "0.21.0" + "@lexical/list": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/table": "0.23.1", + "lexical": "0.23.1" } }, "packages/lexical-website": { "name": "@lexical/website", - "version": "0.21.0", + "version": "0.23.1", "dependencies": { "@docusaurus/core": "3.6.0", "@docusaurus/faster": "3.6.0", @@ -39300,12 +39160,12 @@ }, "packages/lexical-yjs": { "name": "@lexical/yjs", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "@lexical/offset": "0.21.0", - "@lexical/selection": "0.21.0", - "lexical": "0.21.0" + "@lexical/offset": "0.23.1", + "@lexical/selection": "0.23.1", + "lexical": "0.23.1" }, "peerDependencies": { "yjs": ">=13.5.22" @@ -39338,10 +39198,10 @@ } }, "packages/shared": { - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } } }, @@ -39758,82 +39618,6 @@ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", "dev": true }, - "@ampproject/remapping": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-0.2.0.tgz", - "integrity": "sha512-a4EztS9/GOVQjX5Ol+Iz33TFhaXvYBF7aB6D8+Qz0/SCIxOm3UNRhGZiwcCuJ8/Ifc6NCogp3S48kc5hFxRpUw==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "1.0.0", - "sourcemap-codec": "1.4.8" - } - }, - "@ampproject/rollup-plugin-closure-compiler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@ampproject/rollup-plugin-closure-compiler/-/rollup-plugin-closure-compiler-0.27.0.tgz", - "integrity": "sha512-stpAOn2ZZEJuAV39HFw9cnKJYNhEeHtcsoa83orpLDhSxsxSbVEKwHaWlFBaQYpQRSOdapC4eJhJnCzocZxnqg==", - "dev": true, - "requires": { - "@ampproject/remapping": "0.2.0", - "acorn": "7.3.1", - "acorn-walk": "7.1.1", - "estree-walker": "2.0.1", - "google-closure-compiler": "20210808.0.0", - "magic-string": "0.25.7", - "uuid": "8.1.0" - }, - "dependencies": { - "google-closure-compiler": { - "version": "20210808.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler/-/google-closure-compiler-20210808.0.0.tgz", - "integrity": "sha512-+R2+P1tT1lEnDDGk8b+WXfyVZgWjcCK9n1mmZe8pMEzPaPWxqK7GMetLVWnqfTDJ5Q+LRspOiFBv3Is+0yuhCA==", - "dev": true, - "requires": { - "chalk": "2.x", - "google-closure-compiler-java": "^20210808.0.0", - "google-closure-compiler-linux": "^20210808.0.0", - "google-closure-compiler-osx": "^20210808.0.0", - "google-closure-compiler-windows": "^20210808.0.0", - "minimist": "1.x", - "vinyl": "2.x", - "vinyl-sourcemaps-apply": "^0.2.0" - } - }, - "google-closure-compiler-java": { - "version": "20210808.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-java/-/google-closure-compiler-java-20210808.0.0.tgz", - "integrity": "sha512-7dEQfBzOdwdjwa/Pq8VAypNBKyWRrOcKjnNYOO9gEg2hjh8XVMeQzTqw4uANfVvvANGdE/JjD+HF6zHVgLRwjg==", - "dev": true - }, - "google-closure-compiler-linux": { - "version": "20210808.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-linux/-/google-closure-compiler-linux-20210808.0.0.tgz", - "integrity": "sha512-byKi5ITUiWRvEIcQo76i1siVnOwrTmG+GNcBG4cJ7x8IE6+4ki9rG5pUe4+DOYHkfk52XU6XHt9aAAgCcFDKpg==", - "dev": true, - "optional": true - }, - "google-closure-compiler-osx": { - "version": "20210808.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-osx/-/google-closure-compiler-osx-20210808.0.0.tgz", - "integrity": "sha512-iwyAY6dGj1FrrBdmfwKXkjtTGJnqe8F+9WZbfXxiBjkWLtIsJt2dD1+q7g/sw3w8mdHrGQAdxtDZP/usMwj/Rg==", - "dev": true, - "optional": true - }, - "google-closure-compiler-windows": { - "version": "20210808.0.0", - "resolved": "https://registry.npmjs.org/google-closure-compiler-windows/-/google-closure-compiler-windows-20210808.0.0.tgz", - "integrity": "sha512-VI+UUYwtGWDYwpiixrWRD8EklHgl6PMbiEaHxQSrQbH8PDXytwaOKqmsaH2lWYd5Y/BOZie2MzjY7F5JI69q1w==", - "dev": true, - "optional": true - }, - "uuid": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz", - "integrity": "sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg==", - "dev": true - } - } - }, "@babel/code-frame": { "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", @@ -43922,12 +43706,6 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, - "@jridgewell/resolve-uri": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-1.0.0.tgz", - "integrity": "sha512-9oLAnygRMi8Q5QkYEU4XWK04B+nuoXoxjRvRxgjuChkLZFBja0YPSgdZ7dZtwhncLBcQe/I/E+fLuk5qxcYVJA==", - "dev": true - }, "@jridgewell/set-array": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", @@ -43971,19 +43749,19 @@ "@lexical/clipboard": { "version": "file:packages/lexical-clipboard", "requires": { - "@lexical/html": "0.21.0", - "@lexical/list": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/html": "0.23.1", + "@lexical/list": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "@lexical/code": { "version": "file:packages/lexical-code", "requires": { - "@lexical/utils": "0.21.0", + "@lexical/utils": "0.23.1", "@types/prismjs": "^1.26.0", - "lexical": "0.21.0", + "lexical": "0.23.1", "prismjs": "^1.27.0" } }, @@ -43995,7 +43773,7 @@ "@chakra-ui/react": "^2.8.2", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", - "@lexical/devtools-core": "0.21.0", + "@lexical/devtools-core": "0.23.1", "@rollup/plugin-babel": "^6.0.4", "@types/react": "^18.2.46", "@types/react-dom": "^18.2.18", @@ -44004,7 +43782,7 @@ "@webext-pegasus/store-zustand": "^0.3.0", "@webext-pegasus/transport": "^0.3.0", "framer-motion": "^11.1.5", - "lexical": "0.21.0", + "lexical": "0.23.1", "react": "^18.2.0", "react-dom": "^18.2.0", "typescript": "^5.4.5", @@ -44016,18 +43794,18 @@ "@lexical/devtools-core": { "version": "file:packages/lexical-devtools-core", "requires": { - "@lexical/html": "0.21.0", - "@lexical/link": "0.21.0", - "@lexical/mark": "0.21.0", - "@lexical/table": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/html": "0.23.1", + "@lexical/link": "0.23.1", + "@lexical/mark": "0.23.1", + "@lexical/table": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "@lexical/dragon": { "version": "file:packages/lexical-dragon", "requires": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "@lexical/eslint-plugin": { @@ -44039,152 +43817,152 @@ "@lexical/file": { "version": "file:packages/lexical-file", "requires": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "@lexical/hashtag": { "version": "file:packages/lexical-hashtag", "requires": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "@lexical/headless": { "version": "file:packages/lexical-headless", "requires": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "@lexical/history": { "version": "file:packages/lexical-history", "requires": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "@lexical/html": { "version": "file:packages/lexical-html", "requires": { - "@lexical/selection": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/selection": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "@lexical/link": { "version": "file:packages/lexical-link", "requires": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "@lexical/list": { "version": "file:packages/lexical-list", "requires": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "@lexical/mark": { "version": "file:packages/lexical-mark", "requires": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "@lexical/markdown": { "version": "file:packages/lexical-markdown", "requires": { - "@lexical/code": "0.21.0", - "@lexical/link": "0.21.0", - "@lexical/list": "0.21.0", - "@lexical/rich-text": "0.21.0", - "@lexical/text": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/code": "0.23.1", + "@lexical/link": "0.23.1", + "@lexical/list": "0.23.1", + "@lexical/rich-text": "0.23.1", + "@lexical/text": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "@lexical/offset": { "version": "file:packages/lexical-offset", "requires": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "@lexical/overflow": { "version": "file:packages/lexical-overflow", "requires": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "@lexical/plain-text": { "version": "file:packages/lexical-plain-text", "requires": { - "@lexical/clipboard": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/clipboard": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "@lexical/react": { "version": "file:packages/lexical-react", "requires": { - "@lexical/clipboard": "0.21.0", - "@lexical/code": "0.21.0", - "@lexical/devtools-core": "0.21.0", - "@lexical/dragon": "0.21.0", - "@lexical/hashtag": "0.21.0", - "@lexical/history": "0.21.0", - "@lexical/link": "0.21.0", - "@lexical/list": "0.21.0", - "@lexical/mark": "0.21.0", - "@lexical/markdown": "0.21.0", - "@lexical/overflow": "0.21.0", - "@lexical/plain-text": "0.21.0", - "@lexical/rich-text": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/table": "0.21.0", - "@lexical/text": "0.21.0", - "@lexical/utils": "0.21.0", - "@lexical/yjs": "0.21.0", - "lexical": "0.21.0", + "@lexical/clipboard": "0.23.1", + "@lexical/code": "0.23.1", + "@lexical/devtools-core": "0.23.1", + "@lexical/dragon": "0.23.1", + "@lexical/hashtag": "0.23.1", + "@lexical/history": "0.23.1", + "@lexical/link": "0.23.1", + "@lexical/list": "0.23.1", + "@lexical/mark": "0.23.1", + "@lexical/markdown": "0.23.1", + "@lexical/overflow": "0.23.1", + "@lexical/plain-text": "0.23.1", + "@lexical/rich-text": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/table": "0.23.1", + "@lexical/text": "0.23.1", + "@lexical/utils": "0.23.1", + "@lexical/yjs": "0.23.1", + "lexical": "0.23.1", "react-error-boundary": "^3.1.4" } }, "@lexical/rich-text": { "version": "file:packages/lexical-rich-text", "requires": { - "@lexical/clipboard": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/clipboard": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "@lexical/selection": { "version": "file:packages/lexical-selection", "requires": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "@lexical/table": { "version": "file:packages/lexical-table", "requires": { - "@lexical/clipboard": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/clipboard": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } }, "@lexical/text": { "version": "file:packages/lexical-text", "requires": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "@lexical/utils": { "version": "file:packages/lexical-utils", "requires": { - "@lexical/list": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/table": "0.21.0", - "lexical": "0.21.0" + "@lexical/list": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/table": "0.23.1", + "lexical": "0.23.1" } }, "@lexical/website": { @@ -44217,9 +43995,9 @@ "@lexical/yjs": { "version": "file:packages/lexical-yjs", "requires": { - "@lexical/offset": "0.21.0", - "@lexical/selection": "0.21.0", - "lexical": "0.21.0" + "@lexical/offset": "0.23.1", + "@lexical/selection": "0.23.1", + "lexical": "0.23.1" } }, "@mdx-js/mdx": { @@ -46494,12 +46272,6 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" }, - "acorn-walk": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.1.1.tgz", - "integrity": "sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==", - "dev": true - }, "address": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/address/-/address-1.2.0.tgz", @@ -51895,12 +51667,6 @@ } } }, - "estree-walker": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz", - "integrity": "sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg==", - "dev": true - }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -56260,26 +56026,26 @@ "@babel/plugin-transform-flow-strip-types": "^7.24.7", "@babel/preset-react": "^7.24.7", "@excalidraw/excalidraw": "^0.17.0", - "@lexical/clipboard": "0.21.0", - "@lexical/code": "0.21.0", - "@lexical/file": "0.21.0", - "@lexical/hashtag": "0.21.0", - "@lexical/link": "0.21.0", - "@lexical/list": "0.21.0", - "@lexical/mark": "0.21.0", - "@lexical/overflow": "0.21.0", - "@lexical/plain-text": "0.21.0", - "@lexical/react": "0.21.0", - "@lexical/rich-text": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/table": "0.21.0", - "@lexical/utils": "0.21.0", + "@lexical/clipboard": "0.23.1", + "@lexical/code": "0.23.1", + "@lexical/file": "0.23.1", + "@lexical/hashtag": "0.23.1", + "@lexical/link": "0.23.1", + "@lexical/list": "0.23.1", + "@lexical/mark": "0.23.1", + "@lexical/overflow": "0.23.1", + "@lexical/plain-text": "0.23.1", + "@lexical/react": "0.23.1", + "@lexical/rich-text": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/table": "0.23.1", + "@lexical/utils": "0.23.1", "@rollup/plugin-babel": "^6.0.4", "@rollup/plugin-commonjs": "^25.0.7", "@types/lodash-es": "^4.14.182", "@vitejs/plugin-react": "^4.2.1", "katex": "^0.16.10", - "lexical": "0.21.0", + "lexical": "0.23.1", "lodash-es": "^4.17.21", "prettier": "^3.4.2", "react": "^18.2.0", @@ -62575,7 +62341,7 @@ "shared": { "version": "file:packages/shared", "requires": { - "lexical": "0.21.0" + "lexical": "0.23.1" } }, "shebang-command": { diff --git a/package.json b/package.json index ba3ea744db2..15d059b8f62 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@lexical/monorepo", "description": "Lexical is an extensible text editor framework that provides excellent reliability, accessibility and performance.", - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "private": true, "workspaces": [ @@ -110,7 +110,6 @@ "size": "npm run build-prod && size-limit" }, "devDependencies": { - "@ampproject/rollup-plugin-closure-compiler": "^0.27.0", "@babel/core": "^7.24.5", "@babel/eslint-parser": "^7.24.5", "@babel/plugin-transform-optional-catch-binding": "^7.24.1", diff --git a/packages/lexical-clipboard/package.json b/packages/lexical-clipboard/package.json index e6346978107..c3d5f0b655c 100644 --- a/packages/lexical-clipboard/package.json +++ b/packages/lexical-clipboard/package.json @@ -9,15 +9,15 @@ "paste" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalClipboard.js", "types": "index.d.ts", "dependencies": { - "@lexical/html": "0.21.0", - "@lexical/list": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/html": "0.23.1", + "@lexical/list": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" }, "repository": { "type": "git", diff --git a/packages/lexical-clipboard/src/clipboard.ts b/packages/lexical-clipboard/src/clipboard.ts index 9f9155be596..47aacb4b92b 100644 --- a/packages/lexical-clipboard/src/clipboard.ts +++ b/packages/lexical-clipboard/src/clipboard.ts @@ -148,7 +148,12 @@ export function $insertDataTransferForRichText( } const htmlString = dataTransfer.getData('text/html'); - if (htmlString) { + const plainString = dataTransfer.getData('text/plain'); + + // Skip HTML handling if it matches the plain text representation. + // This avoids unnecessary processing for plain text strings created by + // iOS Safari autocorrect, which incorrectly includes a `text/html` type. + if (htmlString && plainString !== htmlString) { try { const parser = new DOMParser(); const dom = parser.parseFromString( @@ -165,8 +170,7 @@ export function $insertDataTransferForRichText( // Multi-line plain text in rich text mode pasted as separate paragraphs // instead of single paragraph with linebreaks. // Webkit-specific: Supports read 'text/uri-list' in clipboard. - const text = - dataTransfer.getData('text/plain') || dataTransfer.getData('text/uri-list'); + const text = plainString || dataTransfer.getData('text/uri-list'); if (text != null) { if ($isRangeSelection(selection)) { const parts = text.split(/(\r?\n|\t)/); @@ -420,9 +424,9 @@ export async function copyToClipboard( } const rootElement = editor.getRootElement(); - const windowDocument = - editor._window == null ? window.document : editor._window.document; - const domSelection = getDOMSelection(editor._window); + const editorWindow = editor._window || window; + const windowDocument = window.document; + const domSelection = getDOMSelection(editorWindow); if (rootElement === null || domSelection === null) { return false; } diff --git a/packages/lexical-code/package.json b/packages/lexical-code/package.json index c6d27e70d3c..97a5f5f954e 100644 --- a/packages/lexical-code/package.json +++ b/packages/lexical-code/package.json @@ -8,12 +8,12 @@ "code" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalCode.js", "types": "index.d.ts", "dependencies": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1", "prismjs": "^1.27.0" }, "repository": { diff --git a/packages/lexical-code/src/CodeHighlightNode.ts b/packages/lexical-code/src/CodeHighlightNode.ts index c9b43e486d3..b0c160328e9 100644 --- a/packages/lexical-code/src/CodeHighlightNode.ts +++ b/packages/lexical-code/src/CodeHighlightNode.ts @@ -10,6 +10,7 @@ import type { EditorConfig, EditorThemeClasses, LexicalNode, + LexicalUpdateJSON, LineBreakNode, NodeKey, SerializedTextNode, @@ -97,7 +98,7 @@ export class CodeHighlightNode extends TextNode { __highlightType: string | null | undefined; constructor( - text: string, + text: string = '', highlightType?: string | null | undefined, key?: NodeKey, ) { @@ -122,6 +123,12 @@ export class CodeHighlightNode extends TextNode { return self.__highlightType; } + setHighlightType(highlightType?: string | null | undefined): this { + const self = this.getWritable(); + self.__highlightType = highlightType || undefined; + return self; + } + canHaveFormat(): boolean { return false; } @@ -160,23 +167,21 @@ export class CodeHighlightNode extends TextNode { static importJSON( serializedNode: SerializedCodeHighlightNode, ): CodeHighlightNode { - const node = $createCodeHighlightNode( - serializedNode.text, - serializedNode.highlightType, - ); - node.setFormat(serializedNode.format); - node.setDetail(serializedNode.detail); - node.setMode(serializedNode.mode); - node.setStyle(serializedNode.style); - return node; + return $createCodeHighlightNode().updateFromJSON(serializedNode); + } + + updateFromJSON( + serializedNode: LexicalUpdateJSON, + ): this { + return super + .updateFromJSON(serializedNode) + .setHighlightType(serializedNode.highlightType); } exportJSON(): SerializedCodeHighlightNode { return { ...super.exportJSON(), highlightType: this.getHighlightType(), - type: 'code-highlight', - version: 1, }; } @@ -207,7 +212,7 @@ function getHighlightThemeClass( } export function $createCodeHighlightNode( - text: string, + text: string = '', highlightType?: string | null | undefined, ): CodeHighlightNode { return $applyNodeReplacement(new CodeHighlightNode(text, highlightType)); diff --git a/packages/lexical-code/src/CodeNode.ts b/packages/lexical-code/src/CodeNode.ts index f2ae407c189..f6a2b975e8c 100644 --- a/packages/lexical-code/src/CodeNode.ts +++ b/packages/lexical-code/src/CodeNode.ts @@ -14,6 +14,7 @@ import type { EditorConfig, LexicalEditor, LexicalNode, + LexicalUpdateJSON, NodeKey, ParagraphNode, RangeSelection, @@ -88,7 +89,7 @@ export class CodeNode extends ElementNode { constructor(language?: string | null | undefined, key?: NodeKey) { super(key); - this.__language = language; + this.__language = language || undefined; this.__isSyntaxHighlightSupported = isLanguageSupportedByPrism(language); } @@ -212,19 +213,19 @@ export class CodeNode extends ElementNode { } static importJSON(serializedNode: SerializedCodeNode): CodeNode { - const node = $createCodeNode(serializedNode.language); - node.setFormat(serializedNode.format); - node.setIndent(serializedNode.indent); - node.setDirection(serializedNode.direction); - return node; + return $createCodeNode().updateFromJSON(serializedNode); + } + + updateFromJSON(serializedNode: LexicalUpdateJSON): this { + return super + .updateFromJSON(serializedNode) + .setLanguage(serializedNode.language); } exportJSON(): SerializedCodeNode { return { ...super.exportJSON(), language: this.getLanguage(), - type: 'code', - version: 1, }; } @@ -319,11 +320,12 @@ export class CodeNode extends ElementNode { return true; } - setLanguage(language: string): void { + setLanguage(language: string | null | undefined): this { const writable = this.getWritable(); - writable.__language = language; + writable.__language = language || undefined; writable.__isSyntaxHighlightSupported = isLanguageSupportedByPrism(language); + return writable; } getLanguage(): string | null | undefined { diff --git a/packages/lexical-code/src/__tests__/unit/LexicalCodeNode.test.ts b/packages/lexical-code/src/__tests__/unit/LexicalCodeNode.test.ts index c4f8a9bf6e7..fede2b48818 100644 --- a/packages/lexical-code/src/__tests__/unit/LexicalCodeNode.test.ts +++ b/packages/lexical-code/src/__tests__/unit/LexicalCodeNode.test.ts @@ -7,6 +7,7 @@ */ import { + $createCodeHighlightNode, $createCodeNode, $isCodeHighlightNode, registerCodeHighlighting, @@ -856,5 +857,33 @@ describe('LexicalCodeNode tests', () => { } } }); + describe('initial editor state before transforms', () => { + test('can be registered after initial editor state (regression #7014)', async () => { + const {editor} = testEnv; + await editor.update( + () => { + const root = $getRoot(); + const codeBlock = $createCodeNode('javascript'); + codeBlock.append( + $createCodeHighlightNode('const lexical = "awesome"'), + ); + root.append(codeBlock); + }, + {tag: 'history-merge'}, + ); + // before transform + expect(testEnv.innerHTML).toBe( + 'const lexical = "awesome"', + ); + registerRichText(editor); + registerTabIndentation(editor); + registerCodeHighlighting(editor); + await Promise.resolve(undefined); + // after transforms + expect(testEnv.innerHTML).toBe( + 'const lexical = "awesome"', + ); + }); + }); }); }); diff --git a/packages/lexical-devtools-core/package.json b/packages/lexical-devtools-core/package.json index a195002ad88..d2fb9cf85dd 100644 --- a/packages/lexical-devtools-core/package.json +++ b/packages/lexical-devtools-core/package.json @@ -8,16 +8,16 @@ "utils" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalDevtoolsCore.js", "types": "index.d.ts", "dependencies": { - "@lexical/html": "0.21.0", - "@lexical/link": "0.21.0", - "@lexical/mark": "0.21.0", - "@lexical/table": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/html": "0.23.1", + "@lexical/link": "0.23.1", + "@lexical/mark": "0.23.1", + "@lexical/table": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" }, "peerDependencies": { "react": ">=17.x", diff --git a/packages/lexical-devtools-core/src/TreeView.tsx b/packages/lexical-devtools-core/src/TreeView.tsx index 65bc7e51e16..7351bbc0166 100644 --- a/packages/lexical-devtools-core/src/TreeView.tsx +++ b/packages/lexical-devtools-core/src/TreeView.tsx @@ -7,6 +7,7 @@ */ import type {EditorSetOptions, EditorState} from 'lexical'; +import type {JSX} from 'react'; import * as React from 'react'; import {forwardRef, useCallback, useEffect, useRef, useState} from 'react'; diff --git a/packages/lexical-devtools/package.json b/packages/lexical-devtools/package.json index 61eb55296d6..254e4fe1e72 100644 --- a/packages/lexical-devtools/package.json +++ b/packages/lexical-devtools/package.json @@ -2,7 +2,7 @@ "name": "@lexical/devtools", "description": "Lexical DevTools browser extension", "private": true, - "version": "0.21.0", + "version": "0.23.1", "type": "module", "scripts": { "dev": "wxt", @@ -41,12 +41,12 @@ "devDependencies": { "@babel/plugin-transform-flow-strip-types": "^7.24.7", "@babel/preset-react": "^7.24.7", - "@lexical/devtools-core": "0.21.0", + "@lexical/devtools-core": "0.23.1", "@rollup/plugin-babel": "^6.0.4", "@types/react": "^18.2.46", "@types/react-dom": "^18.2.18", "@vitejs/plugin-react": "^4.2.1", - "lexical": "0.21.0", + "lexical": "0.23.1", "typescript": "^5.4.5", "vite": "^5.2.2", "wxt": "^0.17.0" diff --git a/packages/lexical-dragon/package.json b/packages/lexical-dragon/package.json index 439d3678b97..95ce8d03ec8 100644 --- a/packages/lexical-dragon/package.json +++ b/packages/lexical-dragon/package.json @@ -9,7 +9,7 @@ "accessibility" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalDragon.js", "types": "index.d.ts", "repository": { @@ -37,6 +37,6 @@ } }, "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } } diff --git a/packages/lexical-eslint-plugin/package.json b/packages/lexical-eslint-plugin/package.json index d3191b8a9c1..d7e4d99db99 100644 --- a/packages/lexical-eslint-plugin/package.json +++ b/packages/lexical-eslint-plugin/package.json @@ -8,7 +8,7 @@ "lexical", "editor" ], - "version": "0.21.0", + "version": "0.23.1", "license": "MIT", "repository": { "type": "git", diff --git a/packages/lexical-file/package.json b/packages/lexical-file/package.json index 614ee42ed8f..099377e00e6 100644 --- a/packages/lexical-file/package.json +++ b/packages/lexical-file/package.json @@ -10,7 +10,7 @@ "export" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalFile.js", "types": "index.d.ts", "repository": { @@ -38,6 +38,6 @@ } }, "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } } diff --git a/packages/lexical-hashtag/package.json b/packages/lexical-hashtag/package.json index 4b7fbbf523b..46d80b1deca 100644 --- a/packages/lexical-hashtag/package.json +++ b/packages/lexical-hashtag/package.json @@ -8,12 +8,12 @@ "hashtag" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalHashtag.js", "types": "index.d.ts", "dependencies": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" }, "repository": { "type": "git", diff --git a/packages/lexical-hashtag/src/LexicalHashtagNode.ts b/packages/lexical-hashtag/src/LexicalHashtagNode.ts index 657bafcd5e6..58543ec6338 100644 --- a/packages/lexical-hashtag/src/LexicalHashtagNode.ts +++ b/packages/lexical-hashtag/src/LexicalHashtagNode.ts @@ -6,12 +6,7 @@ * */ -import type { - EditorConfig, - LexicalNode, - NodeKey, - SerializedTextNode, -} from 'lexical'; +import type {EditorConfig, LexicalNode, SerializedTextNode} from 'lexical'; import {addClassNamesToElement} from '@lexical/utils'; import {$applyNodeReplacement, TextNode} from 'lexical'; @@ -26,10 +21,6 @@ export class HashtagNode extends TextNode { return new HashtagNode(node.__text, node.__key); } - constructor(text: string, key?: NodeKey) { - super(text, key); - } - createDOM(config: EditorConfig): HTMLElement { const element = super.createDOM(config); addClassNamesToElement(element, config.theme.hashtag); @@ -37,19 +28,7 @@ export class HashtagNode extends TextNode { } static importJSON(serializedNode: SerializedTextNode): HashtagNode { - const node = $createHashtagNode(serializedNode.text); - node.setFormat(serializedNode.format); - node.setDetail(serializedNode.detail); - node.setMode(serializedNode.mode); - node.setStyle(serializedNode.style); - return node; - } - - exportJSON(): SerializedTextNode { - return { - ...super.exportJSON(), - type: 'hashtag', - }; + return $createHashtagNode().updateFromJSON(serializedNode); } canInsertTextBefore(): boolean { diff --git a/packages/lexical-headless/package.json b/packages/lexical-headless/package.json index e50aac70eff..c5a497396a0 100644 --- a/packages/lexical-headless/package.json +++ b/packages/lexical-headless/package.json @@ -8,7 +8,7 @@ "headless" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalHeadless.js", "types": "index.d.ts", "repository": { @@ -36,6 +36,6 @@ } }, "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } } diff --git a/packages/lexical-history/package.json b/packages/lexical-history/package.json index 644a935da80..4e9314fdb19 100644 --- a/packages/lexical-history/package.json +++ b/packages/lexical-history/package.json @@ -8,12 +8,12 @@ "history" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalHistory.js", "types": "index.d.ts", "dependencies": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" }, "repository": { "type": "git", diff --git a/packages/lexical-history/src/__tests__/unit/LexicalHistory.test.tsx b/packages/lexical-history/src/__tests__/unit/LexicalHistory.test.tsx index 0cef7f59210..345b1b8f8a8 100644 --- a/packages/lexical-history/src/__tests__/unit/LexicalHistory.test.tsx +++ b/packages/lexical-history/src/__tests__/unit/LexicalHistory.test.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {createEmptyHistoryState, registerHistory} from '@lexical/history'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {ContentEditable} from '@lexical/react/LexicalContentEditable'; @@ -44,7 +46,7 @@ import {createRoot, Root} from 'react-dom/client'; import * as ReactTestUtils from 'shared/react-test-utils'; type SerializedCustomTextNode = Spread< - {type: ReturnType; classes: string[]}, + {type: string; classes: string[]}, SerializedTextNode >; @@ -87,7 +89,6 @@ class CustomTextNode extends TextNode { return { ...super.exportJSON(), classes: Array.from(this.getClasses()), - type: this.constructor.getType(), }; } } diff --git a/packages/lexical-html/package.json b/packages/lexical-html/package.json index 8f02327cbda..8891f0867be 100644 --- a/packages/lexical-html/package.json +++ b/packages/lexical-html/package.json @@ -8,7 +8,7 @@ "html" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalHtml.js", "types": "index.d.ts", "repository": { @@ -17,9 +17,9 @@ "directory": "packages/lexical-html" }, "dependencies": { - "@lexical/selection": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/selection": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" }, "module": "LexicalHtml.mjs", "sideEffects": false, diff --git a/packages/lexical-link/package.json b/packages/lexical-link/package.json index 95b1797099a..c50e19ccad8 100644 --- a/packages/lexical-link/package.json +++ b/packages/lexical-link/package.json @@ -8,12 +8,12 @@ "link" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalLink.js", "types": "index.d.ts", "dependencies": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" }, "repository": { "type": "git", diff --git a/packages/lexical-link/src/index.ts b/packages/lexical-link/src/index.ts index 2149cf4a30c..24291903b9d 100644 --- a/packages/lexical-link/src/index.ts +++ b/packages/lexical-link/src/index.ts @@ -13,6 +13,7 @@ import type { EditorConfig, LexicalCommand, LexicalNode, + LexicalUpdateJSON, NodeKey, Point, RangeSelection, @@ -87,7 +88,11 @@ export class LinkNode extends ElementNode { ); } - constructor(url: string, attributes: LinkAttributes = {}, key?: NodeKey) { + constructor( + url: string = '', + attributes: LinkAttributes = {}, + key?: NodeKey, + ) { super(key); const {target = null, rel = null, title = null} = attributes; this.__url = url; @@ -162,18 +167,17 @@ export class LinkNode extends ElementNode { }; } - static importJSON( - serializedNode: SerializedLinkNode | SerializedAutoLinkNode, - ): LinkNode { - const node = $createLinkNode(serializedNode.url, { - rel: serializedNode.rel, - target: serializedNode.target, - title: serializedNode.title, - }); - node.setFormat(serializedNode.format); - node.setIndent(serializedNode.indent); - node.setDirection(serializedNode.direction); - return node; + static importJSON(serializedNode: SerializedLinkNode): LinkNode { + return $createLinkNode().updateFromJSON(serializedNode); + } + + updateFromJSON(serializedNode: LexicalUpdateJSON): this { + return super + .updateFromJSON(serializedNode) + .setURL(serializedNode.url) + .setRel(serializedNode.rel || null) + .setTarget(serializedNode.target || null) + .setTitle(serializedNode.title || null); } sanitizeUrl(url: string): string { @@ -195,9 +199,7 @@ export class LinkNode extends ElementNode { rel: this.getRel(), target: this.getTarget(), title: this.getTitle(), - type: 'link', url: this.getURL(), - version: 1, }; } @@ -205,36 +207,40 @@ export class LinkNode extends ElementNode { return this.getLatest().__url; } - setURL(url: string): void { + setURL(url: string): this { const writable = this.getWritable(); writable.__url = url; + return writable; } getTarget(): null | string { return this.getLatest().__target; } - setTarget(target: null | string): void { + setTarget(target: null | string): this { const writable = this.getWritable(); writable.__target = target; + return writable; } getRel(): null | string { return this.getLatest().__rel; } - setRel(rel: null | string): void { + setRel(rel: null | string): this { const writable = this.getWritable(); writable.__rel = rel; + return writable; } getTitle(): null | string { return this.getLatest().__title; } - setTitle(title: null | string): void { + setTitle(title: null | string): this { const writable = this.getWritable(); writable.__title = title; + return writable; } insertNewAfter( @@ -318,7 +324,7 @@ function $convertAnchorElement(domNode: Node): DOMConversionOutput { * @returns The LinkNode. */ export function $createLinkNode( - url: string, + url: string = '', attributes?: LinkAttributes, ): LinkNode { return $applyNodeReplacement(new LinkNode(url, attributes)); @@ -349,7 +355,11 @@ export class AutoLinkNode extends LinkNode { /** Indicates whether the autolink was ever unlinked. **/ __isUnlinked: boolean; - constructor(url: string, attributes: AutoLinkAttributes = {}, key?: NodeKey) { + constructor( + url: string = '', + attributes: AutoLinkAttributes = {}, + key?: NodeKey, + ) { super(url, attributes, key); this.__isUnlinked = attributes.isUnlinked !== undefined && attributes.isUnlinked !== null @@ -378,7 +388,7 @@ export class AutoLinkNode extends LinkNode { return this.__isUnlinked; } - setIsUnlinked(value: boolean) { + setIsUnlinked(value: boolean): this { const self = this.getWritable(); self.__isUnlinked = value; return self; @@ -404,16 +414,15 @@ export class AutoLinkNode extends LinkNode { } static importJSON(serializedNode: SerializedAutoLinkNode): AutoLinkNode { - const node = $createAutoLinkNode(serializedNode.url, { - isUnlinked: serializedNode.isUnlinked, - rel: serializedNode.rel, - target: serializedNode.target, - title: serializedNode.title, - }); - node.setFormat(serializedNode.format); - node.setIndent(serializedNode.indent); - node.setDirection(serializedNode.direction); - return node; + return $createAutoLinkNode().updateFromJSON(serializedNode); + } + + updateFromJSON( + serializedNode: LexicalUpdateJSON, + ): this { + return super + .updateFromJSON(serializedNode) + .setIsUnlinked(serializedNode.isUnlinked || false); } static importDOM(): null { @@ -425,8 +434,6 @@ export class AutoLinkNode extends LinkNode { return { ...super.exportJSON(), isUnlinked: this.__isUnlinked, - type: 'autolink', - version: 1, }; } @@ -460,7 +467,7 @@ export class AutoLinkNode extends LinkNode { * @returns The LinkNode. */ export function $createAutoLinkNode( - url: string, + url: string = '', attributes?: AutoLinkAttributes, ): AutoLinkNode { return $applyNodeReplacement(new AutoLinkNode(url, attributes)); diff --git a/packages/lexical-list/README.md b/packages/lexical-list/README.md index 3728e76a160..9b5d97c6688 100644 --- a/packages/lexical-list/README.md +++ b/packages/lexical-list/README.md @@ -9,12 +9,12 @@ The API of @lexical/list primarily consists of Lexical Nodes that encapsulate li ## Functions -### insertList +### $insertList As the name suggests, this inserts a list of the provided type according to an algorithm that tries to determine the best way to do that based on -the current Selection. For instance, if some text is selected, insertList may try to move it into the first item in the list. See the API documentation for more detail. +the current Selection. For instance, if some text is selected, $insertList may try to move it into the first item in the list. See the API documentation for more detail. -### removeList +### $removeList Attempts to remove lists inside the current selection based on a set of opinionated heuristics that implement conventional editor behaviors. For instance, it converts empty ListItemNodes into empty ParagraphNodes. @@ -43,7 +43,7 @@ It's important to note that these commands don't have any functionality on their // MyListPlugin.ts editor.registerCommand(INSERT_UNORDERED_LIST_COMMAND, () => { - insertList(editor, 'bullet'); + $insertList(editor, 'bullet'); return true; }, COMMAND_PRIORITY_LOW); diff --git a/packages/lexical-list/flow/LexicalList.js.flow b/packages/lexical-list/flow/LexicalList.js.flow index 0eedd4038ff..a77252acd15 100644 --- a/packages/lexical-list/flow/LexicalList.js.flow +++ b/packages/lexical-list/flow/LexicalList.js.flow @@ -35,6 +35,10 @@ declare export function $isListNode( node: ?LexicalNode, ): node is ListNode; declare export function indentList(): void; +declare export function $insertList( + listType: ListType, +): void; +/** @deprecated use {@link $insertList} from an update or command listener */ declare export function insertList( editor: LexicalEditor, listType: ListType, @@ -72,7 +76,9 @@ declare export class ListNode extends ElementNode { static importJSON(serializedNode: SerializedListNode): ListNode; } declare export function outdentList(): void; -declare export function removeList(editor: LexicalEditor): boolean; +/** @deprecated use {@link $removeList} from an update or command listener */ +declare export function removeList(editor: LexicalEditor): void; +declare export function $removeList(): void; declare export var INSERT_UNORDERED_LIST_COMMAND: LexicalCommand; declare export var INSERT_ORDERED_LIST_COMMAND: LexicalCommand; diff --git a/packages/lexical-list/package.json b/packages/lexical-list/package.json index 0d179c2e933..08e6b0d6313 100644 --- a/packages/lexical-list/package.json +++ b/packages/lexical-list/package.json @@ -8,12 +8,12 @@ "list" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalList.js", "types": "index.d.ts", "dependencies": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" }, "repository": { "type": "git", diff --git a/packages/lexical-list/src/LexicalListItemNode.ts b/packages/lexical-list/src/LexicalListItemNode.ts index 9dade3ae0a3..0e5153bc256 100644 --- a/packages/lexical-list/src/LexicalListItemNode.ts +++ b/packages/lexical-list/src/LexicalListItemNode.ts @@ -15,6 +15,7 @@ import type { EditorConfig, EditorThemeClasses, LexicalNode, + LexicalUpdateJSON, NodeKey, ParagraphNode, RangeSelection, @@ -123,12 +124,16 @@ export class ListItemNode extends ElementNode { } static importJSON(serializedNode: SerializedListItemNode): ListItemNode { - const node = $createListItemNode(); - node.setChecked(serializedNode.checked); - node.setValue(serializedNode.value); - node.setFormat(serializedNode.format); - node.setDirection(serializedNode.direction); - return node; + return $createListItemNode().updateFromJSON(serializedNode); + } + + updateFromJSON( + serializedNode: LexicalUpdateJSON, + ): this { + return super + .updateFromJSON(serializedNode) + .setValue(serializedNode.value) + .setChecked(serializedNode.checked); } exportDOM(editor: LexicalEditor): DOMExportOutput { @@ -143,9 +148,7 @@ export class ListItemNode extends ElementNode { return { ...super.exportJSON(), checked: this.getChecked(), - type: 'listitem', value: this.getValue(), - version: 1, }; } @@ -259,9 +262,10 @@ export class ListItemNode extends ElementNode { _: RangeSelection, restoreSelection = true, ): ListItemNode | ParagraphNode { - const newElement = $createListItemNode( - this.__checked == null ? undefined : false, - ); + const newElement = $createListItemNode() + .updateFromJSON(this.exportJSON()) + .setChecked(this.getChecked() ? false : undefined); + this.insertAfter(newElement, restoreSelection); return newElement; @@ -312,9 +316,10 @@ export class ListItemNode extends ElementNode { return self.__value; } - setValue(value: number): void { + setValue(value: number): this { const self = this.getWritable(); self.__value = value; + return self; } getChecked(): boolean | undefined { @@ -330,13 +335,15 @@ export class ListItemNode extends ElementNode { return listType === 'check' ? Boolean(self.__checked) : undefined; } - setChecked(checked?: boolean): void { + setChecked(checked?: boolean): this { const self = this.getWritable(); self.__checked = checked; + return self; } - toggleChecked(): void { - this.setChecked(!this.__checked); + toggleChecked(): this { + const self = this.getWritable(); + return self.setChecked(!self.__checked); } getIndent(): number { diff --git a/packages/lexical-list/src/LexicalListNode.ts b/packages/lexical-list/src/LexicalListNode.ts index dfcaacc1d1f..6fdab61c6b1 100644 --- a/packages/lexical-list/src/LexicalListNode.ts +++ b/packages/lexical-list/src/LexicalListNode.ts @@ -23,6 +23,7 @@ import { ElementNode, LexicalEditor, LexicalNode, + LexicalUpdateJSON, NodeKey, SerializedElementNode, Spread, @@ -69,7 +70,7 @@ export class ListNode extends ElementNode { return new ListNode(listType, node.__start, node.__key); } - constructor(listType: ListType, start: number, key?: NodeKey) { + constructor(listType: ListType = 'number', start: number = 1, key?: NodeKey) { super(key); const _listType = TAG_TO_LIST_TYPE[listType] || listType; this.__listType = _listType; @@ -81,10 +82,11 @@ export class ListNode extends ElementNode { return this.__tag; } - setListType(type: ListType): void { + setListType(type: ListType): this { const writable = this.getWritable(); writable.__listType = type; writable.__tag = type === 'number' ? 'ol' : 'ul'; + return writable; } getListType(): ListType { @@ -95,6 +97,12 @@ export class ListNode extends ElementNode { return this.__start; } + setStart(start: number): this { + const self = this.getWritable(); + self.__start = start; + return self; + } + // View createDOM(config: EditorConfig, _editor?: LexicalEditor): HTMLElement { @@ -143,11 +151,14 @@ export class ListNode extends ElementNode { } static importJSON(serializedNode: SerializedListNode): ListNode { - const node = $createListNode(serializedNode.listType, serializedNode.start); - node.setFormat(serializedNode.format); - node.setIndent(serializedNode.indent); - node.setDirection(serializedNode.direction); - return node; + return $createListNode().updateFromJSON(serializedNode); + } + + updateFromJSON(serializedNode: LexicalUpdateJSON): this { + return super + .updateFromJSON(serializedNode) + .setListType(serializedNode.listType) + .setStart(serializedNode.start); } exportDOM(editor: LexicalEditor): DOMExportOutput { @@ -171,8 +182,6 @@ export class ListNode extends ElementNode { listType: this.getListType(), start: this.getStart(), tag: this.getTag(), - type: 'list', - version: 1, }; } @@ -351,7 +360,10 @@ const TAG_TO_LIST_TYPE: Record = { * @param start - Where an ordered list starts its count, start = 1 if left undefined. * @returns The new ListNode */ -export function $createListNode(listType: ListType, start = 1): ListNode { +export function $createListNode( + listType: ListType = 'number', + start = 1, +): ListNode { return $applyNodeReplacement(new ListNode(listType, start)); } diff --git a/packages/lexical-list/src/__tests__/unit/LexicalListNode.test.ts b/packages/lexical-list/src/__tests__/unit/LexicalListNode.test.ts index 18c7010d56b..09e664b3f90 100644 --- a/packages/lexical-list/src/__tests__/unit/LexicalListNode.test.ts +++ b/packages/lexical-list/src/__tests__/unit/LexicalListNode.test.ts @@ -57,9 +57,9 @@ describe('LexicalListNode tests', () => { expect(listNode.getTag()).toBe('ul'); expect(listNode.getTextContent()).toBe(''); }); - - // @ts-expect-error - expect(() => $createListNode()).toThrow(); + await editor.update(() => { + expect(() => $createListNode()).not.toThrow(); + }); }); test('ListNode.getTag()', async () => { diff --git a/packages/lexical-list/src/__tests__/unit/formatList.test.ts b/packages/lexical-list/src/__tests__/unit/formatList.test.ts new file mode 100644 index 00000000000..98f7e7cdf66 --- /dev/null +++ b/packages/lexical-list/src/__tests__/unit/formatList.test.ts @@ -0,0 +1,101 @@ +/** + * 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 { + $createTableCellNode, + $createTableNode, + $createTableRowNode, + TableCellNode, + TableNode, + TableRowNode, +} from '@lexical/table'; +import {$createParagraphNode, $createTextNode, $getRoot} from 'lexical'; +import {initializeUnitTest} from 'lexical/src/__tests__/utils'; + +import {$insertList} from '../../formatList'; +import {$isListNode} from '../../LexicalListNode'; + +describe('insertList', () => { + initializeUnitTest((testEnv) => { + test('inserting with empty root selection', async () => { + const {editor} = testEnv; + + await editor.update(() => { + $getRoot().select(); + }); + + await editor.update(() => { + $insertList('number'); + }); + + editor.read(() => { + const root = $getRoot(); + + expect(root.getChildrenSize()).toBe(1); + + const firstChild = root.getFirstChildOrThrow(); + + expect($isListNode(firstChild)).toBe(true); + }); + }); + + test('inserting in root selection with existing child', async () => { + const {editor} = testEnv; + + await editor.update(() => { + $getRoot().select(); + $getRoot().append( + $createParagraphNode().append($createTextNode('hello')), + ); + }); + + await editor.update(() => { + $insertList('number'); + }); + + editor.read(() => { + const root = $getRoot(); + + expect(root.getChildrenSize()).toBe(1); + + const firstChild = root.getFirstChildOrThrow(); + + expect($isListNode(firstChild)).toBe(true); + }); + }); + + test('inserting with empty shadow root selection', async () => { + const {editor} = testEnv; + + await editor.update(() => { + const table = $createTableNode(); + const row = $createTableRowNode(); + const cell = $createTableCellNode(); + $getRoot().append(table.append(row.append(cell))); + cell.select(); + }); + + await editor.update(() => { + $insertList('number'); + }); + + editor.read(() => { + const cell = $getRoot() + .getFirstChildOrThrow() + .getFirstChildOrThrow() + .getFirstChildOrThrow(); + + expect(cell.getChildrenSize()).toBe(1); + + const firstChild = cell.getFirstChildOrThrow(); + + expect($isListNode(firstChild)).toBe(true); + }); + }); + }); +}); diff --git a/packages/lexical-list/src/formatList.ts b/packages/lexical-list/src/formatList.ts index 46694253ebb..e4e574a1b93 100644 --- a/packages/lexical-list/src/formatList.ts +++ b/packages/lexical-list/src/formatList.ts @@ -15,7 +15,6 @@ import { $isRangeSelection, $isRootOrShadowRoot, ElementNode, - LexicalEditor, LexicalNode, NodeKey, ParagraphNode, @@ -58,90 +57,96 @@ function $isSelectingEmptyListItem( * If the selection's anchor node is not an empty ListItemNode, it will add a new ListNode or merge an existing ListNode, * unless the the node is a leaf node, in which case it will attempt to find a ListNode up the branch and replace it with * a new ListNode, or create a new ListNode at the nearest root/shadow root. - * @param editor - The lexical editor. * @param listType - The type of list, "number" | "bullet" | "check". */ -export function insertList(editor: LexicalEditor, listType: ListType): void { - editor.update(() => { - const selection = $getSelection(); - - if (selection !== null) { - const nodes = selection.getNodes(); - if ($isRangeSelection(selection)) { - const anchorAndFocus = selection.getStartEndPoints(); - invariant( - anchorAndFocus !== null, - 'insertList: anchor should be defined', - ); - const [anchor] = anchorAndFocus; - const anchorNode = anchor.getNode(); - const anchorNodeParent = anchorNode.getParent(); - - if ($isSelectingEmptyListItem(anchorNode, nodes)) { - const list = $createListNode(listType); - - if ($isRootOrShadowRoot(anchorNodeParent)) { - anchorNode.replace(list); - const listItem = $createListItemNode(); - if ($isElementNode(anchorNode)) { - listItem.setFormat(anchorNode.getFormatType()); - listItem.setIndent(anchorNode.getIndent()); - } - list.append(listItem); - } else if ($isListItemNode(anchorNode)) { - const parent = anchorNode.getParentOrThrow(); - append(list, parent.getChildren()); - parent.replace(list); - } +export function $insertList(listType: ListType): void { + const selection = $getSelection(); - return; + if (selection !== null) { + let nodes = selection.getNodes(); + if ($isRangeSelection(selection)) { + const anchorAndFocus = selection.getStartEndPoints(); + invariant( + anchorAndFocus !== null, + 'insertList: anchor should be defined', + ); + const [anchor] = anchorAndFocus; + const anchorNode = anchor.getNode(); + const anchorNodeParent = anchorNode.getParent(); + + if ($isRootOrShadowRoot(anchorNode)) { + const firstChild = anchorNode.getFirstChild(); + if (firstChild) { + nodes = firstChild.selectStart().getNodes(); + } else { + const paragraph = $createParagraphNode(); + anchorNode.append(paragraph); + nodes = paragraph.select().getNodes(); } + } else if ($isSelectingEmptyListItem(anchorNode, nodes)) { + const list = $createListNode(listType); + + if ($isRootOrShadowRoot(anchorNodeParent)) { + anchorNode.replace(list); + const listItem = $createListItemNode(); + if ($isElementNode(anchorNode)) { + listItem.setFormat(anchorNode.getFormatType()); + listItem.setIndent(anchorNode.getIndent()); + } + list.append(listItem); + } else if ($isListItemNode(anchorNode)) { + const parent = anchorNode.getParentOrThrow(); + append(list, parent.getChildren()); + parent.replace(list); + } + + return; } + } - const handled = new Set(); - for (let i = 0; i < nodes.length; i++) { - const node = nodes[i]; + const handled = new Set(); + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + + if ( + $isElementNode(node) && + node.isEmpty() && + !$isListItemNode(node) && + !handled.has(node.getKey()) + ) { + $createListOrMerge(node, listType); + continue; + } - if ( - $isElementNode(node) && - node.isEmpty() && - !$isListItemNode(node) && - !handled.has(node.getKey()) - ) { - $createListOrMerge(node, listType); - continue; - } + if ($isLeafNode(node)) { + let parent = node.getParent(); + while (parent != null) { + const parentKey = parent.getKey(); + + if ($isListNode(parent)) { + if (!handled.has(parentKey)) { + const newListNode = $createListNode(listType); + append(newListNode, parent.getChildren()); + parent.replace(newListNode); + handled.add(parentKey); + } - if ($isLeafNode(node)) { - let parent = node.getParent(); - while (parent != null) { - const parentKey = parent.getKey(); - - if ($isListNode(parent)) { - if (!handled.has(parentKey)) { - const newListNode = $createListNode(listType); - append(newListNode, parent.getChildren()); - parent.replace(newListNode); - handled.add(parentKey); - } + break; + } else { + const nextParent = parent.getParent(); + if ($isRootOrShadowRoot(nextParent) && !handled.has(parentKey)) { + handled.add(parentKey); + $createListOrMerge(parent, listType); break; - } else { - const nextParent = parent.getParent(); - - if ($isRootOrShadowRoot(nextParent) && !handled.has(parentKey)) { - handled.add(parentKey); - $createListOrMerge(parent, listType); - break; - } - - parent = nextParent; } + + parent = nextParent; } } } } - }); + } } function append(node: ElementNode, nodesToAppend: Array) { @@ -223,65 +228,62 @@ export function mergeLists(list1: ListNode, list2: ListNode): void { * it will remove the whole list, including the ListItemNode. For each ListItemNode in the ListNode, * removeList will also generate new ParagraphNodes in the removed ListNode's place. Any child node * inside a ListItemNode will be appended to the new ParagraphNodes. - * @param editor - The lexical editor. */ -export function removeList(editor: LexicalEditor): void { - editor.update(() => { - const selection = $getSelection(); +export function $removeList(): void { + const selection = $getSelection(); - if ($isRangeSelection(selection)) { - const listNodes = new Set(); - const nodes = selection.getNodes(); - const anchorNode = selection.anchor.getNode(); + if ($isRangeSelection(selection)) { + const listNodes = new Set(); + const nodes = selection.getNodes(); + const anchorNode = selection.anchor.getNode(); - if ($isSelectingEmptyListItem(anchorNode, nodes)) { - listNodes.add($getTopListNode(anchorNode)); - } else { - for (let i = 0; i < nodes.length; i++) { - const node = nodes[i]; + if ($isSelectingEmptyListItem(anchorNode, nodes)) { + listNodes.add($getTopListNode(anchorNode)); + } else { + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; - if ($isLeafNode(node)) { - const listItemNode = $getNearestNodeOfType(node, ListItemNode); + if ($isLeafNode(node)) { + const listItemNode = $getNearestNodeOfType(node, ListItemNode); - if (listItemNode != null) { - listNodes.add($getTopListNode(listItemNode)); - } + if (listItemNode != null) { + listNodes.add($getTopListNode(listItemNode)); } } } + } - for (const listNode of listNodes) { - let insertionPoint: ListNode | ParagraphNode = listNode; - - const listItems = $getAllListItems(listNode); + for (const listNode of listNodes) { + let insertionPoint: ListNode | ParagraphNode = listNode; - for (const listItemNode of listItems) { - const paragraph = $createParagraphNode(); + const listItems = $getAllListItems(listNode); - append(paragraph, listItemNode.getChildren()); + for (const listItemNode of listItems) { + const paragraph = $createParagraphNode(); - insertionPoint.insertAfter(paragraph); - insertionPoint = paragraph; + append(paragraph, listItemNode.getChildren()); - // When the anchor and focus fall on the textNode - // we don't have to change the selection because the textNode will be appended to - // the newly generated paragraph. - // When selection is in empty nested list item, selection is actually on the listItemNode. - // When the corresponding listItemNode is deleted and replaced by the newly generated paragraph - // we should manually set the selection's focus and anchor to the newly generated paragraph. - if (listItemNode.__key === selection.anchor.key) { - selection.anchor.set(paragraph.getKey(), 0, 'element'); - } - if (listItemNode.__key === selection.focus.key) { - selection.focus.set(paragraph.getKey(), 0, 'element'); - } + insertionPoint.insertAfter(paragraph); + insertionPoint = paragraph; - listItemNode.remove(); + // When the anchor and focus fall on the textNode + // we don't have to change the selection because the textNode will be appended to + // the newly generated paragraph. + // When selection is in empty nested list item, selection is actually on the listItemNode. + // When the corresponding listItemNode is deleted and replaced by the newly generated paragraph + // we should manually set the selection's focus and anchor to the newly generated paragraph. + if (listItemNode.__key === selection.anchor.key) { + selection.anchor.set(paragraph.getKey(), 0, 'element'); + } + if (listItemNode.__key === selection.focus.key) { + selection.focus.set(paragraph.getKey(), 0, 'element'); } - listNode.remove(); + + listItemNode.remove(); } + listNode.remove(); } - }); + } } /** diff --git a/packages/lexical-list/src/index.ts b/packages/lexical-list/src/index.ts index 6129fc4be37..d04909343c5 100644 --- a/packages/lexical-list/src/index.ts +++ b/packages/lexical-list/src/index.ts @@ -17,7 +17,11 @@ import { INSERT_PARAGRAPH_COMMAND, } from 'lexical'; -import {$handleListInsertParagraph, insertList, removeList} from './formatList'; +import { + $handleListInsertParagraph, + $insertList, + $removeList, +} from './formatList'; import { $createListItemNode, $isListItemNode, @@ -31,13 +35,13 @@ export { $createListNode, $getListDepth, $handleListInsertParagraph, + $insertList, $isListItemNode, $isListNode, - insertList, + $removeList, ListItemNode, ListNode, ListType, - removeList, SerializedListItemNode, SerializedListNode, }; @@ -59,7 +63,7 @@ export function registerList(editor: LexicalEditor): () => void { editor.registerCommand( INSERT_ORDERED_LIST_COMMAND, () => { - insertList(editor, 'number'); + $insertList('number'); return true; }, COMMAND_PRIORITY_LOW, @@ -67,7 +71,7 @@ export function registerList(editor: LexicalEditor): () => void { editor.registerCommand( INSERT_UNORDERED_LIST_COMMAND, () => { - insertList(editor, 'bullet'); + $insertList('bullet'); return true; }, COMMAND_PRIORITY_LOW, @@ -75,7 +79,7 @@ export function registerList(editor: LexicalEditor): () => void { editor.registerCommand( REMOVE_LIST_COMMAND, () => { - removeList(editor); + $removeList(); return true; }, COMMAND_PRIORITY_LOW, @@ -96,3 +100,32 @@ export function registerList(editor: LexicalEditor): () => void { ); return removeListener; } + +/** + * @deprecated use {@link $insertList} from an update or command listener. + * + * Inserts a new ListNode. If the selection's anchor node is an empty ListItemNode and is a child of + * the root/shadow root, it will replace the ListItemNode with a ListNode and the old ListItemNode. + * Otherwise it will replace its parent with a new ListNode and re-insert the ListItemNode and any previous children. + * If the selection's anchor node is not an empty ListItemNode, it will add a new ListNode or merge an existing ListNode, + * unless the the node is a leaf node, in which case it will attempt to find a ListNode up the branch and replace it with + * a new ListNode, or create a new ListNode at the nearest root/shadow root. + * @param editor - The lexical editor. + * @param listType - The type of list, "number" | "bullet" | "check". + */ +export function insertList(editor: LexicalEditor, listType: ListType): void { + editor.update(() => $insertList(listType)); +} + +/** + * @deprecated use {@link $removeList} from an update or command listener. + * + * Searches for the nearest ancestral ListNode and removes it. If selection is an empty ListItemNode + * it will remove the whole list, including the ListItemNode. For each ListItemNode in the ListNode, + * removeList will also generate new ParagraphNodes in the removed ListNode's place. Any child node + * inside a ListItemNode will be appended to the new ParagraphNodes. + * @param editor - The lexical editor. + */ +export function removeList(editor: LexicalEditor): void { + editor.update(() => $removeList()); +} diff --git a/packages/lexical-mark/__tests__/unit/LexicalMarkNode.test.ts b/packages/lexical-mark/__tests__/unit/LexicalMarkNode.test.ts new file mode 100644 index 00000000000..5f9061e32df --- /dev/null +++ b/packages/lexical-mark/__tests__/unit/LexicalMarkNode.test.ts @@ -0,0 +1,185 @@ +/** + * 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 {$wrapSelectionInMarkNode, MarkNode} from '@lexical/mark'; +import { + $createParagraphNode, + $createRangeSelection, + $createTextNode, + $getRoot, + ParagraphNode, +} from 'lexical'; +import { + $createTestDecoratorNode, + $createTestElementNode, + $createTestInlineElementNode, + initializeUnitTest, +} from 'lexical/src/__tests__/utils'; + +describe('LexicalMarkNode tests', () => { + initializeUnitTest((testEnv) => { + describe('$wrapSelectionInMarkNode', () => { + beforeEach(() => { + testEnv.editor.update( + () => { + $getRoot().clear().append($createParagraphNode()); + }, + {discrete: true}, + ); + }); + + test('wraps a whole text node', () => { + const {editor} = testEnv; + + editor.update(() => { + const textNode = $createTextNode('marked'); + const paragraphNode = + $getRoot().getFirstChildOrThrow(); + paragraphNode.append(textNode); + const selection = $createRangeSelection(); + selection.anchor.set(textNode.getKey(), 0, 'text'); + selection.focus.set( + textNode.getKey(), + textNode.getTextContent().length, + 'text', + ); + $wrapSelectionInMarkNode(selection, false, 'my-id'); + + expect(paragraphNode.getChildren()).toHaveLength(1); + const markNode = paragraphNode.getFirstChildOrThrow(); + expect(markNode.getType()).toEqual('mark'); + expect(markNode.getIDs()).toEqual(['my-id']); + expect(markNode.getChildren()).toHaveLength(1); + expect(markNode.getFirstChildOrThrow().getKey()).toEqual( + textNode.getKey(), + ); + expect(markNode.getFirstChildOrThrow().getTextContent()).toEqual( + 'marked', + ); + }); + }); + + test('splits a text node if the selection is not at the start/end', () => { + const {editor} = testEnv; + + editor.update(() => { + const textNode = $createTextNode('unmarked marked unmarked'); + const paragraphNode = + $getRoot().getFirstChildOrThrow(); + paragraphNode.append(textNode); + const selection = $createRangeSelection(); + selection.anchor.set(textNode.getKey(), 'unmarked '.length, 'text'); + selection.focus.set( + textNode.getKey(), + 'unmarked marked'.length, + 'text', + ); + $wrapSelectionInMarkNode(selection, false, 'my-id'); + + expect(paragraphNode.getTextContent()).toEqual( + 'unmarked marked unmarked', + ); + expect(paragraphNode.getChildren().map((c) => c.getType())).toEqual([ + 'text', + 'mark', + 'text', + ]); + expect( + paragraphNode.getChildren().map((c) => c.getTextContent()), + ).toEqual(['unmarked ', 'marked', ' unmarked']); + }); + }); + + test('includes inline decorator nodes', () => { + const {editor} = testEnv; + + editor.update(() => { + const decoratorNode = $createTestDecoratorNode(); + const textNode = $createTextNode('more text'); + const paragraphNode = + $getRoot().getFirstChildOrThrow(); + paragraphNode.append(decoratorNode, textNode); + const selection = $createRangeSelection(); + selection.anchor.set(paragraphNode.getKey(), 0, 'text'); + selection.focus.set( + paragraphNode.getKey(), + paragraphNode.getTextContent().length, + 'text', + ); + $wrapSelectionInMarkNode(selection, false, 'my-id'); + + expect(paragraphNode.getChildren()).toHaveLength(1); + const markNode = paragraphNode.getFirstChildOrThrow(); + expect(markNode.getType()).toEqual('mark'); + expect(markNode.getChildren().map((c) => c.getKey())).toEqual([ + decoratorNode.getKey(), + textNode.getKey(), + ]); + }); + }); + + test('includes inline element nodes', () => { + const {editor} = testEnv; + + editor.update(() => { + const elementNode = $createTestInlineElementNode(); + const textNode = $createTextNode('more text'); + const paragraphNode = + $getRoot().getFirstChildOrThrow(); + paragraphNode.append(elementNode, textNode); + const selection = $createRangeSelection(); + selection.anchor.set(paragraphNode.getKey(), 0, 'text'); + selection.focus.set( + paragraphNode.getKey(), + paragraphNode.getTextContent().length, + 'text', + ); + $wrapSelectionInMarkNode(selection, false, 'my-id'); + + expect(paragraphNode.getChildren()).toHaveLength(1); + const markNode = paragraphNode.getFirstChildOrThrow(); + expect(markNode.getType()).toEqual('mark'); + expect(markNode.getChildren().map((c) => c.getKey())).toEqual([ + elementNode.getKey(), + textNode.getKey(), + ]); + }); + }); + + test('does not include block element nodes', () => { + const {editor} = testEnv; + + editor.update(() => { + const elementNode = $createTestElementNode(); + const textNode = $createTextNode('more text'); + const paragraphNode = + $getRoot().getFirstChildOrThrow(); + paragraphNode.append(elementNode, textNode); + const selection = $createRangeSelection(); + selection.anchor.set(paragraphNode.getKey(), 0, 'text'); + selection.focus.set( + paragraphNode.getKey(), + paragraphNode.getTextContent().length, + 'text', + ); + $wrapSelectionInMarkNode(selection, false, 'my-id'); + + expect(paragraphNode.getChildren()).toHaveLength(2); + expect(paragraphNode.getChildAtIndex(0)!.getKey()).toEqual( + elementNode.getKey(), + ); + + // the text part of the selection should still be marked + const markNode = paragraphNode.getChildAtIndex(1) as MarkNode; + expect(markNode.getType()).toEqual('mark'); + expect(markNode.getChildren()).toHaveLength(1); + expect(markNode.getTextContent()).toEqual('more text'); + }); + }); + }); + }); +}); diff --git a/packages/lexical-mark/package.json b/packages/lexical-mark/package.json index 25c4a02d3d7..981cc710386 100644 --- a/packages/lexical-mark/package.json +++ b/packages/lexical-mark/package.json @@ -8,12 +8,12 @@ "mark" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalMark.js", "types": "index.d.ts", "dependencies": { - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" }, "repository": { "type": "git", diff --git a/packages/lexical-mark/src/MarkNode.ts b/packages/lexical-mark/src/MarkNode.ts index 2bc9ab140f0..a33097723dd 100644 --- a/packages/lexical-mark/src/MarkNode.ts +++ b/packages/lexical-mark/src/MarkNode.ts @@ -10,6 +10,7 @@ import type { BaseSelection, EditorConfig, LexicalNode, + LexicalUpdateJSON, NodeKey, RangeSelection, SerializedElementNode, @@ -29,6 +30,8 @@ export type SerializedMarkNode = Spread< SerializedElementNode >; +const NO_IDS: readonly string[] = []; + /** @noInheritDoc */ export class MarkNode extends ElementNode { /** @internal */ @@ -47,25 +50,23 @@ export class MarkNode extends ElementNode { } static importJSON(serializedNode: SerializedMarkNode): MarkNode { - const node = $createMarkNode(serializedNode.ids); - node.setFormat(serializedNode.format); - node.setIndent(serializedNode.indent); - node.setDirection(serializedNode.direction); - return node; + return $createMarkNode().updateFromJSON(serializedNode); + } + + updateFromJSON(serializedNode: LexicalUpdateJSON): this { + return super.updateFromJSON(serializedNode).setIDs(serializedNode.ids); } exportJSON(): SerializedMarkNode { return { ...super.exportJSON(), - ids: Array.from(this.getIDs()), - type: 'mark', - version: 1, + ids: this.getIDs(), }; } - constructor(ids: readonly string[], key?: NodeKey) { + constructor(ids: readonly string[] = NO_IDS, key?: NodeKey) { super(key); - this.__ids = ids || []; + this.__ids = ids; } createDOM(config: EditorConfig): HTMLElement { @@ -101,47 +102,33 @@ export class MarkNode extends ElementNode { } hasID(id: string): boolean { - const ids = this.getIDs(); - for (let i = 0; i < ids.length; i++) { - if (id === ids[i]) { - return true; - } - } - return false; + return this.getIDs().includes(id); } getIDs(): Array { - const self = this.getLatest(); - return $isMarkNode(self) ? Array.from(self.__ids) : []; + return Array.from(this.getLatest().__ids); } - addID(id: string): void { + setIDs(ids: readonly string[]): this { const self = this.getWritable(); - if ($isMarkNode(self)) { - const ids = Array.from(self.__ids); - self.__ids = ids; - for (let i = 0; i < ids.length; i++) { - // If we already have it, don't add again - if (id === ids[i]) { - return; - } - } - ids.push(id); - } + self.__ids = ids; + return self; } - deleteID(id: string): void { + addID(id: string): this { const self = this.getWritable(); - if ($isMarkNode(self)) { - const ids = Array.from(self.__ids); - self.__ids = ids; - for (let i = 0; i < ids.length; i++) { - if (id === ids[i]) { - ids.splice(i, 1); - return; - } - } + return self.__ids.includes(id) ? self : self.setIDs([...self.__ids, id]); + } + + deleteID(id: string): this { + const self = this.getWritable(); + const idx = self.__ids.indexOf(id); + if (idx === -1) { + return self; } + const ids = Array.from(self.__ids); + ids.splice(idx, 1); + return self.setIDs(ids); } insertNewAfter( @@ -197,7 +184,7 @@ export class MarkNode extends ElementNode { } } -export function $createMarkNode(ids: readonly string[]): MarkNode { +export function $createMarkNode(ids: readonly string[] = NO_IDS): MarkNode { return $applyNodeReplacement(new MarkNode(ids)); } diff --git a/packages/lexical-mark/src/index.ts b/packages/lexical-mark/src/index.ts index 5aa46e82ccc..d5fa9e27e43 100644 --- a/packages/lexical-mark/src/index.ts +++ b/packages/lexical-mark/src/index.ts @@ -9,7 +9,7 @@ import type {SerializedMarkNode} from './MarkNode'; import type {LexicalNode, RangeSelection, TextNode} from 'lexical'; -import {$isElementNode, $isTextNode} from 'lexical'; +import {$isDecoratorNode, $isElementNode, $isTextNode} from 'lexical'; import {$createMarkNode, $isMarkNode, MarkNode} from './MarkNode'; @@ -84,9 +84,12 @@ export function $wrapSelectionInMarkNode( // codebase. continue; - } else if ($isElementNode(node) && node.isInline()) { - // Case 3: inline element nodes can be added in their entirety to the new - // mark + } else if ( + ($isElementNode(node) || $isDecoratorNode(node)) && + node.isInline() + ) { + // Case 3: inline element/decorator nodes can be added in their entirety + // to the new mark targetNode = node; } diff --git a/packages/lexical-markdown/package.json b/packages/lexical-markdown/package.json index 3876ae9137d..0667a8f5713 100644 --- a/packages/lexical-markdown/package.json +++ b/packages/lexical-markdown/package.json @@ -8,17 +8,17 @@ "markdown" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalMarkdown.js", "types": "index.d.ts", "dependencies": { - "@lexical/code": "0.21.0", - "@lexical/link": "0.21.0", - "@lexical/list": "0.21.0", - "@lexical/rich-text": "0.21.0", - "@lexical/text": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/code": "0.23.1", + "@lexical/link": "0.23.1", + "@lexical/list": "0.23.1", + "@lexical/rich-text": "0.23.1", + "@lexical/text": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" }, "repository": { "type": "git", diff --git a/packages/lexical-offset/package.json b/packages/lexical-offset/package.json index 9bdee1780be..fa501ea40f6 100644 --- a/packages/lexical-offset/package.json +++ b/packages/lexical-offset/package.json @@ -8,7 +8,7 @@ "offset" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalOffset.js", "types": "index.d.ts", "repository": { @@ -36,6 +36,6 @@ } }, "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } } diff --git a/packages/lexical-overflow/package.json b/packages/lexical-overflow/package.json index e61f16ccb92..60ee04a4c3e 100644 --- a/packages/lexical-overflow/package.json +++ b/packages/lexical-overflow/package.json @@ -8,7 +8,7 @@ "overflow" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalOverflow.js", "types": "index.d.ts", "repository": { @@ -36,6 +36,6 @@ } }, "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } } diff --git a/packages/lexical-overflow/src/index.ts b/packages/lexical-overflow/src/index.ts index 60e77d21ecb..c6284e3fd95 100644 --- a/packages/lexical-overflow/src/index.ts +++ b/packages/lexical-overflow/src/index.ts @@ -9,7 +9,6 @@ import type { EditorConfig, LexicalNode, - NodeKey, RangeSelection, SerializedElementNode, } from 'lexical'; @@ -30,25 +29,13 @@ export class OverflowNode extends ElementNode { } static importJSON(serializedNode: SerializedOverflowNode): OverflowNode { - return $createOverflowNode(); + return $createOverflowNode().updateFromJSON(serializedNode); } static importDOM(): null { return null; } - constructor(key?: NodeKey) { - super(key); - this.__type = 'overflow'; - } - - exportJSON(): SerializedElementNode { - return { - ...super.exportJSON(), - type: 'overflow', - }; - } - createDOM(config: EditorConfig): HTMLElement { const div = document.createElement('span'); const className = config.theme.characterLimit; diff --git a/packages/lexical-plain-text/package.json b/packages/lexical-plain-text/package.json index 4d63568b927..bb578ed8044 100644 --- a/packages/lexical-plain-text/package.json +++ b/packages/lexical-plain-text/package.json @@ -7,7 +7,7 @@ "plain-text" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalPlainText.js", "types": "index.d.ts", "repository": { @@ -35,9 +35,9 @@ } }, "dependencies": { - "@lexical/clipboard": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/clipboard": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } } diff --git a/packages/lexical-playground/__tests__/e2e/Collaboration.spec.mjs b/packages/lexical-playground/__tests__/e2e/Collaboration.spec.mjs index 296d9ac21a0..90d4edeefca 100644 --- a/packages/lexical-playground/__tests__/e2e/Collaboration.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Collaboration.spec.mjs @@ -413,4 +413,256 @@ test.describe('Collaboration', () => { `, ); }); + + test('Undo/redo where text node is split by formatting change', async ({ + isRichText, + page, + isCollab, + browserName, + }) => { + test.skip(!isCollab); + + // Left collaborator types two words, sets the second one to bold. + await focusEditor(page); + await page.keyboard.type('normal bold'); + + await sleep(1050); + await selectCharacters(page, 'left', 'bold'.length); + await toggleBold(page); + + await assertHTML( + page, + html` +

+ normal + + bold + +

+ `, + ); + + // Right collaborator types in the middle of the bold word. + await page + .frameLocator('iframe[name="right"]') + .locator('[data-lexical-editor="true"]') + .focus(); + await page.keyboard.press('ArrowDown', {delay: 50}); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.type('BOLD'); + + await assertHTML( + page, + html` +

+ normal + + boBOLDld + +

+ `, + ); + + // Left collaborator undoes their bold text. + await page.frameLocator('iframe[name="left"]').getByLabel('Undo').click(); + + // The undo causes the text to be appended to the original string, like in the above test. + await assertHTML( + page, + html` +

+ normal boldBOLD +

+ `, + ); + + // Left collaborator redoes the bold text. + await page.frameLocator('iframe[name="left"]').getByLabel('Redo').click(); + + // The text should be back as it was prior to the undo. + await assertHTML( + page, + html` +

+ normal + + boBOLDld + +

+ `, + ); + + // Collaboration should still work. + await page + .frameLocator('iframe[name="right"]') + .locator('[data-lexical-editor="true"]') + .focus(); + await page.keyboard.press('ArrowDown', {delay: 50}); + await page.keyboard.type(' text'); + + await assertHTML( + page, + html` +

+ normal + + boBOLDld text + +

+ `, + ); + }); + + test('Undo/redo where text node is split by inline element node', async ({ + isRichText, + page, + isCollab, + browserName, + }) => { + test.skip(!isCollab); + + // Left collaborator types some text, then splits the text nodes with an element node. + await focusEditor(page); + await page.keyboard.type('Check out the website!'); + + await sleep(1050); + await page.keyboard.press('ArrowLeft'); + await selectCharacters(page, 'left', 'website'.length); + await page + .frameLocator('iframe[name="left"]') + .getByLabel('Insert link') + .first() + .click(); + + await assertHTML( + page, + html` +

+ Check out the + + website + + ! +

+ `, + ); + + // Right collaborator adds some text. + await page + .frameLocator('iframe[name="right"]') + .locator('[data-lexical-editor="true"]') + .focus(); + await page.keyboard.press('ArrowDown', {delay: 50}); + await page.keyboard.press('ArrowLeft'); + await page.keyboard.type(' now'); + + await assertHTML( + page, + html` +

+ Check out the + + website + + now! +

+ `, + ); + + // Left collaborator undoes the link. + await page.frameLocator('iframe[name="left"]').getByLabel('Undo').click(); + + // The undo causes the text to be appended to the original string, like in the above test. + await assertHTML( + page, + html` +

+ Check out the website! now +

+ `, + ); + + // Left collaborator redoes the link. + await page.frameLocator('iframe[name="left"]').getByLabel('Redo').click(); + + // The text should be back as it was prior to the undo. + await assertHTML( + page, + html` +

+ Check out the + + website + + now! +

+ `, + ); + + // Collaboration should still work. + await page + .frameLocator('iframe[name="right"]') + .locator('[data-lexical-editor="true"]') + .focus(); + await page.keyboard.press('ArrowDown', {delay: 50}); + await page.keyboard.type(' Check it out.'); + + await assertHTML( + page, + html` +

+ Check out the + + website + + now! Check it out. +

+ `, + ); + }); }); diff --git a/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/TablesHTMLCopyAndPaste.spec.mjs b/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/TablesHTMLCopyAndPaste.spec.mjs index c0ef411ca34..bf61c484ccc 100644 --- a/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/TablesHTMLCopyAndPaste.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/CopyAndPaste/html/TablesHTMLCopyAndPaste.spec.mjs @@ -818,4 +818,58 @@ test.describe('HTML Tables CopyAndPaste', () => { `, ); }); + + test('Copy + paste table with empty row', async ({ + page, + isPlainText, + isCollab, + }) => { + test.skip(isPlainText); + + await focusEditor(page); + + const clipboard = { + 'text/html': html` + + + + +
1
2
+ `, + }; + + await pasteFromClipboard(page, clipboard); + + await assertHTML( + page, + html` + + + + + + + + + + + + + +
+

+ 1 +

+
+

+
+

+
+

+ 2 +

+
+ `, + ); + }); }); diff --git a/packages/lexical-playground/__tests__/e2e/Headings/HeadingsEnterAtEnd.spec.mjs b/packages/lexical-playground/__tests__/e2e/Headings/HeadingsEnterAtEnd.spec.mjs index c5539928406..5a15096e412 100644 --- a/packages/lexical-playground/__tests__/e2e/Headings/HeadingsEnterAtEnd.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Headings/HeadingsEnterAtEnd.spec.mjs @@ -6,11 +6,6 @@ * */ -import { - moveRight, - moveToEditorBeginning, - STANDARD_KEYPRESS_DELAY_MS, -} from '../../keyboardShortcuts/index.mjs'; import { assertHTML, click, @@ -20,10 +15,10 @@ import { test, } from '../../utils/index.mjs'; -test(`Headings - stays as a heading when you press enter in the middle of a heading`, async ({ +test('Headings - changes to a paragraph when you press enter at the end of a heading', async ({ page, - isCollab, isPlainText, + isCollab, }) => { test.skip(isPlainText); await initialize({isCollab, page}); @@ -45,10 +40,6 @@ test(`Headings - stays as a heading when you press enter in the middle of a head `, ); - await moveToEditorBeginning(page); - - await moveRight(page, 5, STANDARD_KEYPRESS_DELAY_MS); - await page.keyboard.press('Enter'); await assertHTML( @@ -57,13 +48,9 @@ test(`Headings - stays as a heading when you press enter in the middle of a head

- Welco -

-

- me to the playground + Welcome to the playground

+


`, ); }); diff --git a/packages/lexical-playground/__tests__/e2e/Headings/HeadingsEnterInMiddle.spec.mjs b/packages/lexical-playground/__tests__/e2e/Headings/HeadingsEnterInMiddle.spec.mjs index 5a15096e412..c5539928406 100644 --- a/packages/lexical-playground/__tests__/e2e/Headings/HeadingsEnterInMiddle.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Headings/HeadingsEnterInMiddle.spec.mjs @@ -6,6 +6,11 @@ * */ +import { + moveRight, + moveToEditorBeginning, + STANDARD_KEYPRESS_DELAY_MS, +} from '../../keyboardShortcuts/index.mjs'; import { assertHTML, click, @@ -15,10 +20,10 @@ import { test, } from '../../utils/index.mjs'; -test('Headings - changes to a paragraph when you press enter at the end of a heading', async ({ +test(`Headings - stays as a heading when you press enter in the middle of a heading`, async ({ page, - isPlainText, isCollab, + isPlainText, }) => { test.skip(isPlainText); await initialize({isCollab, page}); @@ -40,6 +45,10 @@ test('Headings - changes to a paragraph when you press enter at the end of a hea `, ); + await moveToEditorBeginning(page); + + await moveRight(page, 5, STANDARD_KEYPRESS_DELAY_MS); + await page.keyboard.press('Enter'); await assertHTML( @@ -48,9 +57,13 @@ test('Headings - changes to a paragraph when you press enter at the end of a hea

- Welcome to the playground + Welco +

+

+ me to the playground

-


`, ); }); diff --git a/packages/lexical-playground/__tests__/e2e/Indentation.spec.mjs b/packages/lexical-playground/__tests__/e2e/Indentation.spec.mjs index aee91bc356b..4811ea087bf 100644 --- a/packages/lexical-playground/__tests__/e2e/Indentation.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Indentation.spec.mjs @@ -14,9 +14,23 @@ import { html, initialize, insertTable, + selectFromAlignDropdown, test, } from '../utils/index.mjs'; +async function toggleBulletList(page) { + await click(page, '.block-controls'); + await click(page, '.dropdown .icon.bullet-list'); +} + +async function clickIndentButton(page, times = 1) { + for (let i = 0; i < times; i++) { + await selectFromAlignDropdown(page, '.indent'); + } +} + +const MAX_INDENT = 7; + test.describe('Identation', () => { test.beforeEach(({isCollab, page}) => initialize({isCollab, page, tableHorizontalScroll: false}), @@ -474,4 +488,117 @@ test.describe('Identation', () => { `, ); }); + + test(`Can only indent paragraph until the max depth`, async ({ + page, + isPlainText, + }) => { + test.skip(isPlainText); + await focusEditor(page); + await clickIndentButton(page, MAX_INDENT); + + const expectedHTML = + '


'; + + await assertHTML(page, expectedHTML); + await clickIndentButton(page, MAX_INDENT); + + // should stay the same + await assertHTML(page, expectedHTML); + }); + + test(`Can only indent until the max depth when list is empty`, async ({ + page, + isPlainText, + }) => { + test.skip(isPlainText); + await focusEditor(page); + await toggleBulletList(page); + + await clickIndentButton(page, MAX_INDENT); + + await assertHTML( + page, + '

', + ); + + await clickIndentButton(page); + + // should stay the same + await assertHTML( + page, + '

', + ); + }); + + test(`Can only indent until the max depth when list has content`, async ({ + page, + isPlainText, + }) => { + test.skip(isPlainText); + await focusEditor(page); + await toggleBulletList(page); + await page.keyboard.type('World'); + + await clickIndentButton(page, MAX_INDENT); + + await assertHTML( + page, + '
              • World
', + ); + + await clickIndentButton(page); + + // should stay the same + await assertHTML( + page, + '
              • World
', + ); + }); + + test(`Can only indent until the max depth a list with nested lists`, async ({ + page, + isPlainText, + }) => { + test.skip(isPlainText); + + await focusEditor(page); + await toggleBulletList(page); + await page.keyboard.type('Hello'); + await page.keyboard.press('Enter'); + await page.keyboard.type('from'); + await clickIndentButton(page); + await page.keyboard.press('Enter'); + await page.keyboard.type('the'); + await clickIndentButton(page); + await page.keyboard.press('Enter'); + await page.keyboard.type('other'); + await clickIndentButton(page); + await page.keyboard.press('Enter'); + await page.keyboard.type('side'); + await clickIndentButton(page); + await page.keyboard.press('Enter'); + + await assertHTML( + page, + '
  • Hello
    • from
      • the
        • other
          • side

', + ); + + await selectAll(page); + + await clickIndentButton(page, 3); + + await assertHTML( + page, + '
      • Hello
        • from
          • the
            • other
              • side

', + ); + + await clickIndentButton(page); + + // should stay the same + await assertHTML( + page, + '
      • Hello
        • from
          • the
            • other
              • side

', + ); + }); }); diff --git a/packages/lexical-playground/__tests__/e2e/Links.spec.mjs b/packages/lexical-playground/__tests__/e2e/Links.spec.mjs index 33d4d5ea89d..ece9a617486 100644 --- a/packages/lexical-playground/__tests__/e2e/Links.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Links.spec.mjs @@ -524,6 +524,68 @@ test.describe.parallel('Links', () => { }, ); + test( + `Can backspace across a link and it deletes text, not the whole link`, + { + tag: '@flaky', + }, + async ({page}) => { + await focusEditor(page); + await page.keyboard.type(' abc def '); + await moveLeft(page, 5); + await selectCharacters(page, 'left', 3); + + // link + await click(page, '.link'); + await click(page, '.link-confirm'); + + await assertHTML( + page, + html` +

+ + + abc + + def +

+ `, + ); + + await moveRight(page, 4); + + await page.keyboard.press('Backspace'); + await page.keyboard.press('Backspace'); + await page.keyboard.press('Backspace'); + await page.keyboard.press('Backspace'); + + await assertHTML( + page, + html` +

+ + + ab + + f +

+ `, + ); + }, + ); + test(`Can create a link then replace it with plain text`, async ({page}) => { await focusEditor(page); await page.keyboard.type(' abc '); diff --git a/packages/lexical-playground/__tests__/e2e/List.spec.mjs b/packages/lexical-playground/__tests__/e2e/List.spec.mjs index df81baee7a2..d4c1bc250e8 100644 --- a/packages/lexical-playground/__tests__/e2e/List.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/List.spec.mjs @@ -9,6 +9,7 @@ import {expect} from '@playwright/test'; import { + indent, moveLeft, moveRight, moveToEditorBeginning, @@ -1894,11 +1895,55 @@ test.describe.parallel('Nested List', () => { ); await page.pause(); await assertSelection(page, { - anchorOffset: 1, - anchorPath: [1, 0], - focusOffset: 1, - focusPath: [1, 0], + anchorOffset: 0, + anchorPath: [2], + focusOffset: 0, + focusPath: [2], }); }, ); + test('new list item should preserve format from previous list item even after new list item is indented', async ({ + page, + }) => { + await focusEditor(page); + await toggleBulletList(page); + await toggleBold(page); + await page.keyboard.type('MLH Fellowship'); + await page.keyboard.press('Enter'); + await indent(page, 1); + await page.keyboard.type('Fall 2024'); + await assertHTML( + page, + html` +
    +
  • + + MLH Fellowship + +
  • +
  • +
      +
    • + + Fall 2024 + +
    • +
    +
  • +
+ `, + ); + }); }); diff --git a/packages/lexical-playground/__tests__/e2e/ListMaxIndentLevel.spec.mjs b/packages/lexical-playground/__tests__/e2e/ListMaxIndentLevel.spec.mjs deleted file mode 100644 index fe37a84b209..00000000000 --- a/packages/lexical-playground/__tests__/e2e/ListMaxIndentLevel.spec.mjs +++ /dev/null @@ -1,128 +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 {selectAll} from '../keyboardShortcuts/index.mjs'; -import { - assertHTML, - click, - focusEditor, - initialize, - selectFromAlignDropdown, - test, -} from '../utils/index.mjs'; - -async function toggleBulletList(page) { - await click(page, '.block-controls'); - await click(page, '.dropdown .icon.bullet-list'); -} - -async function clickIndentButton(page, times = 1) { - for (let i = 0; i < times; i++) { - await selectFromAlignDropdown(page, '.indent'); - } -} - -const MAX_INDENT_LEVEL = 6; - -test.describe('Nested List', () => { - test.beforeEach(({isCollab, page}) => initialize({isCollab, page})); - test(`Can only indent until the max depth when list is empty`, async ({ - page, - isPlainText, - }) => { - test.skip(isPlainText); - await focusEditor(page); - await toggleBulletList(page); - - await clickIndentButton(page, MAX_INDENT_LEVEL); - - await assertHTML( - page, - '

', - ); - - await clickIndentButton(page, MAX_INDENT_LEVEL); - - // should stay the same - await assertHTML( - page, - '

', - ); - }); - - test(`Can only indent until the max depth when list has content`, async ({ - page, - isPlainText, - }) => { - test.skip(isPlainText); - await focusEditor(page); - await toggleBulletList(page); - await page.keyboard.type('World'); - - await clickIndentButton(page, MAX_INDENT_LEVEL); - - await assertHTML( - page, - '
              • World
', - ); - - await clickIndentButton(page, MAX_INDENT_LEVEL); - - // should stay the same - await assertHTML( - page, - '
              • World
', - ); - }); - - test(`Can only indent until the max depth a list with nested lists`, async ({ - page, - isPlainText, - }) => { - test.skip(isPlainText); - - await focusEditor(page); - await toggleBulletList(page); - await page.keyboard.type('Hello'); - await page.keyboard.press('Enter'); - await page.keyboard.type('from'); - await clickIndentButton(page); - await page.keyboard.press('Enter'); - await page.keyboard.type('the'); - await clickIndentButton(page); - await page.keyboard.press('Enter'); - await page.keyboard.type('other'); - await clickIndentButton(page); - await page.keyboard.press('Enter'); - await page.keyboard.type('side'); - await clickIndentButton(page); - await page.keyboard.press('Enter'); - - await assertHTML( - page, - '
  • Hello
    • from
      • the
        • other
          • side

', - ); - - await selectAll(page); - - await clickIndentButton(page, 3); - - await assertHTML( - page, - '
      • Hello
        • from
          • the
            • other
              • side

', - ); - - await clickIndentButton(page, MAX_INDENT_LEVEL); - - // should stay the same - await assertHTML( - page, - '
      • Hello
        • from
          • the
            • other
              • side

', - ); - }); -}); diff --git a/packages/lexical-playground/__tests__/e2e/Selection.spec.mjs b/packages/lexical-playground/__tests__/e2e/Selection.spec.mjs index 71bba6fa5da..38aac924f35 100644 --- a/packages/lexical-playground/__tests__/e2e/Selection.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Selection.spec.mjs @@ -578,6 +578,53 @@ test.describe.parallel('Selection', () => { ); }); + test('Can adjust tripple click selection with', async ({ + page, + isPlainText, + isCollab, + }) => { + test.skip(isPlainText || isCollab); + + await pasteFromClipboard(page, { + 'text/html': `

Helloworld

!

`, + }); + + await page + .locator('div[contenteditable="true"] > p') + .first() + .click({clickCount: 3}); + + await pressToggleBold(page); + + await assertHTML( + page, + html` +

+ + + Hello + + + + world + +

+

+ ! +

+ `, + ); + }); + test('Select all from Node selection #4658', async ({page, isPlainText}) => { // TODO selectAll is bad for Linux #4665 test.skip(isPlainText || IS_LINUX); diff --git a/packages/lexical-playground/__tests__/regression/6974-delete-character-backward.spec.mjs b/packages/lexical-playground/__tests__/regression/6974-delete-character-backward.spec.mjs new file mode 100644 index 00000000000..703596c8bb1 --- /dev/null +++ b/packages/lexical-playground/__tests__/regression/6974-delete-character-backward.spec.mjs @@ -0,0 +1,88 @@ +/** + * 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 { + deleteBackward, + moveToLineBeginning, +} from '../keyboardShortcuts/index.mjs'; +import { + assertHTML, + focusEditor, + html, + initialize, + test, +} from '../utils/index.mjs'; + +test.describe('Regression tests for #6974', () => { + test.beforeEach(({isPlainText, isCollab, page}) => + initialize({isCollab, isPlainText, page}), + ); + + test(`deleteCharacter merges children from adjacent blocks even if the previous leaf is an inline decorator`, async ({ + page, + isCollab, + isPlainText, + }) => { + test.skip(isCollab || isPlainText); + await focusEditor(page); + const testEquation = '$x$'; + const testString = 'test'; + await page.keyboard.type(testEquation); + await page.keyboard.press('Enter'); + await page.keyboard.type(testString); + const beforeHtml = html` +

+ + + + + + + + + +
+

+

test

+ `; + await assertHTML(page, beforeHtml, beforeHtml, { + ignoreClasses: true, + ignoreInlineStyles: true, + }); + await moveToLineBeginning(page); + await deleteBackward(page); + const afterHtml = html` +

+ + + + + + + + + + test +

+ `; + await assertHTML(page, afterHtml, afterHtml, { + ignoreClasses: true, + ignoreInlineStyles: true, + }); + }); +}); diff --git a/packages/lexical-playground/package.json b/packages/lexical-playground/package.json index 5a2751577cf..525e78ab41b 100644 --- a/packages/lexical-playground/package.json +++ b/packages/lexical-playground/package.json @@ -1,6 +1,6 @@ { "name": "lexical-playground", - "version": "0.21.0", + "version": "0.23.1", "private": true, "type": "module", "scripts": { @@ -12,22 +12,22 @@ }, "dependencies": { "@excalidraw/excalidraw": "^0.17.0", - "@lexical/clipboard": "0.21.0", - "@lexical/code": "0.21.0", - "@lexical/file": "0.21.0", - "@lexical/hashtag": "0.21.0", - "@lexical/link": "0.21.0", - "@lexical/list": "0.21.0", - "@lexical/mark": "0.21.0", - "@lexical/overflow": "0.21.0", - "@lexical/plain-text": "0.21.0", - "@lexical/react": "0.21.0", - "@lexical/rich-text": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/table": "0.21.0", - "@lexical/utils": "0.21.0", + "@lexical/clipboard": "0.23.1", + "@lexical/code": "0.23.1", + "@lexical/file": "0.23.1", + "@lexical/hashtag": "0.23.1", + "@lexical/link": "0.23.1", + "@lexical/list": "0.23.1", + "@lexical/mark": "0.23.1", + "@lexical/overflow": "0.23.1", + "@lexical/plain-text": "0.23.1", + "@lexical/react": "0.23.1", + "@lexical/rich-text": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/table": "0.23.1", + "@lexical/utils": "0.23.1", "katex": "^0.16.10", - "lexical": "0.21.0", + "lexical": "0.23.1", "lodash-es": "^4.17.21", "prettier": "^3.4.2", "react": "^18.2.0", diff --git a/packages/lexical-playground/src/App.tsx b/packages/lexical-playground/src/App.tsx index aa4852cf87e..d667ed12c32 100644 --- a/packages/lexical-playground/src/App.tsx +++ b/packages/lexical-playground/src/App.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {$createLinkNode} from '@lexical/link'; import {$createListItemNode, $createListNode} from '@lexical/list'; import {LexicalComposer} from '@lexical/react/LexicalComposer'; diff --git a/packages/lexical-playground/src/Editor.tsx b/packages/lexical-playground/src/Editor.tsx index 1b752ced18c..f5fb3421915 100644 --- a/packages/lexical-playground/src/Editor.tsx +++ b/packages/lexical-playground/src/Editor.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {AutoFocusPlugin} from '@lexical/react/LexicalAutoFocusPlugin'; import {CharacterLimitPlugin} from '@lexical/react/LexicalCharacterLimitPlugin'; import {CheckListPlugin} from '@lexical/react/LexicalCheckListPlugin'; @@ -55,7 +57,6 @@ import InlineImagePlugin from './plugins/InlineImagePlugin'; import KeywordsPlugin from './plugins/KeywordsPlugin'; import {LayoutPlugin} from './plugins/LayoutPlugin/LayoutPlugin'; import LinkPlugin from './plugins/LinkPlugin'; -import ListMaxIndentLevelPlugin from './plugins/ListMaxIndentLevelPlugin'; import MarkdownShortcutPlugin from './plugins/MarkdownShortcutPlugin'; import {MaxLengthPlugin} from './plugins/MaxLengthPlugin'; import MentionsPlugin from './plugins/MentionsPlugin'; @@ -200,7 +201,6 @@ export default function Editor(): JSX.Element { - - + diff --git a/packages/lexical-playground/src/Settings.tsx b/packages/lexical-playground/src/Settings.tsx index cc787b5ba56..138fb33e647 100644 --- a/packages/lexical-playground/src/Settings.tsx +++ b/packages/lexical-playground/src/Settings.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {CAN_USE_BEFORE_INPUT} from '@lexical/utils'; import {useEffect, useMemo, useState} from 'react'; diff --git a/packages/lexical-playground/src/context/FlashMessageContext.tsx b/packages/lexical-playground/src/context/FlashMessageContext.tsx index 16f83c39cce..7ee838a0cf3 100644 --- a/packages/lexical-playground/src/context/FlashMessageContext.tsx +++ b/packages/lexical-playground/src/context/FlashMessageContext.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import { createContext, ReactNode, diff --git a/packages/lexical-playground/src/context/SettingsContext.tsx b/packages/lexical-playground/src/context/SettingsContext.tsx index f114c29619b..48b2e1c2007 100644 --- a/packages/lexical-playground/src/context/SettingsContext.tsx +++ b/packages/lexical-playground/src/context/SettingsContext.tsx @@ -7,6 +7,7 @@ */ import type {SettingName} from '../appSettings'; +import type {JSX} from 'react'; import * as React from 'react'; import { diff --git a/packages/lexical-playground/src/context/SharedHistoryContext.tsx b/packages/lexical-playground/src/context/SharedHistoryContext.tsx index 316c337f43c..340360afd95 100644 --- a/packages/lexical-playground/src/context/SharedHistoryContext.tsx +++ b/packages/lexical-playground/src/context/SharedHistoryContext.tsx @@ -7,6 +7,7 @@ */ import type {HistoryState} from '@lexical/react/LexicalHistoryPlugin'; +import type {JSX} from 'react'; import {createEmptyHistoryState} from '@lexical/react/LexicalHistoryPlugin'; import * as React from 'react'; diff --git a/packages/lexical-playground/src/context/ToolbarContext.tsx b/packages/lexical-playground/src/context/ToolbarContext.tsx index f8b1c1f082b..1b6e17ddbc5 100644 --- a/packages/lexical-playground/src/context/ToolbarContext.tsx +++ b/packages/lexical-playground/src/context/ToolbarContext.tsx @@ -5,6 +5,9 @@ * LICENSE file in the root directory of this source tree. * */ + +import type {JSX} from 'react'; + import {ElementFormatType} from 'lexical'; import React, { createContext, diff --git a/packages/lexical-playground/src/hooks/useModal.tsx b/packages/lexical-playground/src/hooks/useModal.tsx index ef68e7c7959..b87e9e04af0 100644 --- a/packages/lexical-playground/src/hooks/useModal.tsx +++ b/packages/lexical-playground/src/hooks/useModal.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useCallback, useMemo, useState} from 'react'; import * as React from 'react'; diff --git a/packages/lexical-playground/src/nodes/AutocompleteNode.tsx b/packages/lexical-playground/src/nodes/AutocompleteNode.tsx index 777f0d69ab6..20b6e6b1088 100644 --- a/packages/lexical-playground/src/nodes/AutocompleteNode.tsx +++ b/packages/lexical-playground/src/nodes/AutocompleteNode.tsx @@ -48,23 +48,16 @@ export class AutocompleteNode extends TextNode { static importJSON( serializedNode: SerializedAutocompleteNode, ): AutocompleteNode { - const node = $createAutocompleteNode( + return $createAutocompleteNode( serializedNode.text, serializedNode.uuid, - ); - node.setFormat(serializedNode.format); - node.setDetail(serializedNode.detail); - node.setMode(serializedNode.mode); - node.setStyle(serializedNode.style); - return node; + ).updateFromJSON(serializedNode); } exportJSON(): SerializedAutocompleteNode { return { ...super.exportJSON(), - type: 'autocomplete', uuid: this.__uuid, - version: 1, }; } diff --git a/packages/lexical-playground/src/nodes/EmojiNode.tsx b/packages/lexical-playground/src/nodes/EmojiNode.tsx index 30b899666d1..5957632d371 100644 --- a/packages/lexical-playground/src/nodes/EmojiNode.tsx +++ b/packages/lexical-playground/src/nodes/EmojiNode.tsx @@ -58,22 +58,16 @@ export class EmojiNode extends TextNode { } static importJSON(serializedNode: SerializedEmojiNode): EmojiNode { - const node = $createEmojiNode( + return $createEmojiNode( serializedNode.className, serializedNode.text, - ); - node.setFormat(serializedNode.format); - node.setDetail(serializedNode.detail); - node.setMode(serializedNode.mode); - node.setStyle(serializedNode.style); - return node; + ).updateFromJSON(serializedNode); } exportJSON(): SerializedEmojiNode { return { ...super.exportJSON(), className: this.getClassName(), - type: 'emoji', }; } diff --git a/packages/lexical-playground/src/nodes/EquationComponent.tsx b/packages/lexical-playground/src/nodes/EquationComponent.tsx index 6929f5363f7..61fc07f12b7 100644 --- a/packages/lexical-playground/src/nodes/EquationComponent.tsx +++ b/packages/lexical-playground/src/nodes/EquationComponent.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalEditable} from '@lexical/react/useLexicalEditable'; import {mergeRegister} from '@lexical/utils'; diff --git a/packages/lexical-playground/src/nodes/EquationNode.tsx b/packages/lexical-playground/src/nodes/EquationNode.tsx index 1ab7cce2128..e98d23600e1 100644 --- a/packages/lexical-playground/src/nodes/EquationNode.tsx +++ b/packages/lexical-playground/src/nodes/EquationNode.tsx @@ -15,6 +15,7 @@ import type { SerializedLexicalNode, Spread, } from 'lexical'; +import type {JSX} from 'react'; import katex from 'katex'; import {$applyNodeReplacement, DecoratorNode, DOMExportOutput} from 'lexical'; @@ -65,19 +66,17 @@ export class EquationNode extends DecoratorNode { } static importJSON(serializedNode: SerializedEquationNode): EquationNode { - const node = $createEquationNode( + return $createEquationNode( serializedNode.equation, serializedNode.inline, - ); - return node; + ).updateFromJSON(serializedNode); } exportJSON(): SerializedEquationNode { return { + ...super.exportJSON(), equation: this.getEquation(), inline: this.__inline, - type: 'equation', - version: 1, }; } diff --git a/packages/lexical-playground/src/nodes/ExcalidrawNode/ExcalidrawComponent.tsx b/packages/lexical-playground/src/nodes/ExcalidrawNode/ExcalidrawComponent.tsx index 259935a41f6..d3d1bc22db8 100644 --- a/packages/lexical-playground/src/nodes/ExcalidrawNode/ExcalidrawComponent.tsx +++ b/packages/lexical-playground/src/nodes/ExcalidrawNode/ExcalidrawComponent.tsx @@ -8,6 +8,7 @@ import type {ExcalidrawInitialElements} from '../../ui/ExcalidrawModal'; import type {NodeKey} from 'lexical'; +import type {JSX} from 'react'; import {AppState, BinaryFiles} from '@excalidraw/excalidraw/types/types'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; @@ -57,16 +58,14 @@ export default function ExcalidrawComponent({ (event: KeyboardEvent) => { if (isSelected) { event.preventDefault(); - editor.update(() => { - const node = $getNodeByKey(nodeKey); - if (node) { - node.remove(); - } - }); + const node = $getNodeByKey(nodeKey); + if (node) { + node.remove(); + } } return false; }, - [editor, isSelected, nodeKey], + [isSelected, nodeKey], ); useEffect(() => { diff --git a/packages/lexical-playground/src/nodes/ExcalidrawNode/ExcalidrawImage.tsx b/packages/lexical-playground/src/nodes/ExcalidrawNode/ExcalidrawImage.tsx index b5e13a8f59a..6078ad7d9ad 100644 --- a/packages/lexical-playground/src/nodes/ExcalidrawNode/ExcalidrawImage.tsx +++ b/packages/lexical-playground/src/nodes/ExcalidrawNode/ExcalidrawImage.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {exportToSvg} from '@excalidraw/excalidraw'; import { ExcalidrawElement, diff --git a/packages/lexical-playground/src/nodes/ExcalidrawNode/index.tsx b/packages/lexical-playground/src/nodes/ExcalidrawNode/index.tsx index 71d0860f4b5..a98f23e0604 100644 --- a/packages/lexical-playground/src/nodes/ExcalidrawNode/index.tsx +++ b/packages/lexical-playground/src/nodes/ExcalidrawNode/index.tsx @@ -17,6 +17,7 @@ import type { SerializedLexicalNode, Spread, } from 'lexical'; +import type {JSX} from 'react'; import {DecoratorNode} from 'lexical'; import * as React from 'react'; @@ -79,15 +80,14 @@ export class ExcalidrawNode extends DecoratorNode { serializedNode.data, serializedNode.width ?? 'inherit', serializedNode.height ?? 'inherit', - ); + ).updateFromJSON(serializedNode); } exportJSON(): SerializedExcalidrawNode { return { + ...super.exportJSON(), data: this.__data, height: this.__height === 'inherit' ? undefined : this.__height, - type: 'excalidraw', - version: 1, width: this.__width === 'inherit' ? undefined : this.__width, }; } diff --git a/packages/lexical-playground/src/nodes/FigmaNode.tsx b/packages/lexical-playground/src/nodes/FigmaNode.tsx index 1984c4e4a5f..63aa04c8770 100644 --- a/packages/lexical-playground/src/nodes/FigmaNode.tsx +++ b/packages/lexical-playground/src/nodes/FigmaNode.tsx @@ -14,6 +14,7 @@ import type { NodeKey, Spread, } from 'lexical'; +import type {JSX} from 'react'; import {BlockWithAlignableContents} from '@lexical/react/LexicalBlockWithAlignableContents'; import { @@ -73,17 +74,15 @@ export class FigmaNode extends DecoratorBlockNode { } static importJSON(serializedNode: SerializedFigmaNode): FigmaNode { - const node = $createFigmaNode(serializedNode.documentID); - node.setFormat(serializedNode.format); - return node; + return $createFigmaNode(serializedNode.documentID).updateFromJSON( + serializedNode, + ); } exportJSON(): SerializedFigmaNode { return { ...super.exportJSON(), documentID: this.__id, - type: 'figma', - version: 1, }; } diff --git a/packages/lexical-playground/src/nodes/ImageComponent.tsx b/packages/lexical-playground/src/nodes/ImageComponent.tsx index 7cd2deff7ce..bc4890ccae0 100644 --- a/packages/lexical-playground/src/nodes/ImageComponent.tsx +++ b/packages/lexical-playground/src/nodes/ImageComponent.tsx @@ -12,6 +12,7 @@ import type { LexicalEditor, NodeKey, } from 'lexical'; +import type {JSX} from 'react'; import './ImageNode.css'; @@ -180,17 +181,15 @@ export default function ImageComponent({ if (isSelected && $isNodeSelection(deleteSelection)) { const event: KeyboardEvent = payload; event.preventDefault(); - editor.update(() => { - deleteSelection.getNodes().forEach((node) => { - if ($isImageNode(node)) { - node.remove(); - } - }); + deleteSelection.getNodes().forEach((node) => { + if ($isImageNode(node)) { + node.remove(); + } }); } return false; }, - [editor, isSelected], + [isSelected], ); const $onEnter = useCallback( diff --git a/packages/lexical-playground/src/nodes/ImageNode.tsx b/packages/lexical-playground/src/nodes/ImageNode.tsx index a21971c85f0..f1fda7bb767 100644 --- a/packages/lexical-playground/src/nodes/ImageNode.tsx +++ b/packages/lexical-playground/src/nodes/ImageNode.tsx @@ -13,11 +13,13 @@ import type { EditorConfig, LexicalEditor, LexicalNode, + LexicalUpdateJSON, NodeKey, SerializedEditor, SerializedLexicalNode, Spread, } from 'lexical'; +import type {JSX} from 'react'; import {$applyNodeReplacement, createEditor, DecoratorNode} from 'lexical'; import * as React from 'react'; @@ -99,16 +101,21 @@ export class ImageNode extends DecoratorNode { } static importJSON(serializedNode: SerializedImageNode): ImageNode { - const {altText, height, width, maxWidth, caption, src, showCaption} = - serializedNode; - const node = $createImageNode({ + const {altText, height, width, maxWidth, src, showCaption} = serializedNode; + return $createImageNode({ altText, height, maxWidth, showCaption, src, width, - }); + }).updateFromJSON(serializedNode); + } + + updateFromJSON(serializedNode: LexicalUpdateJSON): this { + const node = super.updateFromJSON(serializedNode); + const {caption} = serializedNode; + const nestedEditor = node.__caption; const editorState = nestedEditor.parseEditorState(caption.editorState); if (!editorState.isEmpty()) { @@ -163,14 +170,13 @@ export class ImageNode extends DecoratorNode { exportJSON(): SerializedImageNode { return { + ...super.exportJSON(), altText: this.getAltText(), caption: this.__caption.toJSON(), height: this.__height === 'inherit' ? 0 : this.__height, maxWidth: this.__maxWidth, showCaption: this.__showCaption, src: this.getSrc(), - type: 'image', - version: 1, width: this.__width === 'inherit' ? 0 : this.__width, }; } diff --git a/packages/lexical-playground/src/nodes/InlineImageNode/InlineImageComponent.tsx b/packages/lexical-playground/src/nodes/InlineImageNode/InlineImageComponent.tsx index 4a2629ffb45..f18f6cd00a0 100644 --- a/packages/lexical-playground/src/nodes/InlineImageNode/InlineImageComponent.tsx +++ b/packages/lexical-playground/src/nodes/InlineImageNode/InlineImageComponent.tsx @@ -7,6 +7,7 @@ */ import type {Position} from './InlineImageNode'; import type {BaseSelection, LexicalEditor, NodeKey} from 'lexical'; +import type {JSX} from 'react'; import './InlineImageNode.css'; @@ -210,18 +211,16 @@ export default function InlineImageComponent({ const event: KeyboardEvent = payload; event.preventDefault(); if (isSelected && $isNodeSelection(deleteSelection)) { - editor.update(() => { - deleteSelection.getNodes().forEach((node) => { - if ($isInlineImageNode(node)) { - node.remove(); - } - }); + deleteSelection.getNodes().forEach((node) => { + if ($isInlineImageNode(node)) { + node.remove(); + } }); } } return false; }, - [editor, isSelected], + [isSelected], ); const $onEnter = useCallback( diff --git a/packages/lexical-playground/src/nodes/InlineImageNode/InlineImageNode.tsx b/packages/lexical-playground/src/nodes/InlineImageNode/InlineImageNode.tsx index df78864ca00..84dac17e9f5 100644 --- a/packages/lexical-playground/src/nodes/InlineImageNode/InlineImageNode.tsx +++ b/packages/lexical-playground/src/nodes/InlineImageNode/InlineImageNode.tsx @@ -13,11 +13,13 @@ import type { EditorConfig, LexicalEditor, LexicalNode, + LexicalUpdateJSON, NodeKey, SerializedEditor, SerializedLexicalNode, Spread, } from 'lexical'; +import type {JSX} from 'react'; import { $applyNodeReplacement, @@ -100,16 +102,22 @@ export class InlineImageNode extends DecoratorNode { static importJSON( serializedNode: SerializedInlineImageNode, ): InlineImageNode { - const {altText, height, width, caption, src, showCaption, position} = - serializedNode; - const node = $createInlineImageNode({ + const {altText, height, width, src, showCaption, position} = serializedNode; + return $createInlineImageNode({ altText, height, position, showCaption, src, width, - }); + }).updateFromJSON(serializedNode); + } + + updateFromJSON( + serializedNode: LexicalUpdateJSON, + ): this { + const {caption} = serializedNode; + const node = super.updateFromJSON(serializedNode); const nestedEditor = node.__caption; const editorState = nestedEditor.parseEditorState(caption.editorState); if (!editorState.isEmpty()) { @@ -158,14 +166,13 @@ export class InlineImageNode extends DecoratorNode { exportJSON(): SerializedInlineImageNode { return { + ...super.exportJSON(), altText: this.getAltText(), caption: this.__caption.toJSON(), height: this.__height === 'inherit' ? 0 : this.__height, position: this.__position, showCaption: this.__showCaption, src: this.getSrc(), - type: 'inline-image', - version: 1, width: this.__width === 'inherit' ? 0 : this.__width, }; } diff --git a/packages/lexical-playground/src/nodes/KeywordNode.ts b/packages/lexical-playground/src/nodes/KeywordNode.ts index 9d179b8cf2d..f98c01e0f32 100644 --- a/packages/lexical-playground/src/nodes/KeywordNode.ts +++ b/packages/lexical-playground/src/nodes/KeywordNode.ts @@ -8,7 +8,7 @@ import type {EditorConfig, LexicalNode, SerializedTextNode} from 'lexical'; -import {TextNode} from 'lexical'; +import {$applyNodeReplacement, TextNode} from 'lexical'; export type SerializedKeywordNode = SerializedTextNode; @@ -22,20 +22,7 @@ export class KeywordNode extends TextNode { } static importJSON(serializedNode: SerializedKeywordNode): KeywordNode { - const node = $createKeywordNode(serializedNode.text); - node.setFormat(serializedNode.format); - node.setDetail(serializedNode.detail); - node.setMode(serializedNode.mode); - node.setStyle(serializedNode.style); - return node; - } - - exportJSON(): SerializedKeywordNode { - return { - ...super.exportJSON(), - type: 'keyword', - version: 1, - }; + return $createKeywordNode().updateFromJSON(serializedNode); } createDOM(config: EditorConfig): HTMLElement { @@ -58,8 +45,8 @@ export class KeywordNode extends TextNode { } } -export function $createKeywordNode(keyword: string): KeywordNode { - return new KeywordNode(keyword); +export function $createKeywordNode(keyword: string = ''): KeywordNode { + return $applyNodeReplacement(new KeywordNode(keyword)); } export function $isKeywordNode(node: LexicalNode | null | undefined): boolean { diff --git a/packages/lexical-playground/src/nodes/LayoutContainerNode.ts b/packages/lexical-playground/src/nodes/LayoutContainerNode.ts index 8bb7cddf47a..e084c2196f0 100644 --- a/packages/lexical-playground/src/nodes/LayoutContainerNode.ts +++ b/packages/lexical-playground/src/nodes/LayoutContainerNode.ts @@ -12,6 +12,7 @@ import type { DOMExportOutput, EditorConfig, LexicalNode, + LexicalUpdateJSON, NodeKey, SerializedElementNode, Spread, @@ -95,7 +96,15 @@ export class LayoutContainerNode extends ElementNode { } static importJSON(json: SerializedLayoutContainerNode): LayoutContainerNode { - return $createLayoutContainerNode(json.templateColumns); + return $createLayoutContainerNode().updateFromJSON(json); + } + + updateFromJSON( + serializedNode: LexicalUpdateJSON, + ): this { + return super + .updateFromJSON(serializedNode) + .setTemplateColumns(serializedNode.templateColumns); } isShadowRoot(): boolean { @@ -110,8 +119,6 @@ export class LayoutContainerNode extends ElementNode { return { ...super.exportJSON(), templateColumns: this.__templateColumns, - type: 'layout-container', - version: 1, }; } @@ -119,13 +126,15 @@ export class LayoutContainerNode extends ElementNode { return this.getLatest().__templateColumns; } - setTemplateColumns(templateColumns: string) { - this.getWritable().__templateColumns = templateColumns; + setTemplateColumns(templateColumns: string): this { + const self = this.getWritable(); + self.__templateColumns = templateColumns; + return self; } } export function $createLayoutContainerNode( - templateColumns: string, + templateColumns: string = '', ): LayoutContainerNode { return new LayoutContainerNode(templateColumns); } diff --git a/packages/lexical-playground/src/nodes/LayoutItemNode.ts b/packages/lexical-playground/src/nodes/LayoutItemNode.ts index 3d227976d64..4d6bf9da297 100644 --- a/packages/lexical-playground/src/nodes/LayoutItemNode.ts +++ b/packages/lexical-playground/src/nodes/LayoutItemNode.ts @@ -59,21 +59,13 @@ export class LayoutItemNode extends ElementNode { }; } - static importJSON(): LayoutItemNode { - return $createLayoutItemNode(); + static importJSON(serializedNode: SerializedLayoutItemNode): LayoutItemNode { + return $createLayoutItemNode().updateFromJSON(serializedNode); } isShadowRoot(): boolean { return true; } - - exportJSON(): SerializedLayoutItemNode { - return { - ...super.exportJSON(), - type: 'layout-item', - version: 1, - }; - } } export function $createLayoutItemNode(): LayoutItemNode { diff --git a/packages/lexical-playground/src/nodes/MentionNode.ts b/packages/lexical-playground/src/nodes/MentionNode.ts index b6a41754025..ffeb96e9c05 100644 --- a/packages/lexical-playground/src/nodes/MentionNode.ts +++ b/packages/lexical-playground/src/nodes/MentionNode.ts @@ -30,9 +30,13 @@ function $convertMentionElement( domNode: HTMLElement, ): DOMConversionOutput | null { const textContent = domNode.textContent; + const mentionName = domNode.getAttribute('data-lexical-mention-name'); if (textContent !== null) { - const node = $createMentionNode(textContent); + const node = $createMentionNode( + typeof mentionName === 'string' ? mentionName : textContent, + textContent, + ); return { node, }; @@ -53,13 +57,9 @@ export class MentionNode extends TextNode { return new MentionNode(node.__mention, node.__text, node.__key); } static importJSON(serializedNode: SerializedMentionNode): MentionNode { - const node = $createMentionNode(serializedNode.mentionName); - node.setTextContent(serializedNode.text); - node.setFormat(serializedNode.format); - node.setDetail(serializedNode.detail); - node.setMode(serializedNode.mode); - node.setStyle(serializedNode.style); - return node; + return $createMentionNode(serializedNode.mentionName).updateFromJSON( + serializedNode, + ); } constructor(mentionName: string, text?: string, key?: NodeKey) { @@ -71,8 +71,6 @@ export class MentionNode extends TextNode { return { ...super.exportJSON(), mentionName: this.__mention, - type: 'mention', - version: 1, }; } @@ -87,6 +85,9 @@ export class MentionNode extends TextNode { exportDOM(): DOMExportOutput { const element = document.createElement('span'); element.setAttribute('data-lexical-mention', 'true'); + if (this.__text !== this.__mention) { + element.setAttribute('data-lexical-mention-name', this.__mention); + } element.textContent = this.__text; return {element}; } @@ -118,8 +119,11 @@ export class MentionNode extends TextNode { } } -export function $createMentionNode(mentionName: string): MentionNode { - const mentionNode = new MentionNode(mentionName); +export function $createMentionNode( + mentionName: string, + textContent?: string, +): MentionNode { + const mentionNode = new MentionNode(mentionName, (textContent = mentionName)); mentionNode.setMode('segmented').toggleDirectionless(); return $applyNodeReplacement(mentionNode); } diff --git a/packages/lexical-playground/src/nodes/PageBreakNode/index.tsx b/packages/lexical-playground/src/nodes/PageBreakNode/index.tsx index 8e6a1f551a1..4416faa9729 100644 --- a/packages/lexical-playground/src/nodes/PageBreakNode/index.tsx +++ b/packages/lexical-playground/src/nodes/PageBreakNode/index.tsx @@ -5,6 +5,9 @@ * LICENSE file in the root directory of this source tree. * */ + +import type {JSX} from 'react'; + import './index.css'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; @@ -40,17 +43,15 @@ function PageBreakComponent({nodeKey}: {nodeKey: NodeKey}) { event.preventDefault(); const deleteSelection = $getSelection(); if (isSelected && $isNodeSelection(deleteSelection)) { - editor.update(() => { - deleteSelection.getNodes().forEach((node) => { - if ($isPageBreakNode(node)) { - node.remove(); - } - }); + deleteSelection.getNodes().forEach((node) => { + if ($isPageBreakNode(node)) { + node.remove(); + } }); } return false; }, - [editor, isSelected], + [isSelected], ); useEffect(() => { @@ -105,7 +106,7 @@ export class PageBreakNode extends DecoratorNode { } static importJSON(serializedNode: SerializedPageBreakNode): PageBreakNode { - return $createPageBreakNode(); + return $createPageBreakNode().updateFromJSON(serializedNode); } static importDOM(): DOMConversionMap | null { @@ -124,13 +125,6 @@ export class PageBreakNode extends DecoratorNode { }; } - exportJSON(): SerializedLexicalNode { - return { - type: this.getType(), - version: 1, - }; - } - createDOM(): HTMLElement { const el = document.createElement('figure'); el.style.pageBreakAfter = 'always'; diff --git a/packages/lexical-playground/src/nodes/PollComponent.tsx b/packages/lexical-playground/src/nodes/PollComponent.tsx index 687a924bc8b..70a67de3468 100644 --- a/packages/lexical-playground/src/nodes/PollComponent.tsx +++ b/packages/lexical-playground/src/nodes/PollComponent.tsx @@ -7,6 +7,7 @@ */ import type {Option, Options, PollNode} from './PollNode'; +import type {JSX} from 'react'; import './PollNode.css'; @@ -150,17 +151,15 @@ export default function PollComponent({ if (isSelected && $isNodeSelection(deleteSelection)) { const event: KeyboardEvent = payload; event.preventDefault(); - editor.update(() => { - deleteSelection.getNodes().forEach((node) => { - if ($isPollNode(node)) { - node.remove(); - } - }); + deleteSelection.getNodes().forEach((node) => { + if ($isPollNode(node)) { + node.remove(); + } }); } return false; }, - [editor, isSelected], + [isSelected], ); useEffect(() => { diff --git a/packages/lexical-playground/src/nodes/PollNode.tsx b/packages/lexical-playground/src/nodes/PollNode.tsx index fd8fe8097e7..f4f57f47cda 100644 --- a/packages/lexical-playground/src/nodes/PollNode.tsx +++ b/packages/lexical-playground/src/nodes/PollNode.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import { DecoratorNode, DOMConversionMap, @@ -87,12 +89,10 @@ export class PollNode extends DecoratorNode { } static importJSON(serializedNode: SerializedPollNode): PollNode { - const node = $createPollNode( + return $createPollNode( serializedNode.question, serializedNode.options, - ); - serializedNode.options.forEach(node.addOption); - return node; + ).updateFromJSON(serializedNode); } constructor(question: string, options: Options, key?: NodeKey) { @@ -103,10 +103,9 @@ export class PollNode extends DecoratorNode { exportJSON(): SerializedPollNode { return { + ...super.exportJSON(), options: this.__options, question: this.__question, - type: 'poll', - version: 1, }; } diff --git a/packages/lexical-playground/src/nodes/SpecialTextNode.tsx b/packages/lexical-playground/src/nodes/SpecialTextNode.tsx index 8c89106f7cf..fd4b5922706 100644 --- a/packages/lexical-playground/src/nodes/SpecialTextNode.tsx +++ b/packages/lexical-playground/src/nodes/SpecialTextNode.tsx @@ -6,12 +6,7 @@ * */ -import type { - EditorConfig, - LexicalNode, - NodeKey, - SerializedTextNode, -} from 'lexical'; +import type {EditorConfig, LexicalNode, SerializedTextNode} from 'lexical'; import {addClassNamesToElement} from '@lexical/utils'; import {$applyNodeReplacement, TextNode} from 'lexical'; @@ -26,10 +21,6 @@ export class SpecialTextNode extends TextNode { return new SpecialTextNode(node.__text, node.__key); } - constructor(text: string, key?: NodeKey) { - super(text, key); - } - createDOM(config: EditorConfig): HTMLElement { const dom = document.createElement('span'); addClassNamesToElement(dom, config.theme.specialText); @@ -49,19 +40,7 @@ export class SpecialTextNode extends TextNode { } static importJSON(serializedNode: SerializedTextNode): SpecialTextNode { - const node = $createSpecialTextNode(serializedNode.text); - node.setFormat(serializedNode.format); - node.setStyle(serializedNode.style); - node.setDetail(serializedNode.detail); - node.setMode(serializedNode.mode); - return node; - } - - exportJSON(): SerializedTextNode { - return { - ...super.exportJSON(), - type: 'specialText', - }; + return $createSpecialTextNode().updateFromJSON(serializedNode); } isTextEntity(): true { diff --git a/packages/lexical-playground/src/nodes/StickyComponent.tsx b/packages/lexical-playground/src/nodes/StickyComponent.tsx index 469ac869457..9b83e5c2e96 100644 --- a/packages/lexical-playground/src/nodes/StickyComponent.tsx +++ b/packages/lexical-playground/src/nodes/StickyComponent.tsx @@ -7,6 +7,7 @@ */ import type {LexicalEditor, NodeKey} from 'lexical'; +import type {JSX} from 'react'; import './StickyNode.css'; diff --git a/packages/lexical-playground/src/nodes/StickyNode.tsx b/packages/lexical-playground/src/nodes/StickyNode.tsx index 883974ee48e..bf7e568ce4f 100644 --- a/packages/lexical-playground/src/nodes/StickyNode.tsx +++ b/packages/lexical-playground/src/nodes/StickyNode.tsx @@ -10,11 +10,13 @@ import type { EditorConfig, LexicalEditor, LexicalNode, + LexicalUpdateJSON, NodeKey, SerializedEditor, SerializedLexicalNode, Spread, } from 'lexical'; +import type {JSX} from 'react'; import {$setSelection, createEditor, DecoratorNode} from 'lexical'; import * as React from 'react'; @@ -55,11 +57,17 @@ export class StickyNode extends DecoratorNode { ); } static importJSON(serializedNode: SerializedStickyNode): StickyNode { - const stickyNode = new StickyNode( + return new StickyNode( serializedNode.xOffset, serializedNode.yOffset, serializedNode.color, - ); + ).updateFromJSON(serializedNode); + } + + updateFromJSON( + serializedNode: LexicalUpdateJSON, + ): this { + const stickyNode = super.updateFromJSON(serializedNode); const caption = serializedNode.caption; const nestedEditor = stickyNode.__caption; const editorState = nestedEditor.parseEditorState(caption.editorState); @@ -85,10 +93,9 @@ export class StickyNode extends DecoratorNode { exportJSON(): SerializedStickyNode { return { + ...super.exportJSON(), caption: this.__caption.toJSON(), color: this.__color, - type: 'sticky', - version: 1, xOffset: this.__x, yOffset: this.__y, }; diff --git a/packages/lexical-playground/src/nodes/TweetNode.tsx b/packages/lexical-playground/src/nodes/TweetNode.tsx index 4ca2c288a40..31a9cae05c9 100644 --- a/packages/lexical-playground/src/nodes/TweetNode.tsx +++ b/packages/lexical-playground/src/nodes/TweetNode.tsx @@ -17,6 +17,7 @@ import type { NodeKey, Spread, } from 'lexical'; +import type {JSX} from 'react'; import {BlockWithAlignableContents} from '@lexical/react/LexicalBlockWithAlignableContents'; import { @@ -142,17 +143,13 @@ export class TweetNode extends DecoratorBlockNode { } static importJSON(serializedNode: SerializedTweetNode): TweetNode { - const node = $createTweetNode(serializedNode.id); - node.setFormat(serializedNode.format); - return node; + return $createTweetNode(serializedNode.id).updateFromJSON(serializedNode); } exportJSON(): SerializedTweetNode { return { ...super.exportJSON(), id: this.getId(), - type: 'tweet', - version: 1, }; } diff --git a/packages/lexical-playground/src/nodes/YouTubeNode.tsx b/packages/lexical-playground/src/nodes/YouTubeNode.tsx index 3c04a0269ed..999da5efa07 100644 --- a/packages/lexical-playground/src/nodes/YouTubeNode.tsx +++ b/packages/lexical-playground/src/nodes/YouTubeNode.tsx @@ -17,6 +17,7 @@ import type { NodeKey, Spread, } from 'lexical'; +import type {JSX} from 'react'; import {BlockWithAlignableContents} from '@lexical/react/LexicalBlockWithAlignableContents'; import { @@ -89,16 +90,14 @@ export class YouTubeNode extends DecoratorBlockNode { } static importJSON(serializedNode: SerializedYouTubeNode): YouTubeNode { - const node = $createYouTubeNode(serializedNode.videoID); - node.setFormat(serializedNode.format); - return node; + return $createYouTubeNode(serializedNode.videoID).updateFromJSON( + serializedNode, + ); } exportJSON(): SerializedYouTubeNode { return { ...super.exportJSON(), - type: 'youtube', - version: 1, videoID: this.__id, }; } diff --git a/packages/lexical-playground/src/plugins/ActionsPlugin/index.tsx b/packages/lexical-playground/src/plugins/ActionsPlugin/index.tsx index 7fa791a2a1b..dcd4cddac8e 100644 --- a/packages/lexical-playground/src/plugins/ActionsPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/ActionsPlugin/index.tsx @@ -7,6 +7,7 @@ */ import type {LexicalEditor} from 'lexical'; +import type {JSX} from 'react'; import {$createCodeNode, $isCodeNode} from '@lexical/code'; import { diff --git a/packages/lexical-playground/src/plugins/AutoEmbedPlugin/index.tsx b/packages/lexical-playground/src/plugins/AutoEmbedPlugin/index.tsx index 808967b3082..59c672d6e73 100644 --- a/packages/lexical-playground/src/plugins/AutoEmbedPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/AutoEmbedPlugin/index.tsx @@ -7,6 +7,7 @@ */ import type {LexicalEditor} from 'lexical'; +import type {JSX} from 'react'; import { AutoEmbedOption, diff --git a/packages/lexical-playground/src/plugins/AutoLinkPlugin/index.tsx b/packages/lexical-playground/src/plugins/AutoLinkPlugin/index.tsx index 399b0e5eafa..3686590785b 100644 --- a/packages/lexical-playground/src/plugins/AutoLinkPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/AutoLinkPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import { AutoLinkPlugin, createLinkMatcherWithRegExp, diff --git a/packages/lexical-playground/src/plugins/AutocompletePlugin/index.tsx b/packages/lexical-playground/src/plugins/AutocompletePlugin/index.tsx index 6f427cdfe7d..6a3da055337 100644 --- a/packages/lexical-playground/src/plugins/AutocompletePlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/AutocompletePlugin/index.tsx @@ -7,6 +7,7 @@ */ import type {BaseSelection, NodeKey, TextNode} from 'lexical'; +import type {JSX} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {$isAtNodeEnd} from '@lexical/selection'; diff --git a/packages/lexical-playground/src/plugins/CodeActionMenuPlugin/index.tsx b/packages/lexical-playground/src/plugins/CodeActionMenuPlugin/index.tsx index e0a795a6a05..aeb94e98b87 100644 --- a/packages/lexical-playground/src/plugins/CodeActionMenuPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/CodeActionMenuPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import './index.css'; import { diff --git a/packages/lexical-playground/src/plugins/CodeHighlightPlugin/index.ts b/packages/lexical-playground/src/plugins/CodeHighlightPlugin/index.ts index 7813912ecb8..2ec110c7bdc 100644 --- a/packages/lexical-playground/src/plugins/CodeHighlightPlugin/index.ts +++ b/packages/lexical-playground/src/plugins/CodeHighlightPlugin/index.ts @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {registerCodeHighlighting} from '@lexical/code'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useEffect} from 'react'; diff --git a/packages/lexical-playground/src/plugins/CollapsiblePlugin/CollapsibleContainerNode.ts b/packages/lexical-playground/src/plugins/CollapsiblePlugin/CollapsibleContainerNode.ts index 6d4387e0a59..5222227b13f 100644 --- a/packages/lexical-playground/src/plugins/CollapsiblePlugin/CollapsibleContainerNode.ts +++ b/packages/lexical-playground/src/plugins/CollapsiblePlugin/CollapsibleContainerNode.ts @@ -118,8 +118,9 @@ export class CollapsibleContainerNode extends ElementNode { static importJSON( serializedNode: SerializedCollapsibleContainerNode, ): CollapsibleContainerNode { - const node = $createCollapsibleContainerNode(serializedNode.open); - return node; + return $createCollapsibleContainerNode(serializedNode.open).updateFromJSON( + serializedNode, + ); } exportDOM(): DOMExportOutput { @@ -133,8 +134,6 @@ export class CollapsibleContainerNode extends ElementNode { return { ...super.exportJSON(), open: this.__open, - type: 'collapsible-container', - version: 1, }; } diff --git a/packages/lexical-playground/src/plugins/CollapsiblePlugin/CollapsibleContentNode.ts b/packages/lexical-playground/src/plugins/CollapsiblePlugin/CollapsibleContentNode.ts index f6f4ce07ddd..a0c7632b846 100644 --- a/packages/lexical-playground/src/plugins/CollapsiblePlugin/CollapsibleContentNode.ts +++ b/packages/lexical-playground/src/plugins/CollapsiblePlugin/CollapsibleContentNode.ts @@ -100,20 +100,12 @@ export class CollapsibleContentNode extends ElementNode { static importJSON( serializedNode: SerializedCollapsibleContentNode, ): CollapsibleContentNode { - return $createCollapsibleContentNode(); + return $createCollapsibleContentNode().updateFromJSON(serializedNode); } isShadowRoot(): boolean { return true; } - - exportJSON(): SerializedCollapsibleContentNode { - return { - ...super.exportJSON(), - type: 'collapsible-content', - version: 1, - }; - } } export function $createCollapsibleContentNode(): CollapsibleContentNode { diff --git a/packages/lexical-playground/src/plugins/CollapsiblePlugin/CollapsibleTitleNode.ts b/packages/lexical-playground/src/plugins/CollapsiblePlugin/CollapsibleTitleNode.ts index 3b6a39061b3..9a466d5b7d4 100644 --- a/packages/lexical-playground/src/plugins/CollapsiblePlugin/CollapsibleTitleNode.ts +++ b/packages/lexical-playground/src/plugins/CollapsiblePlugin/CollapsibleTitleNode.ts @@ -80,15 +80,7 @@ export class CollapsibleTitleNode extends ElementNode { static importJSON( serializedNode: SerializedCollapsibleTitleNode, ): CollapsibleTitleNode { - return $createCollapsibleTitleNode(); - } - - exportJSON(): SerializedCollapsibleTitleNode { - return { - ...super.exportJSON(), - type: 'collapsible-title', - version: 1, - }; + return $createCollapsibleTitleNode().updateFromJSON(serializedNode); } collapseAtStart(_selection: RangeSelection): boolean { diff --git a/packages/lexical-playground/src/plugins/CommentPlugin/index.tsx b/packages/lexical-playground/src/plugins/CommentPlugin/index.tsx index 2367d0a165e..0d4d7d03dcc 100644 --- a/packages/lexical-playground/src/plugins/CommentPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/CommentPlugin/index.tsx @@ -14,6 +14,7 @@ import type { NodeKey, RangeSelection, } from 'lexical'; +import type {JSX} from 'react'; import type {Doc} from 'yjs'; import './index.css'; diff --git a/packages/lexical-playground/src/plugins/ComponentPickerPlugin/index.tsx b/packages/lexical-playground/src/plugins/ComponentPickerPlugin/index.tsx index 19406089056..af099392625 100644 --- a/packages/lexical-playground/src/plugins/ComponentPickerPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/ComponentPickerPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {$createCodeNode} from '@lexical/code'; import { INSERT_CHECK_LIST_COMMAND, diff --git a/packages/lexical-playground/src/plugins/ContextMenuPlugin/index.tsx b/packages/lexical-playground/src/plugins/ContextMenuPlugin/index.tsx index 36f51ecb2ba..eeec5e02788 100644 --- a/packages/lexical-playground/src/plugins/ContextMenuPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/ContextMenuPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {$isLinkNode, TOGGLE_LINK_COMMAND} from '@lexical/link'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import { @@ -15,6 +17,8 @@ import { import { $getNearestNodeFromDOMNode, $getSelection, + $isDecoratorNode, + $isNodeSelection, $isRangeSelection, COPY_COMMAND, CUT_COMMAND, @@ -181,6 +185,13 @@ export default function ContextMenuPlugin(): JSX.Element { .at(-2); ancestorNodeWithRootAsParent?.remove(); + } else if ($isNodeSelection(selection)) { + const selectedNodes = selection.getNodes(); + selectedNodes.forEach((node) => { + if ($isDecoratorNode(node)) { + node.remove(); + } + }); } }, }), diff --git a/packages/lexical-playground/src/plugins/DocsPlugin/index.tsx b/packages/lexical-playground/src/plugins/DocsPlugin/index.tsx index fe0e24079d1..80738c8bba7 100644 --- a/packages/lexical-playground/src/plugins/DocsPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/DocsPlugin/index.tsx @@ -5,6 +5,9 @@ * LICENSE file in the root directory of this source tree. * */ + +import type {JSX} from 'react'; + import * as React from 'react'; export default function DocsPlugin(): JSX.Element { diff --git a/packages/lexical-playground/src/plugins/DraggableBlockPlugin/index.tsx b/packages/lexical-playground/src/plugins/DraggableBlockPlugin/index.tsx index 891932c94d0..f8320fd94c6 100644 --- a/packages/lexical-playground/src/plugins/DraggableBlockPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/DraggableBlockPlugin/index.tsx @@ -5,6 +5,8 @@ * LICENSE file in the root directory of this source tree. * */ +import type {JSX} from 'react'; + import './index.css'; import {DraggableBlockPlugin_EXPERIMENTAL} from '@lexical/react/LexicalDraggableBlockPlugin'; diff --git a/packages/lexical-playground/src/plugins/EmojisPlugin/index.ts b/packages/lexical-playground/src/plugins/EmojisPlugin/index.ts index 7d0b847dfb6..1ace4ff0d95 100644 --- a/packages/lexical-playground/src/plugins/EmojisPlugin/index.ts +++ b/packages/lexical-playground/src/plugins/EmojisPlugin/index.ts @@ -7,6 +7,7 @@ */ import type {LexicalEditor} from 'lexical'; +import type {JSX} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {TextNode} from 'lexical'; diff --git a/packages/lexical-playground/src/plugins/EquationsPlugin/index.tsx b/packages/lexical-playground/src/plugins/EquationsPlugin/index.tsx index e22fc558ec1..46f1bf7ae1e 100644 --- a/packages/lexical-playground/src/plugins/EquationsPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/EquationsPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import 'katex/dist/katex.css'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; diff --git a/packages/lexical-playground/src/plugins/ExcalidrawPlugin/index.tsx b/packages/lexical-playground/src/plugins/ExcalidrawPlugin/index.tsx index 4bcc00c4b8f..2f431234ca6 100644 --- a/packages/lexical-playground/src/plugins/ExcalidrawPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/ExcalidrawPlugin/index.tsx @@ -7,6 +7,7 @@ */ import type {ExcalidrawInitialElements} from '../../ui/ExcalidrawModal'; import type {AppState, BinaryFiles} from '@excalidraw/excalidraw/types/types'; +import type {JSX} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {$wrapNodeInElement} from '@lexical/utils'; diff --git a/packages/lexical-playground/src/plugins/FigmaPlugin/index.tsx b/packages/lexical-playground/src/plugins/FigmaPlugin/index.tsx index 36c4637411d..50313f761c6 100644 --- a/packages/lexical-playground/src/plugins/FigmaPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/FigmaPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {$insertNodeToNearestRoot} from '@lexical/utils'; import {COMMAND_PRIORITY_EDITOR, createCommand, LexicalCommand} from 'lexical'; diff --git a/packages/lexical-playground/src/plugins/FloatingLinkEditorPlugin/index.tsx b/packages/lexical-playground/src/plugins/FloatingLinkEditorPlugin/index.tsx index 39c9cb2d695..d8255eff11f 100644 --- a/packages/lexical-playground/src/plugins/FloatingLinkEditorPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/FloatingLinkEditorPlugin/index.tsx @@ -5,6 +5,8 @@ * LICENSE file in the root directory of this source tree. * */ +import type {JSX} from 'react'; + import './index.css'; import { diff --git a/packages/lexical-playground/src/plugins/FloatingTextFormatToolbarPlugin/index.tsx b/packages/lexical-playground/src/plugins/FloatingTextFormatToolbarPlugin/index.tsx index 0cb2730b632..4faffa5333d 100644 --- a/packages/lexical-playground/src/plugins/FloatingTextFormatToolbarPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/FloatingTextFormatToolbarPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import './index.css'; import {$isCodeHighlightNode} from '@lexical/code'; diff --git a/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx b/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx index 4fb80b2fab2..4097c58a47f 100644 --- a/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx @@ -5,6 +5,9 @@ * LICENSE file in the root directory of this source tree. * */ + +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {$wrapNodeInElement, mergeRegister} from '@lexical/utils'; import { @@ -22,7 +25,7 @@ import { DRAGOVER_COMMAND, DRAGSTART_COMMAND, DROP_COMMAND, - getDOMSelection, + getDOMSelectionFromTarget, isHTMLElement, LexicalCommand, LexicalEditor, @@ -367,14 +370,7 @@ function canDropImage(event: DragEvent): boolean { function getDragSelection(event: DragEvent): Range | null | undefined { let range; - const target = event.target as null | Element | Document; - const targetWindow = - target == null - ? null - : target.nodeType === 9 - ? (target as Document).defaultView - : (target as Element).ownerDocument.defaultView; - const domSelection = getDOMSelection(targetWindow); + const domSelection = getDOMSelectionFromTarget(event.target); if (document.caretRangeFromPoint) { range = document.caretRangeFromPoint(event.clientX, event.clientY); } else if (event.rangeParent && domSelection !== null) { diff --git a/packages/lexical-playground/src/plugins/InlineImagePlugin/index.tsx b/packages/lexical-playground/src/plugins/InlineImagePlugin/index.tsx index 4ba2f6b40d6..00ce93be3f8 100644 --- a/packages/lexical-playground/src/plugins/InlineImagePlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/InlineImagePlugin/index.tsx @@ -6,6 +6,7 @@ * */ import type {Position} from '../../nodes/InlineImageNode/InlineImageNode'; +import type {JSX} from 'react'; import '../../nodes/InlineImageNode/InlineImageNode.css'; @@ -26,7 +27,7 @@ import { DRAGOVER_COMMAND, DRAGSTART_COMMAND, DROP_COMMAND, - getDOMSelection, + getDOMSelectionFromTarget, isHTMLElement, LexicalCommand, LexicalEditor, @@ -319,14 +320,7 @@ function canDropImage(event: DragEvent): boolean { function getDragSelection(event: DragEvent): Range | null | undefined { let range; - const target = event.target as null | Element | Document; - const targetWindow = - target == null - ? null - : target.nodeType === 9 - ? (target as Document).defaultView - : (target as Element).ownerDocument.defaultView; - const domSelection = getDOMSelection(targetWindow); + const domSelection = getDOMSelectionFromTarget(event.target); if (document.caretRangeFromPoint) { range = document.caretRangeFromPoint(event.clientX, event.clientY); } else if (event.rangeParent && domSelection !== null) { diff --git a/packages/lexical-playground/src/plugins/KeywordsPlugin/index.ts b/packages/lexical-playground/src/plugins/KeywordsPlugin/index.ts index 08e3fe91225..32ed8f5374a 100644 --- a/packages/lexical-playground/src/plugins/KeywordsPlugin/index.ts +++ b/packages/lexical-playground/src/plugins/KeywordsPlugin/index.ts @@ -7,6 +7,7 @@ */ import type {TextNode} from 'lexical'; +import type {JSX} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalTextEntity} from '@lexical/react/useLexicalTextEntity'; diff --git a/packages/lexical-playground/src/plugins/LayoutPlugin/InsertLayoutDialog.tsx b/packages/lexical-playground/src/plugins/LayoutPlugin/InsertLayoutDialog.tsx index cf333bb8a45..a932c584ba5 100644 --- a/packages/lexical-playground/src/plugins/LayoutPlugin/InsertLayoutDialog.tsx +++ b/packages/lexical-playground/src/plugins/LayoutPlugin/InsertLayoutDialog.tsx @@ -5,6 +5,9 @@ * LICENSE file in the root directory of this source tree. * */ + +import type {JSX} from 'react'; + import {LexicalEditor} from 'lexical'; import * as React from 'react'; import {useState} from 'react'; diff --git a/packages/lexical-playground/src/plugins/LinkPlugin/index.tsx b/packages/lexical-playground/src/plugins/LinkPlugin/index.tsx index 68799491dc5..0d5dad094f6 100644 --- a/packages/lexical-playground/src/plugins/LinkPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/LinkPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {LinkPlugin as LexicalLinkPlugin} from '@lexical/react/LexicalLinkPlugin'; import * as React from 'react'; diff --git a/packages/lexical-playground/src/plugins/ListMaxIndentLevelPlugin/index.ts b/packages/lexical-playground/src/plugins/ListMaxIndentLevelPlugin/index.ts deleted file mode 100644 index 198543784c1..00000000000 --- a/packages/lexical-playground/src/plugins/ListMaxIndentLevelPlugin/index.ts +++ /dev/null @@ -1,85 +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 {ElementNode, RangeSelection} from 'lexical'; - -import {$getListDepth, $isListItemNode, $isListNode} from '@lexical/list'; -import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; -import { - $getSelection, - $isElementNode, - $isRangeSelection, - COMMAND_PRIORITY_CRITICAL, - INDENT_CONTENT_COMMAND, -} from 'lexical'; -import {useEffect} from 'react'; - -function getElementNodesInSelection( - selection: RangeSelection, -): Set { - const nodesInSelection = selection.getNodes(); - - if (nodesInSelection.length === 0) { - return new Set([ - selection.anchor.getNode().getParentOrThrow(), - selection.focus.getNode().getParentOrThrow(), - ]); - } - - return new Set( - nodesInSelection.map((n) => ($isElementNode(n) ? n : n.getParentOrThrow())), - ); -} - -function $shouldPreventIndent(maxDepth: number): boolean { - const selection = $getSelection(); - - if (!$isRangeSelection(selection)) { - return false; - } - - const elementNodesInSelection: Set = - getElementNodesInSelection(selection); - - let totalDepth = 0; - - for (const elementNode of elementNodesInSelection) { - if ($isListNode(elementNode)) { - totalDepth = Math.max($getListDepth(elementNode) + 1, totalDepth); - } else if ($isListItemNode(elementNode)) { - const parent = elementNode.getParent(); - - if (!$isListNode(parent)) { - throw new Error( - 'ListMaxIndentLevelPlugin: A ListItemNode must have a ListNode for a parent.', - ); - } - - totalDepth = Math.max($getListDepth(parent) + 1, totalDepth); - } - } - - return totalDepth > maxDepth; -} - -export default function ListMaxIndentLevelPlugin({ - maxDepth = 7, -}: { - maxDepth?: number; -}): null { - const [editor] = useLexicalComposerContext(); - - useEffect(() => { - return editor.registerCommand( - INDENT_CONTENT_COMMAND, - () => $shouldPreventIndent(maxDepth), - COMMAND_PRIORITY_CRITICAL, - ); - }, [editor, maxDepth]); - return null; -} diff --git a/packages/lexical-playground/src/plugins/MarkdownShortcutPlugin/index.tsx b/packages/lexical-playground/src/plugins/MarkdownShortcutPlugin/index.tsx index a2eee255c3d..1c801566696 100644 --- a/packages/lexical-playground/src/plugins/MarkdownShortcutPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/MarkdownShortcutPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {MarkdownShortcutPlugin} from '@lexical/react/LexicalMarkdownShortcutPlugin'; import * as React from 'react'; diff --git a/packages/lexical-playground/src/plugins/MarkdownTransformers/index.ts b/packages/lexical-playground/src/plugins/MarkdownTransformers/index.ts index 391e8a7bdb2..7498485217a 100644 --- a/packages/lexical-playground/src/plugins/MarkdownTransformers/index.ts +++ b/packages/lexical-playground/src/plugins/MarkdownTransformers/index.ts @@ -173,10 +173,9 @@ export const TABLE: ElementTransformer = { // It's TableCellNode so it's just to make flow happy if ($isTableCellNode(cell)) { rowOutput.push( - $convertToMarkdownString(PLAYGROUND_TRANSFORMERS, cell).replace( - /\n/g, - '\\n', - ), + $convertToMarkdownString(PLAYGROUND_TRANSFORMERS, cell) + .replace(/\n/g, '\\n') + .trim(), ); if (cell.__headerState === TableCellHeaderStates.ROW) { isHeaderRow = true; diff --git a/packages/lexical-playground/src/plugins/MentionsPlugin/index.tsx b/packages/lexical-playground/src/plugins/MentionsPlugin/index.tsx index faaca3496a3..c81bdf6e542 100644 --- a/packages/lexical-playground/src/plugins/MentionsPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/MentionsPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import { LexicalTypeaheadMenuPlugin, diff --git a/packages/lexical-playground/src/plugins/PageBreakPlugin/index.tsx b/packages/lexical-playground/src/plugins/PageBreakPlugin/index.tsx index 03167c395a0..55b5b4d28d4 100644 --- a/packages/lexical-playground/src/plugins/PageBreakPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/PageBreakPlugin/index.tsx @@ -5,6 +5,9 @@ * LICENSE file in the root directory of this source tree. * */ + +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {$insertNodeToNearestRoot, mergeRegister} from '@lexical/utils'; import { diff --git a/packages/lexical-playground/src/plugins/PasteLogPlugin/index.tsx b/packages/lexical-playground/src/plugins/PasteLogPlugin/index.tsx index 245e6bfa26a..f0d8c02bb9b 100644 --- a/packages/lexical-playground/src/plugins/PasteLogPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/PasteLogPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {COMMAND_PRIORITY_NORMAL, PASTE_COMMAND} from 'lexical'; import * as React from 'react'; diff --git a/packages/lexical-playground/src/plugins/PollPlugin/index.tsx b/packages/lexical-playground/src/plugins/PollPlugin/index.tsx index 93323331f82..99989b76101 100644 --- a/packages/lexical-playground/src/plugins/PollPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/PollPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {$wrapNodeInElement} from '@lexical/utils'; import { diff --git a/packages/lexical-playground/src/plugins/SpecialTextPlugin/index.ts b/packages/lexical-playground/src/plugins/SpecialTextPlugin/index.ts index ecbec844b66..7ad21d61f94 100644 --- a/packages/lexical-playground/src/plugins/SpecialTextPlugin/index.ts +++ b/packages/lexical-playground/src/plugins/SpecialTextPlugin/index.ts @@ -6,6 +6,7 @@ * */ import type {LexicalEditor} from 'lexical'; +import type {JSX} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {TextNode} from 'lexical'; diff --git a/packages/lexical-playground/src/plugins/StickyPlugin/index.ts b/packages/lexical-playground/src/plugins/StickyPlugin/index.ts index 719833f2c84..510cf865a66 100644 --- a/packages/lexical-playground/src/plugins/StickyPlugin/index.ts +++ b/packages/lexical-playground/src/plugins/StickyPlugin/index.ts @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useEffect} from 'react'; diff --git a/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx b/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx index 7fdae2e20c1..06e8510163a 100644 --- a/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx @@ -7,6 +7,7 @@ */ import type {ElementNode, LexicalEditor} from 'lexical'; +import type {JSX} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalEditable} from '@lexical/react/useLexicalEditable'; diff --git a/packages/lexical-playground/src/plugins/TableCellResizer/index.tsx b/packages/lexical-playground/src/plugins/TableCellResizer/index.tsx index 72f6fe694a8..570ad5d11ff 100644 --- a/packages/lexical-playground/src/plugins/TableCellResizer/index.tsx +++ b/packages/lexical-playground/src/plugins/TableCellResizer/index.tsx @@ -7,6 +7,7 @@ */ import type {TableCellNode, TableDOMCell, TableMapType} from '@lexical/table'; import type {LexicalEditor} from 'lexical'; +import type {JSX} from 'react'; import './index.css'; diff --git a/packages/lexical-playground/src/plugins/TableHoverActionsPlugin/index.tsx b/packages/lexical-playground/src/plugins/TableHoverActionsPlugin/index.tsx index 00b1169f06e..a326dfa7683 100644 --- a/packages/lexical-playground/src/plugins/TableHoverActionsPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/TableHoverActionsPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalEditable} from '@lexical/react/useLexicalEditable'; import { @@ -115,6 +117,19 @@ function TableHoverActionsContainer({ height: tableElemHeight, } = (tableDOMElement as HTMLTableElement).getBoundingClientRect(); + // Adjust for using the scrollable table container + const parentElement = (tableDOMElement as HTMLTableElement) + .parentElement; + let tableHasScroll = false; + if ( + parentElement && + parentElement.classList.contains( + 'PlaygroundEditorTheme__tableScrollableWrapper', + ) + ) { + tableHasScroll = + parentElement.scrollWidth > parentElement.clientWidth; + } const {y: editorElemY, left: editorElemLeft} = anchorElem.getBoundingClientRect(); @@ -123,9 +138,15 @@ function TableHoverActionsContainer({ setShownRow(true); setPosition({ height: BUTTON_WIDTH_PX, - left: tableElemLeft - editorElemLeft, + left: + tableHasScroll && parentElement + ? parentElement.offsetLeft + : tableElemLeft - editorElemLeft, top: tableElemBottom - editorElemY + 5, - width: tableElemWidth, + width: + tableHasScroll && parentElement + ? parentElement.offsetWidth + : tableElemWidth, }); } else if (hoveredColumnNode) { setShownColumn(true); diff --git a/packages/lexical-playground/src/plugins/TableOfContentsPlugin/index.tsx b/packages/lexical-playground/src/plugins/TableOfContentsPlugin/index.tsx index 31df0e7259d..e8d3256a590 100644 --- a/packages/lexical-playground/src/plugins/TableOfContentsPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/TableOfContentsPlugin/index.tsx @@ -8,6 +8,7 @@ import type {TableOfContentsEntry} from '@lexical/react/LexicalTableOfContentsPlugin'; import type {HeadingTagType} from '@lexical/rich-text'; import type {NodeKey} from 'lexical'; +import type {JSX} from 'react'; import './index.css'; @@ -56,7 +57,7 @@ function TableOfContentsList({ editor.getEditorState().read(() => { const domElement = editor.getElementByKey(key); if (domElement !== null) { - domElement.scrollIntoView(); + domElement.scrollIntoView({behavior: 'smooth', block: 'center'}); setSelectedKey(key); selectedIndex.current = currIndex; } diff --git a/packages/lexical-playground/src/plugins/TablePlugin.tsx b/packages/lexical-playground/src/plugins/TablePlugin.tsx index 795c784335e..69f8fac4fa7 100644 --- a/packages/lexical-playground/src/plugins/TablePlugin.tsx +++ b/packages/lexical-playground/src/plugins/TablePlugin.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import { INSERT_TABLE_COMMAND, diff --git a/packages/lexical-playground/src/plugins/TestRecorderPlugin/index.tsx b/packages/lexical-playground/src/plugins/TestRecorderPlugin/index.tsx index c97b3de3248..d1ffc174e62 100644 --- a/packages/lexical-playground/src/plugins/TestRecorderPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/TestRecorderPlugin/index.tsx @@ -7,6 +7,7 @@ */ import type {BaseSelection, LexicalEditor} from 'lexical'; +import type {JSX} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import { diff --git a/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx b/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx index 1dd6dc066d4..ab108f41091 100644 --- a/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import { $isCodeNode, CODE_LANGUAGE_FRIENDLY_NAME_MAP, diff --git a/packages/lexical-playground/src/plugins/TreeViewPlugin/index.tsx b/packages/lexical-playground/src/plugins/TreeViewPlugin/index.tsx index 68eae89a00b..36466c9d22c 100644 --- a/packages/lexical-playground/src/plugins/TreeViewPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/TreeViewPlugin/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {TreeView} from '@lexical/react/LexicalTreeView'; import * as React from 'react'; diff --git a/packages/lexical-playground/src/plugins/TwitterPlugin/index.ts b/packages/lexical-playground/src/plugins/TwitterPlugin/index.ts index 789b36fe282..42169837ae6 100644 --- a/packages/lexical-playground/src/plugins/TwitterPlugin/index.ts +++ b/packages/lexical-playground/src/plugins/TwitterPlugin/index.ts @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {$insertNodeToNearestRoot} from '@lexical/utils'; import {COMMAND_PRIORITY_EDITOR, createCommand, LexicalCommand} from 'lexical'; diff --git a/packages/lexical-playground/src/plugins/TypingPerfPlugin/index.ts b/packages/lexical-playground/src/plugins/TypingPerfPlugin/index.ts index 535a9dd1bb4..30577517852 100644 --- a/packages/lexical-playground/src/plugins/TypingPerfPlugin/index.ts +++ b/packages/lexical-playground/src/plugins/TypingPerfPlugin/index.ts @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useEffect} from 'react'; import useReport from '../../hooks/useReport'; diff --git a/packages/lexical-playground/src/plugins/YouTubePlugin/index.ts b/packages/lexical-playground/src/plugins/YouTubePlugin/index.ts index 76685c6d6f5..4bf5a7e4e62 100644 --- a/packages/lexical-playground/src/plugins/YouTubePlugin/index.ts +++ b/packages/lexical-playground/src/plugins/YouTubePlugin/index.ts @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {$insertNodeToNearestRoot} from '@lexical/utils'; import {COMMAND_PRIORITY_EDITOR, createCommand, LexicalCommand} from 'lexical'; diff --git a/packages/lexical-playground/src/themes/PlaygroundEditorTheme.css b/packages/lexical-playground/src/themes/PlaygroundEditorTheme.css index b5306f0b691..02197f4cc9b 100644 --- a/packages/lexical-playground/src/themes/PlaygroundEditorTheme.css +++ b/packages/lexical-playground/src/themes/PlaygroundEditorTheme.css @@ -193,8 +193,16 @@ margin: 0px 25px 30px 0px; } .PlaygroundEditorTheme__tableScrollableWrapper > .PlaygroundEditorTheme__table { - /* Remove the table's margin and put it on the wrapper */ - margin: 0; + /* Remove the table's vertical margin and put it on the wrapper */ + margin-top: 0; + margin-bottom: 0; +} +.PlaygroundEditorTheme__tableAlignmentCenter { + margin-left: auto; + margin-right: auto; +} +.PlaygroundEditorTheme__tableAlignmentRight { + margin-left: auto; } .PlaygroundEditorTheme__table { border-collapse: collapse; @@ -203,7 +211,8 @@ overflow-x: scroll; table-layout: fixed; width: fit-content; - margin: 0px 25px 30px 0px; + margin-top: 25px; + margin-bottom: 30px; } .PlaygroundEditorTheme__tableRowStriping tr:nth-child(even) { background-color: #f2f5fb; @@ -507,6 +516,8 @@ .PlaygroundEditorTheme__layoutItem { border: 1px dashed #ddd; padding: 8px 16px; + min-width: 0; + max-width: 100%; } .PlaygroundEditorTheme__autocomplete { color: #ccc; diff --git a/packages/lexical-playground/src/themes/PlaygroundEditorTheme.ts b/packages/lexical-playground/src/themes/PlaygroundEditorTheme.ts index e7c6a4aab7e..06fc67b44d3 100644 --- a/packages/lexical-playground/src/themes/PlaygroundEditorTheme.ts +++ b/packages/lexical-playground/src/themes/PlaygroundEditorTheme.ts @@ -93,6 +93,10 @@ const theme: EditorThemeClasses = { specialText: 'PlaygroundEditorTheme__specialText', tab: 'PlaygroundEditorTheme__tabNode', table: 'PlaygroundEditorTheme__table', + tableAlignment: { + center: 'PlaygroundEditorTheme__tableAlignmentCenter', + right: 'PlaygroundEditorTheme__tableAlignmentRight', + }, tableCell: 'PlaygroundEditorTheme__tableCell', tableCellActionButton: 'PlaygroundEditorTheme__tableCellActionButton', tableCellActionButtonContainer: diff --git a/packages/lexical-playground/src/ui/Button.tsx b/packages/lexical-playground/src/ui/Button.tsx index a83f7a8735a..9980cc4492b 100644 --- a/packages/lexical-playground/src/ui/Button.tsx +++ b/packages/lexical-playground/src/ui/Button.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import './Button.css'; import * as React from 'react'; diff --git a/packages/lexical-playground/src/ui/ColorPicker.tsx b/packages/lexical-playground/src/ui/ColorPicker.tsx index 6934f5a3af8..6593c02389f 100644 --- a/packages/lexical-playground/src/ui/ColorPicker.tsx +++ b/packages/lexical-playground/src/ui/ColorPicker.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import './ColorPicker.css'; import {calculateZoomLevel} from '@lexical/utils'; diff --git a/packages/lexical-playground/src/ui/ContentEditable.tsx b/packages/lexical-playground/src/ui/ContentEditable.tsx index b1ee20b2103..3865709ef40 100644 --- a/packages/lexical-playground/src/ui/ContentEditable.tsx +++ b/packages/lexical-playground/src/ui/ContentEditable.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import './ContentEditable.css'; import {ContentEditable} from '@lexical/react/LexicalContentEditable'; diff --git a/packages/lexical-playground/src/ui/Dialog.tsx b/packages/lexical-playground/src/ui/Dialog.tsx index 36e3b8c5938..7492432f212 100644 --- a/packages/lexical-playground/src/ui/Dialog.tsx +++ b/packages/lexical-playground/src/ui/Dialog.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import './Dialog.css'; import * as React from 'react'; diff --git a/packages/lexical-playground/src/ui/DropDown.tsx b/packages/lexical-playground/src/ui/DropDown.tsx index 19d3065df0e..1d0b8ac23ab 100644 --- a/packages/lexical-playground/src/ui/DropDown.tsx +++ b/packages/lexical-playground/src/ui/DropDown.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {isDOMNode} from 'lexical'; import * as React from 'react'; import { diff --git a/packages/lexical-playground/src/ui/EquationEditor.tsx b/packages/lexical-playground/src/ui/EquationEditor.tsx index ce512aed010..5f23da1075b 100644 --- a/packages/lexical-playground/src/ui/EquationEditor.tsx +++ b/packages/lexical-playground/src/ui/EquationEditor.tsx @@ -6,7 +6,7 @@ * */ -import type {Ref, RefObject} from 'react'; +import type {JSX, Ref, RefObject} from 'react'; import './EquationEditor.css'; diff --git a/packages/lexical-playground/src/ui/ExcalidrawModal.tsx b/packages/lexical-playground/src/ui/ExcalidrawModal.tsx index 221a2c7c818..2e6acd7d2a9 100644 --- a/packages/lexical-playground/src/ui/ExcalidrawModal.tsx +++ b/packages/lexical-playground/src/ui/ExcalidrawModal.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import './ExcalidrawModal.css'; import {Excalidraw} from '@excalidraw/excalidraw'; diff --git a/packages/lexical-playground/src/ui/FileInput.tsx b/packages/lexical-playground/src/ui/FileInput.tsx index 465330bb446..0d264d8ea61 100644 --- a/packages/lexical-playground/src/ui/FileInput.tsx +++ b/packages/lexical-playground/src/ui/FileInput.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import './Input.css'; import * as React from 'react'; diff --git a/packages/lexical-playground/src/ui/FlashMessage.tsx b/packages/lexical-playground/src/ui/FlashMessage.tsx index 5c6fdb0f340..03219aea6a3 100644 --- a/packages/lexical-playground/src/ui/FlashMessage.tsx +++ b/packages/lexical-playground/src/ui/FlashMessage.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import './FlashMessage.css'; import {ReactNode} from 'react'; diff --git a/packages/lexical-playground/src/ui/ImageResizer.tsx b/packages/lexical-playground/src/ui/ImageResizer.tsx index 13e9f48f926..e2c52ebfbc9 100644 --- a/packages/lexical-playground/src/ui/ImageResizer.tsx +++ b/packages/lexical-playground/src/ui/ImageResizer.tsx @@ -7,6 +7,7 @@ */ import type {LexicalEditor} from 'lexical'; +import type {JSX} from 'react'; import {calculateZoomLevel} from '@lexical/utils'; import * as React from 'react'; diff --git a/packages/lexical-playground/src/ui/KatexEquationAlterer.tsx b/packages/lexical-playground/src/ui/KatexEquationAlterer.tsx index 5bbbcbc4db5..ab3dd38abbc 100644 --- a/packages/lexical-playground/src/ui/KatexEquationAlterer.tsx +++ b/packages/lexical-playground/src/ui/KatexEquationAlterer.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import './KatexEquationAlterer.css'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; diff --git a/packages/lexical-playground/src/ui/KatexRenderer.tsx b/packages/lexical-playground/src/ui/KatexRenderer.tsx index a6084e77aa8..3b914bf4c16 100644 --- a/packages/lexical-playground/src/ui/KatexRenderer.tsx +++ b/packages/lexical-playground/src/ui/KatexRenderer.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import katex from 'katex'; import * as React from 'react'; import {useEffect, useRef} from 'react'; diff --git a/packages/lexical-playground/src/ui/Modal.tsx b/packages/lexical-playground/src/ui/Modal.tsx index 540d7e9d0b2..253df1aca35 100644 --- a/packages/lexical-playground/src/ui/Modal.tsx +++ b/packages/lexical-playground/src/ui/Modal.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import './Modal.css'; import {isDOMNode} from 'lexical'; diff --git a/packages/lexical-playground/src/ui/Select.tsx b/packages/lexical-playground/src/ui/Select.tsx index 59e5ccc069b..5122aed9890 100644 --- a/packages/lexical-playground/src/ui/Select.tsx +++ b/packages/lexical-playground/src/ui/Select.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import './Select.css'; import * as React from 'react'; diff --git a/packages/lexical-playground/src/ui/Switch.tsx b/packages/lexical-playground/src/ui/Switch.tsx index 4510bd11593..fc6b6b439e6 100644 --- a/packages/lexical-playground/src/ui/Switch.tsx +++ b/packages/lexical-playground/src/ui/Switch.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import * as React from 'react'; import {useMemo} from 'react'; diff --git a/packages/lexical-playground/src/ui/TextInput.tsx b/packages/lexical-playground/src/ui/TextInput.tsx index 7b1765ff286..6d2b7b4f6cb 100644 --- a/packages/lexical-playground/src/ui/TextInput.tsx +++ b/packages/lexical-playground/src/ui/TextInput.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import './Input.css'; import * as React from 'react'; diff --git a/packages/lexical-react/flow/LexicalAutoLinkPlugin.js.flow b/packages/lexical-react/flow/LexicalAutoLinkPlugin.js.flow index 77a1399d83f..d166fe8cc14 100644 --- a/packages/lexical-react/flow/LexicalAutoLinkPlugin.js.flow +++ b/packages/lexical-react/flow/LexicalAutoLinkPlugin.js.flow @@ -29,4 +29,4 @@ declare export function createLinkMatcherWithRegExp( declare export function AutoLinkPlugin(props: { matchers: Array, onChange?: ChangeHandler, -}): React$Node; +}): React.Node; diff --git a/packages/lexical-react/flow/LexicalBlockWithAlignableContents.js.flow b/packages/lexical-react/flow/LexicalBlockWithAlignableContents.js.flow index b90f4de03bb..0b479c6151a 100644 --- a/packages/lexical-react/flow/LexicalBlockWithAlignableContents.js.flow +++ b/packages/lexical-react/flow/LexicalBlockWithAlignableContents.js.flow @@ -16,7 +16,7 @@ import type { } from 'lexical'; type Props = $ReadOnly<{ - children: React$Node, + children: React.Node, format: ?ElementFormatType, nodeKey: NodeKey, className: $ReadOnly<{ @@ -25,4 +25,4 @@ type Props = $ReadOnly<{ }>, }>; -declare export function BlockWithAlignableContents(Props): React$Node; +declare export function BlockWithAlignableContents(Props): React.Node; diff --git a/packages/lexical-react/flow/LexicalCharacterLimitPlugin.js.flow b/packages/lexical-react/flow/LexicalCharacterLimitPlugin.js.flow index e0ab6ad096d..2271ffc48d0 100644 --- a/packages/lexical-react/flow/LexicalCharacterLimitPlugin.js.flow +++ b/packages/lexical-react/flow/LexicalCharacterLimitPlugin.js.flow @@ -9,4 +9,4 @@ declare export function CharacterLimitPlugin(props: { charset: 'UTF-8' | 'UTF-16', -}): React$Node; +}): React.Node; diff --git a/packages/lexical-react/flow/LexicalClearEditorPlugin.js.flow b/packages/lexical-react/flow/LexicalClearEditorPlugin.js.flow index 415c60b451b..d815cda8284 100644 --- a/packages/lexical-react/flow/LexicalClearEditorPlugin.js.flow +++ b/packages/lexical-react/flow/LexicalClearEditorPlugin.js.flow @@ -11,4 +11,4 @@ type Props = $ReadOnly<{ onClear?: () => void, }>; -declare export function ClearEditorPlugin(Props): React$Node; +declare export function ClearEditorPlugin(Props): React.Node; diff --git a/packages/lexical-react/flow/LexicalCollaborationPlugin.js.flow b/packages/lexical-react/flow/LexicalCollaborationPlugin.js.flow index 43d2511386b..ad6fbab8806 100644 --- a/packages/lexical-react/flow/LexicalCollaborationPlugin.js.flow +++ b/packages/lexical-react/flow/LexicalCollaborationPlugin.js.flow @@ -47,4 +47,4 @@ declare export function CollaborationPlugin(arg0: { cursorsContainerRef?: CursorsContainerRef, initialEditorState?: InitialEditorStateType, excludedProperties?: ExcludedProperties, -}): React$Node; +}): React.Node; diff --git a/packages/lexical-react/flow/LexicalComposer.js.flow b/packages/lexical-react/flow/LexicalComposer.js.flow index ae02446078c..1fade778921 100644 --- a/packages/lexical-react/flow/LexicalComposer.js.flow +++ b/packages/lexical-react/flow/LexicalComposer.js.flow @@ -34,7 +34,7 @@ export type InitialConfigType = $ReadOnly<{ type Props = { initialConfig: InitialConfigType, - children: React$Node, + children: React.Node, }; -declare export function LexicalComposer(Props): React$MixedElement; +declare export function LexicalComposer(Props): React.MixedElement; diff --git a/packages/lexical-react/flow/LexicalContentEditable.js.flow b/packages/lexical-react/flow/LexicalContentEditable.js.flow index 46fa8ccb950..ceb84c9da30 100644 --- a/packages/lexical-react/flow/LexicalContentEditable.js.flow +++ b/packages/lexical-react/flow/LexicalContentEditable.js.flow @@ -51,9 +51,9 @@ export type PlaceholderProps = | $ReadOnly<{ 'aria-placeholder': string, placeholder: - | ((isEditable: boolean) => null | React$Node) + | ((isEditable: boolean) => null | React.Node) | null - | React$Node, + | React.Node, }>; export type Props = $ReadOnly<{ diff --git a/packages/lexical-react/flow/LexicalDraggableBlockPlugin.js.flow b/packages/lexical-react/flow/LexicalDraggableBlockPlugin.js.flow index c04a612054f..3cecefe4aed 100644 --- a/packages/lexical-react/flow/LexicalDraggableBlockPlugin.js.flow +++ b/packages/lexical-react/flow/LexicalDraggableBlockPlugin.js.flow @@ -20,4 +20,4 @@ type Props = $ReadOnly<{ declare export function DraggableBlockPlugin_EXPERIMENTAL( props: Props, -): React$MixedElement; +): React.MixedElement; diff --git a/packages/lexical-react/flow/LexicalErrorBoundary.js.flow b/packages/lexical-react/flow/LexicalErrorBoundary.js.flow index e94ef8f4a0b..c1f029728e9 100644 --- a/packages/lexical-react/flow/LexicalErrorBoundary.js.flow +++ b/packages/lexical-react/flow/LexicalErrorBoundary.js.flow @@ -8,13 +8,13 @@ */ export type LexicalErrorBoundaryProps = $ReadOnly<{ - children: React$Node, + children: React.Node, onError: (error: Error) => void, }>; declare export function LexicalErrorBoundary( props: LexicalErrorBoundaryProps, -): React$Node; +): React.Node; /** @deprecated use the named export {@link LexicalErrorBoundary} */ export default typeof LexicalErrorBoundary; diff --git a/packages/lexical-react/flow/LexicalHashtagPlugin.js.flow b/packages/lexical-react/flow/LexicalHashtagPlugin.js.flow index 227d9849ab9..21db6643de0 100644 --- a/packages/lexical-react/flow/LexicalHashtagPlugin.js.flow +++ b/packages/lexical-react/flow/LexicalHashtagPlugin.js.flow @@ -7,4 +7,4 @@ * @flow strict */ -declare export function HashtagPlugin(): React$Node; +declare export function HashtagPlugin(): React.Node; diff --git a/packages/lexical-react/flow/LexicalHistoryPlugin.js.flow b/packages/lexical-react/flow/LexicalHistoryPlugin.js.flow index c377b092e51..9ac9c6d2b67 100644 --- a/packages/lexical-react/flow/LexicalHistoryPlugin.js.flow +++ b/packages/lexical-react/flow/LexicalHistoryPlugin.js.flow @@ -23,6 +23,6 @@ export type HistoryState = { declare export function HistoryPlugin({ externalHistoryState?: HistoryState, -}): React$Node; +}): React.Node; declare export function createEmptyHistoryState(): HistoryState; diff --git a/packages/lexical-react/flow/LexicalHorizontalRuleNode.js.flow b/packages/lexical-react/flow/LexicalHorizontalRuleNode.js.flow index 686f7a30e64..2f101926e09 100644 --- a/packages/lexical-react/flow/LexicalHorizontalRuleNode.js.flow +++ b/packages/lexical-react/flow/LexicalHorizontalRuleNode.js.flow @@ -11,13 +11,13 @@ import type {LexicalNode, LexicalCommand} from 'lexical'; import {DecoratorNode} from 'lexical'; -declare export class HorizontalRuleNode extends DecoratorNode { +declare export class HorizontalRuleNode extends DecoratorNode { static getType(): string; static clone(node: HorizontalRuleNode): HorizontalRuleNode; createDOM(): HTMLElement; getTextContent(): '\n'; updateDOM(): false; - decorate(): React$Node; + decorate(): React.Node; } declare export function $createHorizontalRuleNode(): HorizontalRuleNode; diff --git a/packages/lexical-react/flow/LexicalMarkdownShortcutPlugin.js.flow b/packages/lexical-react/flow/LexicalMarkdownShortcutPlugin.js.flow index 05defb423ae..441de0d910c 100644 --- a/packages/lexical-react/flow/LexicalMarkdownShortcutPlugin.js.flow +++ b/packages/lexical-react/flow/LexicalMarkdownShortcutPlugin.js.flow @@ -13,4 +13,4 @@ declare export var DEFAULT_TRANSFORMERS: Array; declare export function MarkdownShortcutPlugin({ transformers?: Array, -}): React$Node; +}): React.Node; diff --git a/packages/lexical-react/flow/LexicalNestedComposer.js.flow b/packages/lexical-react/flow/LexicalNestedComposer.js.flow index 2a4957861fe..98abaace9c7 100644 --- a/packages/lexical-react/flow/LexicalNestedComposer.js.flow +++ b/packages/lexical-react/flow/LexicalNestedComposer.js.flow @@ -15,8 +15,8 @@ import type { } from 'lexical'; declare export function LexicalNestedComposer({ - children: React$Node, + children: React.Node, initialEditor: LexicalEditor, initialTheme?: EditorThemeClasses, initialNodes?: $ReadOnlyArray | LexicalNodeReplacement>, -}): React$Node; +}): React.Node; diff --git a/packages/lexical-react/flow/LexicalPlainTextPlugin.js.flow b/packages/lexical-react/flow/LexicalPlainTextPlugin.js.flow index 7a9e8b403e2..a57425a3042 100644 --- a/packages/lexical-react/flow/LexicalPlainTextPlugin.js.flow +++ b/packages/lexical-react/flow/LexicalPlainTextPlugin.js.flow @@ -20,10 +20,10 @@ type InitialEditorStateType = | ((editor: LexicalEditor) => void); declare export function PlainTextPlugin({ - contentEditable: React$Node, + contentEditable: React.Node, placeholder?: - | ((isEditable: boolean) => null | React$Node) + | ((isEditable: boolean) => null | React.Node) | null - | React$Node; + | React.Node; ErrorBoundary: LexicalErrorBoundary, -}): React$Node; +}): React.Node; diff --git a/packages/lexical-react/flow/LexicalRichTextPlugin.js.flow b/packages/lexical-react/flow/LexicalRichTextPlugin.js.flow index a07bf9e92f4..1cf794ab1c4 100644 --- a/packages/lexical-react/flow/LexicalRichTextPlugin.js.flow +++ b/packages/lexical-react/flow/LexicalRichTextPlugin.js.flow @@ -20,10 +20,10 @@ type InitialEditorStateType = | ((editor: LexicalEditor) => void); declare export function RichTextPlugin({ - contentEditable: React$Node, + contentEditable: React.Node, placeholder?: - | ((isEditable: boolean) => null | React$Node) + | ((isEditable: boolean) => null | React.Node) | null - | React$Node; + | React.Node; ErrorBoundary: LexicalErrorBoundary, -}): React$Node; +}): React.Node; diff --git a/packages/lexical-react/flow/LexicalTabIndentationPlugin.js.flow b/packages/lexical-react/flow/LexicalTabIndentationPlugin.js.flow index 44784b01131..64d9ff87caa 100644 --- a/packages/lexical-react/flow/LexicalTabIndentationPlugin.js.flow +++ b/packages/lexical-react/flow/LexicalTabIndentationPlugin.js.flow @@ -11,6 +11,11 @@ import type {LexicalEditor} from 'lexical'; declare export function registerTabIndentation( editor: LexicalEditor, + maxIndent?: number, ): () => void; -declare export function TabIndentationPlugin(): null; +type Props = $ReadOnly<{ + maxIndent?: number, +}>; + +declare export function TabIndentationPlugin(props: Props): null; diff --git a/packages/lexical-react/flow/LexicalTableOfContentsPlugin.js.flow b/packages/lexical-react/flow/LexicalTableOfContentsPlugin.js.flow index 029ddd35000..302cd1c77a9 100644 --- a/packages/lexical-react/flow/LexicalTableOfContentsPlugin.js.flow +++ b/packages/lexical-react/flow/LexicalTableOfContentsPlugin.js.flow @@ -14,5 +14,5 @@ declare export function TableOfContentsPlugin({ children: ( tableOfContents: Array<[NodeKey, string, HeadingTagType]>, editor: LexicalEditor, - ) => React$Node, -}): React$Node; + ) => React.Node, +}): React.Node; diff --git a/packages/lexical-react/flow/LexicalTreeView.js.flow b/packages/lexical-react/flow/LexicalTreeView.js.flow index 079eab80c18..fb15e54f683 100644 --- a/packages/lexical-react/flow/LexicalTreeView.js.flow +++ b/packages/lexical-react/flow/LexicalTreeView.js.flow @@ -18,4 +18,4 @@ declare export function TreeView(props: { viewClassName: string, editor: LexicalEditor, customPrintNode?: CustomPrintNodeFn, -}): React$Node; +}): React.Node; diff --git a/packages/lexical-react/package.json b/packages/lexical-react/package.json index 79482eb0db9..e9c9499849b 100644 --- a/packages/lexical-react/package.json +++ b/packages/lexical-react/package.json @@ -8,27 +8,27 @@ "rich-text" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "dependencies": { - "@lexical/clipboard": "0.21.0", - "@lexical/code": "0.21.0", - "@lexical/devtools-core": "0.21.0", - "@lexical/dragon": "0.21.0", - "@lexical/hashtag": "0.21.0", - "@lexical/history": "0.21.0", - "@lexical/link": "0.21.0", - "@lexical/list": "0.21.0", - "@lexical/mark": "0.21.0", - "@lexical/markdown": "0.21.0", - "@lexical/overflow": "0.21.0", - "@lexical/plain-text": "0.21.0", - "@lexical/rich-text": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/table": "0.21.0", - "@lexical/text": "0.21.0", - "@lexical/utils": "0.21.0", - "@lexical/yjs": "0.21.0", - "lexical": "0.21.0", + "@lexical/clipboard": "0.23.1", + "@lexical/code": "0.23.1", + "@lexical/devtools-core": "0.23.1", + "@lexical/dragon": "0.23.1", + "@lexical/hashtag": "0.23.1", + "@lexical/history": "0.23.1", + "@lexical/link": "0.23.1", + "@lexical/list": "0.23.1", + "@lexical/mark": "0.23.1", + "@lexical/markdown": "0.23.1", + "@lexical/overflow": "0.23.1", + "@lexical/plain-text": "0.23.1", + "@lexical/rich-text": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/table": "0.23.1", + "@lexical/text": "0.23.1", + "@lexical/utils": "0.23.1", + "@lexical/yjs": "0.23.1", + "lexical": "0.23.1", "react-error-boundary": "^3.1.4" }, "peerDependencies": { diff --git a/packages/lexical-react/src/LexicalAutoEmbedPlugin.tsx b/packages/lexical-react/src/LexicalAutoEmbedPlugin.tsx index 49ebbb1a270..06f753758a2 100644 --- a/packages/lexical-react/src/LexicalAutoEmbedPlugin.tsx +++ b/packages/lexical-react/src/LexicalAutoEmbedPlugin.tsx @@ -10,6 +10,7 @@ import type { LexicalNode, MutationListener, } from 'lexical'; +import type {JSX} from 'react'; import {$isLinkNode, AutoLinkNode, LinkNode} from '@lexical/link'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; diff --git a/packages/lexical-react/src/LexicalAutoLinkPlugin.ts b/packages/lexical-react/src/LexicalAutoLinkPlugin.ts index bb859ca82c6..3fd7314eff9 100644 --- a/packages/lexical-react/src/LexicalAutoLinkPlugin.ts +++ b/packages/lexical-react/src/LexicalAutoLinkPlugin.ts @@ -8,6 +8,7 @@ import type {AutoLinkAttributes} from '@lexical/link'; import type {ElementNode, LexicalEditor, LexicalNode} from 'lexical'; +import type {JSX} from 'react'; import { $createAutoLinkNode, diff --git a/packages/lexical-react/src/LexicalBlockWithAlignableContents.tsx b/packages/lexical-react/src/LexicalBlockWithAlignableContents.tsx index 0a48094ce42..b4a37c04c7a 100644 --- a/packages/lexical-react/src/LexicalBlockWithAlignableContents.tsx +++ b/packages/lexical-react/src/LexicalBlockWithAlignableContents.tsx @@ -7,6 +7,7 @@ */ import type {ElementFormatType, NodeKey} from 'lexical'; +import type {JSX} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {$isDecoratorBlockNode} from '@lexical/react/LexicalDecoratorBlockNode'; @@ -57,17 +58,15 @@ export function BlockWithAlignableContents({ const deleteSelection = $getSelection(); if (isSelected && $isNodeSelection(deleteSelection)) { event.preventDefault(); - editor.update(() => { - deleteSelection.getNodes().forEach((node) => { - if ($isDecoratorNode(node)) { - node.remove(); - } - }); + deleteSelection.getNodes().forEach((node) => { + if ($isDecoratorNode(node)) { + node.remove(); + } }); } return false; }, - [editor, isSelected], + [isSelected], ); useEffect(() => { diff --git a/packages/lexical-react/src/LexicalCharacterLimitPlugin.tsx b/packages/lexical-react/src/LexicalCharacterLimitPlugin.tsx index 7ec19accc0e..125228adec3 100644 --- a/packages/lexical-react/src/LexicalCharacterLimitPlugin.tsx +++ b/packages/lexical-react/src/LexicalCharacterLimitPlugin.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import * as React from 'react'; import {useMemo, useState} from 'react'; diff --git a/packages/lexical-react/src/LexicalClearEditorPlugin.ts b/packages/lexical-react/src/LexicalClearEditorPlugin.ts index b1c77339e6b..11a94da651e 100644 --- a/packages/lexical-react/src/LexicalClearEditorPlugin.ts +++ b/packages/lexical-react/src/LexicalClearEditorPlugin.ts @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import { $createParagraphNode, diff --git a/packages/lexical-react/src/LexicalCollaborationPlugin.tsx b/packages/lexical-react/src/LexicalCollaborationPlugin.tsx index b3018c1af5f..05fec9da468 100644 --- a/packages/lexical-react/src/LexicalCollaborationPlugin.tsx +++ b/packages/lexical-react/src/LexicalCollaborationPlugin.tsx @@ -6,6 +6,7 @@ * */ +import type {JSX} from 'react'; import type {Doc} from 'yjs'; import { diff --git a/packages/lexical-react/src/LexicalComposer.tsx b/packages/lexical-react/src/LexicalComposer.tsx index f5a58ca0a69..1175e1e64fb 100644 --- a/packages/lexical-react/src/LexicalComposer.tsx +++ b/packages/lexical-react/src/LexicalComposer.tsx @@ -7,6 +7,7 @@ */ import type {LexicalComposerContextType} from '@lexical/react/LexicalComposerContext'; +import type {JSX} from 'react'; import { createLexicalComposerContext, diff --git a/packages/lexical-react/src/LexicalContentEditable.tsx b/packages/lexical-react/src/LexicalContentEditable.tsx index 0463ffb4a7a..a4040683728 100644 --- a/packages/lexical-react/src/LexicalContentEditable.tsx +++ b/packages/lexical-react/src/LexicalContentEditable.tsx @@ -8,6 +8,7 @@ import type {Props as ElementProps} from './shared/LexicalContentEditableElement'; import type {LexicalEditor} from 'lexical'; +import type {JSX} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {forwardRef, Ref, useLayoutEffect, useState} from 'react'; diff --git a/packages/lexical-react/src/LexicalContextMenuPlugin.tsx b/packages/lexical-react/src/LexicalContextMenuPlugin.tsx index 7f1676f3cf9..5a31e247adb 100644 --- a/packages/lexical-react/src/LexicalContextMenuPlugin.tsx +++ b/packages/lexical-react/src/LexicalContextMenuPlugin.tsx @@ -6,6 +6,7 @@ * */ import type {MenuRenderFn, MenuResolution} from './shared/LexicalMenu'; +import type {JSX} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {calculateZoomLevel} from '@lexical/utils'; diff --git a/packages/lexical-react/src/LexicalDecoratorBlockNode.ts b/packages/lexical-react/src/LexicalDecoratorBlockNode.ts index 64b1f4bcb74..d2f94d010a3 100644 --- a/packages/lexical-react/src/LexicalDecoratorBlockNode.ts +++ b/packages/lexical-react/src/LexicalDecoratorBlockNode.ts @@ -9,10 +9,12 @@ import type { ElementFormatType, LexicalNode, + LexicalUpdateJSON, NodeKey, SerializedLexicalNode, Spread, } from 'lexical'; +import type {JSX} from 'react'; import {DecoratorNode} from 'lexical'; @@ -33,12 +35,19 @@ export class DecoratorBlockNode extends DecoratorNode { exportJSON(): SerializedDecoratorBlockNode { return { + ...super.exportJSON(), format: this.__format || '', - type: 'decorator-block', - version: 1, }; } + updateFromJSON( + serializedNode: LexicalUpdateJSON, + ): this { + return super + .updateFromJSON(serializedNode) + .setFormat(serializedNode.format || ''); + } + canIndent(): false { return false; } @@ -51,9 +60,10 @@ export class DecoratorBlockNode extends DecoratorNode { return false; } - setFormat(format: ElementFormatType): void { + setFormat(format: ElementFormatType): this { const self = this.getWritable(); self.__format = format; + return self; } isInline(): false { diff --git a/packages/lexical-react/src/LexicalDraggableBlockPlugin.tsx b/packages/lexical-react/src/LexicalDraggableBlockPlugin.tsx index be695b76b23..10584389b05 100644 --- a/packages/lexical-react/src/LexicalDraggableBlockPlugin.tsx +++ b/packages/lexical-react/src/LexicalDraggableBlockPlugin.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {eventFiles} from '@lexical/rich-text'; import {calculateZoomLevel, isHTMLElement, mergeRegister} from '@lexical/utils'; diff --git a/packages/lexical-react/src/LexicalErrorBoundary.tsx b/packages/lexical-react/src/LexicalErrorBoundary.tsx index 5eb59aa741a..5d463e7665f 100644 --- a/packages/lexical-react/src/LexicalErrorBoundary.tsx +++ b/packages/lexical-react/src/LexicalErrorBoundary.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import * as React from 'react'; import {ErrorBoundary as ReactErrorBoundary} from 'react-error-boundary'; diff --git a/packages/lexical-react/src/LexicalHashtagPlugin.ts b/packages/lexical-react/src/LexicalHashtagPlugin.ts index e4b64a9d51b..0f89717f764 100644 --- a/packages/lexical-react/src/LexicalHashtagPlugin.ts +++ b/packages/lexical-react/src/LexicalHashtagPlugin.ts @@ -7,6 +7,7 @@ */ import type {TextNode} from 'lexical'; +import type {JSX} from 'react'; import {$createHashtagNode, HashtagNode} from '@lexical/hashtag'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; diff --git a/packages/lexical-react/src/LexicalHorizontalRuleNode.tsx b/packages/lexical-react/src/LexicalHorizontalRuleNode.tsx index 19aae08faed..850b1eb5f25 100644 --- a/packages/lexical-react/src/LexicalHorizontalRuleNode.tsx +++ b/packages/lexical-react/src/LexicalHorizontalRuleNode.tsx @@ -16,6 +16,7 @@ import type { NodeKey, SerializedLexicalNode, } from 'lexical'; +import type {JSX} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalNodeSelection} from '@lexical/react/useLexicalNodeSelection'; @@ -53,17 +54,15 @@ function HorizontalRuleComponent({nodeKey}: {nodeKey: NodeKey}) { const deleteSelection = $getSelection(); if (isSelected && $isNodeSelection(deleteSelection)) { event.preventDefault(); - editor.update(() => { - deleteSelection.getNodes().forEach((node) => { - if ($isHorizontalRuleNode(node)) { - node.remove(); - } - }); + deleteSelection.getNodes().forEach((node) => { + if ($isHorizontalRuleNode(node)) { + node.remove(); + } }); } return false; }, - [editor, isSelected], + [isSelected], ); useEffect(() => { @@ -126,7 +125,7 @@ export class HorizontalRuleNode extends DecoratorNode { static importJSON( serializedNode: SerializedHorizontalRuleNode, ): HorizontalRuleNode { - return $createHorizontalRuleNode(); + return $createHorizontalRuleNode().updateFromJSON(serializedNode); } static importDOM(): DOMConversionMap | null { @@ -138,13 +137,6 @@ export class HorizontalRuleNode extends DecoratorNode { }; } - exportJSON(): SerializedLexicalNode { - return { - type: 'horizontalrule', - version: 1, - }; - } - exportDOM(): DOMExportOutput { return {element: document.createElement('hr')}; } diff --git a/packages/lexical-react/src/LexicalNestedComposer.tsx b/packages/lexical-react/src/LexicalNestedComposer.tsx index 8aa9326e429..cea1f2dcb23 100644 --- a/packages/lexical-react/src/LexicalNestedComposer.tsx +++ b/packages/lexical-react/src/LexicalNestedComposer.tsx @@ -8,6 +8,7 @@ import type {LexicalComposerContextType} from '@lexical/react/LexicalComposerContext'; import type {KlassConstructor, Transform} from 'lexical'; +import type {JSX} from 'react'; import {useCollaborationContext} from '@lexical/react/LexicalCollaborationContext'; import { diff --git a/packages/lexical-react/src/LexicalNodeMenuPlugin.tsx b/packages/lexical-react/src/LexicalNodeMenuPlugin.tsx index b8f685ad990..068ee9c9791 100644 --- a/packages/lexical-react/src/LexicalNodeMenuPlugin.tsx +++ b/packages/lexical-react/src/LexicalNodeMenuPlugin.tsx @@ -7,6 +7,7 @@ */ import type {MenuRenderFn, MenuResolution} from './shared/LexicalMenu'; +import type {JSX} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import { diff --git a/packages/lexical-react/src/LexicalPlainTextPlugin.tsx b/packages/lexical-react/src/LexicalPlainTextPlugin.tsx index 108e6aa1914..3b6e86aab04 100644 --- a/packages/lexical-react/src/LexicalPlainTextPlugin.tsx +++ b/packages/lexical-react/src/LexicalPlainTextPlugin.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalEditable} from '@lexical/react/useLexicalEditable'; import * as React from 'react'; diff --git a/packages/lexical-react/src/LexicalRichTextPlugin.tsx b/packages/lexical-react/src/LexicalRichTextPlugin.tsx index 40ce57544d5..2498c87f19f 100644 --- a/packages/lexical-react/src/LexicalRichTextPlugin.tsx +++ b/packages/lexical-react/src/LexicalRichTextPlugin.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {useLexicalEditable} from '@lexical/react/useLexicalEditable'; import * as React from 'react'; diff --git a/packages/lexical-react/src/LexicalTabIndentationPlugin.tsx b/packages/lexical-react/src/LexicalTabIndentationPlugin.tsx index db8c0e8a6e2..84025cc7472 100644 --- a/packages/lexical-react/src/LexicalTabIndentationPlugin.tsx +++ b/packages/lexical-react/src/LexicalTabIndentationPlugin.tsx @@ -9,13 +9,18 @@ import type {LexicalCommand, LexicalEditor, RangeSelection} from 'lexical'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; -import {$filter, $getNearestBlockElementAncestorOrThrow} from '@lexical/utils'; +import { + $filter, + $getNearestBlockElementAncestorOrThrow, + mergeRegister, +} from '@lexical/utils'; import { $createRangeSelection, $getSelection, $isBlockElementNode, $isRangeSelection, $normalizeSelection__EXPERIMENTAL, + COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_EDITOR, INDENT_CONTENT_COMMAND, INSERT_TAB_COMMAND, @@ -57,24 +62,51 @@ function $indentOverTab(selection: RangeSelection): boolean { return false; } -export function registerTabIndentation(editor: LexicalEditor) { - return editor.registerCommand( - KEY_TAB_COMMAND, - (event) => { - const selection = $getSelection(); - if (!$isRangeSelection(selection)) { - return false; - } +export function registerTabIndentation( + editor: LexicalEditor, + maxIndent?: number, +) { + return mergeRegister( + editor.registerCommand( + KEY_TAB_COMMAND, + (event) => { + const selection = $getSelection(); + if (!$isRangeSelection(selection)) { + return false; + } + event.preventDefault(); + const command: LexicalCommand = $indentOverTab(selection) + ? event.shiftKey + ? OUTDENT_CONTENT_COMMAND + : INDENT_CONTENT_COMMAND + : INSERT_TAB_COMMAND; + return editor.dispatchCommand(command, undefined); + }, + COMMAND_PRIORITY_EDITOR, + ), + + editor.registerCommand( + INDENT_CONTENT_COMMAND, + () => { + if (maxIndent == null) { + return false; + } + + const selection = $getSelection(); + if (!$isRangeSelection(selection)) { + return false; + } + + const indents = selection + .getNodes() + .map((node) => + $getNearestBlockElementAncestorOrThrow(node).getIndent(), + ); - event.preventDefault(); - const command: LexicalCommand = $indentOverTab(selection) - ? event.shiftKey - ? OUTDENT_CONTENT_COMMAND - : INDENT_CONTENT_COMMAND - : INSERT_TAB_COMMAND; - return editor.dispatchCommand(command, undefined); - }, - COMMAND_PRIORITY_EDITOR, + return Math.max(...indents) + 1 >= maxIndent; + }, + COMMAND_PRIORITY_CRITICAL, + ), ); } @@ -83,11 +115,11 @@ export function registerTabIndentation(editor: LexicalEditor) { * recommend using this plugin as it could negatively affect acessibility for keyboard * users, causing focus to become trapped within the editor. */ -export function TabIndentationPlugin(): null { +export function TabIndentationPlugin({maxIndent}: {maxIndent?: number}): null { const [editor] = useLexicalComposerContext(); useEffect(() => { - return registerTabIndentation(editor); - }, [editor]); + return registerTabIndentation(editor, maxIndent); + }, [editor, maxIndent]); return null; } diff --git a/packages/lexical-react/src/LexicalTableOfContentsPlugin.tsx b/packages/lexical-react/src/LexicalTableOfContentsPlugin.tsx index 86f280e0d44..e1da06d7df2 100644 --- a/packages/lexical-react/src/LexicalTableOfContentsPlugin.tsx +++ b/packages/lexical-react/src/LexicalTableOfContentsPlugin.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {$isHeadingNode, HeadingNode, HeadingTagType} from '@lexical/rich-text'; import {$getNextRightPreorderNode} from '@lexical/utils'; diff --git a/packages/lexical-react/src/LexicalTablePlugin.ts b/packages/lexical-react/src/LexicalTablePlugin.ts index 7d91b0b576c..2136adb2dbf 100644 --- a/packages/lexical-react/src/LexicalTablePlugin.ts +++ b/packages/lexical-react/src/LexicalTablePlugin.ts @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import { registerTableCellUnmergeTransform, diff --git a/packages/lexical-react/src/LexicalTreeView.tsx b/packages/lexical-react/src/LexicalTreeView.tsx index 1b7057b27ef..13b010e0a26 100644 --- a/packages/lexical-react/src/LexicalTreeView.tsx +++ b/packages/lexical-react/src/LexicalTreeView.tsx @@ -7,6 +7,7 @@ */ import type {EditorState, LexicalEditor} from 'lexical'; +import type {JSX} from 'react'; import { CustomPrintNodeFn, diff --git a/packages/lexical-react/src/LexicalTypeaheadMenuPlugin.tsx b/packages/lexical-react/src/LexicalTypeaheadMenuPlugin.tsx index da497dc9aad..9947b97a078 100644 --- a/packages/lexical-react/src/LexicalTypeaheadMenuPlugin.tsx +++ b/packages/lexical-react/src/LexicalTypeaheadMenuPlugin.tsx @@ -12,6 +12,7 @@ import type { MenuTextMatch, TriggerFn, } from './shared/LexicalMenu'; +import type {JSX} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import { diff --git a/packages/lexical-react/src/shared/LexicalContentEditableElement.tsx b/packages/lexical-react/src/shared/LexicalContentEditableElement.tsx index 64db5d1709b..099619f924e 100644 --- a/packages/lexical-react/src/shared/LexicalContentEditableElement.tsx +++ b/packages/lexical-react/src/shared/LexicalContentEditableElement.tsx @@ -7,6 +7,7 @@ */ import type {LexicalEditor} from 'lexical'; +import type {JSX} from 'react'; import * as React from 'react'; import {forwardRef, Ref, useCallback, useMemo, useState} from 'react'; diff --git a/packages/lexical-react/src/shared/LexicalMenu.ts b/packages/lexical-react/src/shared/LexicalMenu.ts index cda6ca3c5cb..29897b79832 100644 --- a/packages/lexical-react/src/shared/LexicalMenu.ts +++ b/packages/lexical-react/src/shared/LexicalMenu.ts @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {mergeRegister} from '@lexical/utils'; import { diff --git a/packages/lexical-react/src/shared/useDecorators.tsx b/packages/lexical-react/src/shared/useDecorators.tsx index e3c5a0715c5..aefda99d520 100644 --- a/packages/lexical-react/src/shared/useDecorators.tsx +++ b/packages/lexical-react/src/shared/useDecorators.tsx @@ -7,6 +7,7 @@ */ import type {LexicalEditor, NodeKey} from 'lexical'; +import type {JSX} from 'react'; import {Suspense, useEffect, useMemo, useState} from 'react'; import * as React from 'react'; diff --git a/packages/lexical-react/src/shared/useYjsCollaboration.tsx b/packages/lexical-react/src/shared/useYjsCollaboration.tsx index a8f4e49da17..b1928457f99 100644 --- a/packages/lexical-react/src/shared/useYjsCollaboration.tsx +++ b/packages/lexical-react/src/shared/useYjsCollaboration.tsx @@ -6,8 +6,9 @@ * */ -import type {Binding, Provider} from '@lexical/yjs'; +import type {Binding, Provider, SyncCursorPositionsFn} from '@lexical/yjs'; import type {LexicalEditor} from 'lexical'; +import type {JSX} from 'react'; import {mergeRegister} from '@lexical/utils'; import { @@ -54,6 +55,7 @@ export function useYjsCollaboration( cursorsContainerRef?: CursorsContainerRef, initialEditorState?: InitialEditorStateType, awarenessData?: object, + syncCursorPositionsFn: SyncCursorPositionsFn = syncCursorPositions, ): JSX.Element { const isReloadingDoc = useRef(false); @@ -90,7 +92,7 @@ export function useYjsCollaboration( }; const onAwarenessUpdate = () => { - syncCursorPositions(binding, provider); + syncCursorPositionsFn(binding, provider); }; const onYjsTreeChanges = ( @@ -102,7 +104,13 @@ export function useYjsCollaboration( const origin = transaction.origin; if (origin !== binding) { const isFromUndoManger = origin instanceof UndoManager; - syncYjsChangesToLexical(binding, provider, events, isFromUndoManger); + syncYjsChangesToLexical( + binding, + provider, + events, + isFromUndoManger, + syncCursorPositionsFn, + ); } }; @@ -191,6 +199,7 @@ export function useYjsCollaboration( shouldBootstrap, awarenessData, setDoc, + syncCursorPositionsFn, ]); const cursorsContainer = useMemo(() => { const ref = (element: null | HTMLElement) => { diff --git a/packages/lexical-rich-text/package.json b/packages/lexical-rich-text/package.json index aead90d4159..974a7268c26 100644 --- a/packages/lexical-rich-text/package.json +++ b/packages/lexical-rich-text/package.json @@ -7,7 +7,7 @@ "rich-text" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalRichText.js", "types": "index.d.ts", "repository": { @@ -35,9 +35,9 @@ } }, "dependencies": { - "@lexical/clipboard": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/clipboard": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" } } diff --git a/packages/lexical-rich-text/src/__tests__/unit/LexicalHeadingNode.test.ts b/packages/lexical-rich-text/src/__tests__/unit/LexicalHeadingNode.test.ts index 057999ba031..7cdede95c4f 100644 --- a/packages/lexical-rich-text/src/__tests__/unit/LexicalHeadingNode.test.ts +++ b/packages/lexical-rich-text/src/__tests__/unit/LexicalHeadingNode.test.ts @@ -74,13 +74,26 @@ describe('LexicalHeadingNode tests', () => { test('HeadingNode.updateDOM()', async () => { const {editor} = testEnv; await editor.update(() => { - const headingNode = new HeadingNode('h1'); + const headingNode = $createHeadingNode('h1'); const domElement = headingNode.createDOM(editorConfig); expect(domElement.outerHTML).toBe('

'); - const newHeadingNode = new HeadingNode('h2'); - const result = newHeadingNode.updateDOM(headingNode, domElement); + const newHeadingNode = $createHeadingNode('h1'); + const result = newHeadingNode.updateDOM( + headingNode, + domElement, + editor._config, + ); expect(result).toBe(false); expect(domElement.outerHTML).toBe('

'); + // When the HTML tag changes we must return true and not update the DOM, as createDOM will be called + const newTag = $createHeadingNode('h2'); + const newTagResult = newTag.updateDOM( + headingNode, + domElement, + editor._config, + ); + expect(newTagResult).toBe(true); + expect(domElement.outerHTML).toBe('

'); }); }); diff --git a/packages/lexical-rich-text/src/index.ts b/packages/lexical-rich-text/src/index.ts index 7e39f5631dd..3bc75ca6580 100644 --- a/packages/lexical-rich-text/src/index.ts +++ b/packages/lexical-rich-text/src/index.ts @@ -16,6 +16,7 @@ import type { LexicalCommand, LexicalEditor, LexicalNode, + LexicalUpdateJSON, NodeKey, ParagraphNode, PasteCommandType, @@ -128,10 +129,6 @@ export class QuoteNode extends ElementNode { return new QuoteNode(node.__key); } - constructor(key?: NodeKey) { - super(key); - } - // View createDOM(config: EditorConfig): HTMLElement { @@ -175,18 +172,7 @@ export class QuoteNode extends ElementNode { } static importJSON(serializedNode: SerializedQuoteNode): QuoteNode { - const node = $createQuoteNode(); - node.setFormat(serializedNode.format); - node.setIndent(serializedNode.indent); - node.setDirection(serializedNode.direction); - return node; - } - - exportJSON(): SerializedElementNode { - return { - ...super.exportJSON(), - type: 'quote', - }; + return $createQuoteNode().updateFromJSON(serializedNode); } // Mutation @@ -246,6 +232,12 @@ export class HeadingNode extends ElementNode { return this.__tag; } + setTag(tag: HeadingTagType): this { + const self = this.getWritable(); + this.__tag = tag; + return self; + } + // View createDOM(config: EditorConfig): HTMLElement { @@ -260,8 +252,8 @@ export class HeadingNode extends ElementNode { return element; } - updateDOM(prevNode: this, dom: HTMLElement): boolean { - return false; + updateDOM(prevNode: this, dom: HTMLElement, config: EditorConfig): boolean { + return prevNode.__tag !== this.__tag; } static importDOM(): DOMConversionMap | null { @@ -341,19 +333,21 @@ export class HeadingNode extends ElementNode { } static importJSON(serializedNode: SerializedHeadingNode): HeadingNode { - const node = $createHeadingNode(serializedNode.tag); - node.setFormat(serializedNode.format); - node.setIndent(serializedNode.indent); - node.setDirection(serializedNode.direction); - return node; + return $createHeadingNode(serializedNode.tag).updateFromJSON( + serializedNode, + ); + } + + updateFromJSON( + serializedNode: LexicalUpdateJSON, + ): this { + return super.updateFromJSON(serializedNode).setTag(serializedNode.tag); } exportJSON(): SerializedHeadingNode { return { ...super.exportJSON(), tag: this.getTag(), - type: 'heading', - version: 1, }; } @@ -435,7 +429,9 @@ function $convertBlockquoteElement(element: HTMLElement): DOMConversionOutput { return {node}; } -export function $createHeadingNode(headingTag: HeadingTagType): HeadingNode { +export function $createHeadingNode( + headingTag: HeadingTagType = 'h1', +): HeadingNode { return $applyNodeReplacement(new HeadingNode(headingTag)); } diff --git a/packages/lexical-selection/package.json b/packages/lexical-selection/package.json index 368cce030b4..282bbcbe28e 100644 --- a/packages/lexical-selection/package.json +++ b/packages/lexical-selection/package.json @@ -9,7 +9,7 @@ "selection" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalSelection.js", "types": "index.d.ts", "repository": { @@ -37,6 +37,6 @@ } }, "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } } diff --git a/packages/lexical-selection/src/__tests__/utils/index.ts b/packages/lexical-selection/src/__tests__/utils/index.ts index 84c82edecfa..ab9d80decec 100644 --- a/packages/lexical-selection/src/__tests__/utils/index.ts +++ b/packages/lexical-selection/src/__tests__/utils/index.ts @@ -890,10 +890,7 @@ export function $setAnchorPoint( return; } - const anchor = selection.anchor; - anchor.type = point.type; - anchor.offset = point.offset; - anchor.key = point.key; + selection.anchor.set(point.key, point.offset, point.type); } export function $setFocusPoint( @@ -911,8 +908,5 @@ export function $setFocusPoint( return; } - const focus = selection.focus; - focus.type = point.type; - focus.offset = point.offset; - focus.key = point.key; + selection.focus.set(point.key, point.offset, point.type); } diff --git a/packages/lexical-selection/src/index.ts b/packages/lexical-selection/src/index.ts index 8d9d47ce635..2fd6becf09b 100644 --- a/packages/lexical-selection/src/index.ts +++ b/packages/lexical-selection/src/index.ts @@ -8,6 +8,7 @@ import { $addNodeStyle, + $forEachSelectedTextNode, $isAtNodeEnd, $patchStyleText, $sliceSelectedTextNodeContent, @@ -36,6 +37,7 @@ export { export { $addNodeStyle, + $forEachSelectedTextNode, $isAtNodeEnd, $patchStyleText, $sliceSelectedTextNodeContent, diff --git a/packages/lexical-selection/src/lexical-node.ts b/packages/lexical-selection/src/lexical-node.ts index 32b7b0b802e..22074d1fd6e 100644 --- a/packages/lexical-selection/src/lexical-node.ts +++ b/packages/lexical-selection/src/lexical-node.ts @@ -10,6 +10,7 @@ import { $getCharacterOffsets, $getNodeByKey, $getPreviousSelection, + $getSelection, $isElementNode, $isRangeSelection, $isRootNode, @@ -288,23 +289,30 @@ export function $patchStyleText( ) => string) >, ): void { - const selectedNodes = selection.getNodes(); - const selectedNodesLength = selectedNodes.length; - const anchorAndFocus = selection.getStartEndPoints(); - if (anchorAndFocus === null) { + if (selection.isCollapsed() && $isRangeSelection(selection)) { + $patchStyle(selection, patch); + } else { + $forEachSelectedTextNode((textNode) => { + $patchStyle(textNode, patch); + }); + } +} + +export function $forEachSelectedTextNode( + fn: (textNode: TextNode) => void, +): void { + const selection = $getSelection(); + if (!$isRangeSelection(selection)) { return; } - const [anchor, focus] = anchorAndFocus; + const selectedNodes = selection.getNodes(); + const selectedNodesLength = selectedNodes.length; + const {anchor, focus} = selection; const lastIndex = selectedNodesLength - 1; let firstNode = selectedNodes[0]; let lastNode = selectedNodes[lastIndex]; - if (selection.isCollapsed() && $isRangeSelection(selection)) { - $patchStyle(selection, patch); - return; - } - const firstNodeText = firstNode.getTextContent(); const firstNodeTextLength = firstNodeText.length; const focusOffset = focus.offset; @@ -355,14 +363,14 @@ export function $patchStyleText( $isTokenOrSegmented(firstNode) || (startOffset === 0 && endOffset === firstNodeTextLength) ) { - $patchStyle(firstNode, patch); + fn(firstNode); firstNode.select(startOffset, endOffset); } else { // The node is partially selected, so split it into two nodes // and style the selected one. const splitNodes = firstNode.splitText(startOffset, endOffset); const replacement = startOffset === 0 ? splitNodes[0] : splitNodes[1]; - $patchStyle(replacement, patch); + fn(replacement); replacement.select(0, endOffset - startOffset); } } // multiple nodes selected. @@ -383,7 +391,7 @@ export function $patchStyleText( } } - $patchStyle(firstNode as TextNode, patch); + fn(firstNode as TextNode); } if ($isTextNode(lastNode) && lastNode.canHaveFormat()) { @@ -404,7 +412,7 @@ export function $patchStyleText( } if (endOffset !== 0 || endType === 'element') { - $patchStyle(lastNode as TextNode, patch); + fn(lastNode as TextNode); } } @@ -420,7 +428,7 @@ export function $patchStyleText( selectedNodeKey !== lastNode.getKey() && !selectedNode.isToken() ) { - $patchStyle(selectedNode, patch); + fn(selectedNode as TextNode); } } } diff --git a/packages/lexical-selection/src/range-selection.ts b/packages/lexical-selection/src/range-selection.ts index 15b4e66c5c7..6dc33ca750a 100644 --- a/packages/lexical-selection/src/range-selection.ts +++ b/packages/lexical-selection/src/range-selection.ts @@ -21,16 +21,17 @@ import { $getAdjacentNode, $getPreviousSelection, $getRoot, + $getSelection, $hasAncestor, $isDecoratorNode, $isElementNode, $isLeafNode, - $isLineBreakNode, $isRangeSelection, $isRootNode, $isRootOrShadowRoot, $isTextNode, $setSelection, + INTERNAL_$isBlock, } from 'lexical'; import invariant from 'shared/invariant'; @@ -50,6 +51,8 @@ export function $setBlocksType( } const anchorAndFocus = selection.getStartEndPoints(); const anchor = anchorAndFocus ? anchorAndFocus[0] : null; + const isCollapsedSelection = + selection.is($getSelection()) && selection.isCollapsed(); if (anchor !== null && anchor.key === 'root') { const element = createElement(); @@ -61,29 +64,33 @@ export function $setBlocksType( } else { root.append(element); } - + if (isCollapsedSelection) { + element.select(); + } return; } - const nodes = selection.getNodes(); - const firstSelectedBlock = - anchor !== null ? $getAncestor(anchor.getNode(), INTERNAL_$isBlock) : false; - if (firstSelectedBlock && nodes.indexOf(firstSelectedBlock) === -1) { + const nodes = selection + .getNodes() + .filter(INTERNAL_$isBlock) + .filter($isElementNode); + const firstSelectedBlock = anchor + ? $getAncestor(anchor.getNode(), INTERNAL_$isBlock) + : null; + if ( + $isElementNode(firstSelectedBlock) && + !nodes.find((node) => node.is(firstSelectedBlock)) + ) { nodes.push(firstSelectedBlock); } - - for (let i = 0; i < nodes.length; i++) { - const node = nodes[i]; - - if (!INTERNAL_$isBlock(node)) { - continue; - } - invariant($isElementNode(node), 'Expected block node to be an ElementNode'); - + for (const node of nodes) { const targetElement = createElement(); targetElement.setFormat(node.getFormatType()); targetElement.setIndent(node.getIndent()); node.replace(targetElement, true); + if (node.is(firstSelectedBlock) && isCollapsedSelection) { + targetElement.select(); + } } } @@ -539,28 +546,6 @@ export function $getSelectionStyleValueForProperty( return styleValue === null ? defaultValue : styleValue; } -/** - * This function is for internal use of the library. - * Please do not use it as it may change in the future. - */ -export function INTERNAL_$isBlock(node: LexicalNode): node is ElementNode { - if ($isDecoratorNode(node)) { - return false; - } - if (!$isElementNode(node) || $isRootOrShadowRoot(node)) { - return false; - } - - const firstChild = node.getFirstChild(); - const isLeafElement = - firstChild === null || - $isLineBreakNode(firstChild) || - $isTextNode(firstChild) || - firstChild.isInline(); - - return !node.isInline() && node.canBeEmpty() !== false && isLeafElement; -} - export function $getAncestor( node: LexicalNode, predicate: (ancestor: LexicalNode) => ancestor is NodeType, diff --git a/packages/lexical-table/package.json b/packages/lexical-table/package.json index c112513f792..bf36cfcebf1 100644 --- a/packages/lexical-table/package.json +++ b/packages/lexical-table/package.json @@ -8,13 +8,13 @@ "table" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalTable.js", "types": "index.d.ts", "dependencies": { - "@lexical/clipboard": "0.21.0", - "@lexical/utils": "0.21.0", - "lexical": "0.21.0" + "@lexical/clipboard": "0.23.1", + "@lexical/utils": "0.23.1", + "lexical": "0.23.1" }, "repository": { "type": "git", diff --git a/packages/lexical-table/src/LexicalTableCellNode.ts b/packages/lexical-table/src/LexicalTableCellNode.ts index 396fc6564d7..85f282e07be 100644 --- a/packages/lexical-table/src/LexicalTableCellNode.ts +++ b/packages/lexical-table/src/LexicalTableCellNode.ts @@ -13,6 +13,7 @@ import type { EditorConfig, LexicalEditor, LexicalNode, + LexicalUpdateJSON, NodeKey, SerializedElementNode, Spread, @@ -61,7 +62,7 @@ export class TableCellNode extends ElementNode { /** @internal */ __headerState: TableCellHeaderState; /** @internal */ - __width?: number; + __width?: number | undefined; /** @internal */ __backgroundColor: null | string; @@ -98,14 +99,18 @@ export class TableCellNode extends ElementNode { } static importJSON(serializedNode: SerializedTableCellNode): TableCellNode { - const colSpan = serializedNode.colSpan || 1; - const rowSpan = serializedNode.rowSpan || 1; - return $createTableCellNode( - serializedNode.headerState, - colSpan, - serializedNode.width || undefined, - ) - .setRowSpan(rowSpan) + return $createTableCellNode().updateFromJSON(serializedNode); + } + + updateFromJSON( + serializedNode: LexicalUpdateJSON, + ): this { + return super + .updateFromJSON(serializedNode) + .setHeaderStyles(serializedNode.headerState) + .setColSpan(serializedNode.colSpan || 1) + .setRowSpan(serializedNode.rowSpan || 1) + .setWidth(serializedNode.width || undefined) .setBackgroundColor(serializedNode.backgroundColor || null); } @@ -183,7 +188,6 @@ export class TableCellNode extends ElementNode { colSpan: this.__colSpan, headerState: this.__headerState, rowSpan: this.__rowSpan, - type: 'tablecell', width: this.getWidth(), }; } @@ -225,7 +229,7 @@ export class TableCellNode extends ElementNode { return this.getLatest().__headerState; } - setWidth(width: number): this { + setWidth(width: number | undefined): this { const self = this.getWritable(); self.__width = width; return self; diff --git a/packages/lexical-table/src/LexicalTableNode.ts b/packages/lexical-table/src/LexicalTableNode.ts index fa7aa3d4d04..1069c072e7b 100644 --- a/packages/lexical-table/src/LexicalTableNode.ts +++ b/packages/lexical-table/src/LexicalTableNode.ts @@ -22,9 +22,11 @@ import { DOMExportOutput, EditorConfig, ElementDOMSlot, + type ElementFormatType, ElementNode, LexicalEditor, LexicalNode, + LexicalUpdateJSON, NodeKey, SerializedElementNode, setDOMUnmanaged, @@ -76,7 +78,7 @@ function setRowStriping( dom: HTMLElement, config: EditorConfig, rowStriping: boolean, -) { +): void { if (rowStriping) { addClassNamesToElement(dom, config.theme.tableRowStriping); dom.setAttribute('data-lexical-row-striping', 'true'); @@ -86,6 +88,27 @@ function setRowStriping( } } +function alignTableElement( + dom: HTMLElement, + config: EditorConfig, + formatType: ElementFormatType, +): void { + if (!config.theme.tableAlignment) { + return; + } + const removeClasses: string[] = []; + const addClasses: string[] = []; + for (const format of ['center', 'right'] as const) { + const classes = config.theme.tableAlignment[format]; + if (!classes) { + continue; + } + (format === formatType ? addClasses : removeClasses).push(classes); + } + removeClassNamesFromElement(dom, ...removeClasses); + addClassNamesToElement(dom, ...addClasses); +} + const scrollableEditors = new WeakSet(); export function $isScrollableTablesActive( @@ -114,21 +137,22 @@ export function setScrollableTablesActive( export class TableNode extends ElementNode { /** @internal */ __rowStriping: boolean; - __colWidths?: number[] | readonly number[]; + __colWidths?: readonly number[]; static getType(): string { return 'table'; } - getColWidths(): number[] | readonly number[] | undefined { + getColWidths(): readonly number[] | undefined { const self = this.getLatest(); return self.__colWidths; } - setColWidths(colWidths: readonly number[]): this { + setColWidths(colWidths: readonly number[] | undefined): this { const self = this.getWritable(); // NOTE: Node properties should be immutable. Freeze to prevent accidental mutation. - self.__colWidths = __DEV__ ? Object.freeze(colWidths) : colWidths; + self.__colWidths = + colWidths !== undefined && __DEV__ ? Object.freeze(colWidths) : colWidths; return self; } @@ -152,10 +176,14 @@ export class TableNode extends ElementNode { } static importJSON(serializedNode: SerializedTableNode): TableNode { - const tableNode = $createTableNode(); - tableNode.__rowStriping = serializedNode.rowStriping || false; - tableNode.__colWidths = serializedNode.colWidths; - return tableNode; + return $createTableNode().updateFromJSON(serializedNode); + } + + updateFromJSON(serializedNode: LexicalUpdateJSON): this { + return super + .updateFromJSON(serializedNode) + .setRowStriping(serializedNode.rowStriping || false) + .setColWidths(serializedNode.colWidths); } constructor(key?: NodeKey) { @@ -168,8 +196,6 @@ export class TableNode extends ElementNode { ...super.exportJSON(), colWidths: this.getColWidths(), rowStriping: this.__rowStriping ? this.__rowStriping : undefined, - type: 'table', - version: 1, }; } @@ -207,6 +233,7 @@ export class TableNode extends ElementNode { setDOMUnmanaged(colGroup); addClassNamesToElement(tableElement, config.theme.table); + alignTableElement(tableElement, config, this.getFormatType()); if (this.__rowStriping) { setRowStriping(tableElement, config, true); } @@ -230,6 +257,11 @@ export class TableNode extends ElementNode { setRowStriping(dom, config, this.__rowStriping); } updateColgroup(dom, config, this.getColumnCount(), this.getColWidths()); + alignTableElement( + this.getDOMSlot(dom).element, + config, + this.getFormatType(), + ); return false; } @@ -240,6 +272,13 @@ export class TableNode extends ElementNode { after: (tableElement) => { if (superExport.after) { tableElement = superExport.after(tableElement); + if (this.__format) { + alignTableElement( + tableElement as HTMLElement, + editor._config, + this.getFormatType(), + ); + } } if (isHTMLElement(tableElement) && tableElement.nodeName !== 'TABLE') { tableElement = tableElement.querySelector('table'); @@ -427,8 +466,10 @@ export class TableNode extends ElementNode { return Boolean(this.getLatest().__rowStriping); } - setRowStriping(newRowStriping: boolean): void { - this.getWritable().__rowStriping = newRowStriping; + setRowStriping(newRowStriping: boolean): this { + const self = this.getWritable(); + self.__rowStriping = newRowStriping; + return self; } canSelectBefore(): true { diff --git a/packages/lexical-table/src/LexicalTableObserver.ts b/packages/lexical-table/src/LexicalTableObserver.ts index 2f76ce0712a..3dc2a77b1e6 100644 --- a/packages/lexical-table/src/LexicalTableObserver.ts +++ b/packages/lexical-table/src/LexicalTableObserver.ts @@ -18,7 +18,6 @@ import { $createTextNode, $getEditor, $getNodeByKey, - $getRoot, $getSelection, $isElementNode, $isParagraphNode, @@ -470,8 +469,6 @@ export class TableObserver { tableNode.selectPrevious(); // Delete entire table tableNode.remove(); - const rootNode = $getRoot(); - rootNode.selectStart(); return; } diff --git a/packages/lexical-table/src/LexicalTableRowNode.ts b/packages/lexical-table/src/LexicalTableRowNode.ts index 4e216b865df..6d5fe6ae542 100644 --- a/packages/lexical-table/src/LexicalTableRowNode.ts +++ b/packages/lexical-table/src/LexicalTableRowNode.ts @@ -6,7 +6,7 @@ * */ -import type {BaseSelection, Spread} from 'lexical'; +import type {BaseSelection, LexicalUpdateJSON, Spread} from 'lexical'; import {$descendantsMatching, addClassNamesToElement} from '@lexical/utils'; import { @@ -53,7 +53,15 @@ export class TableRowNode extends ElementNode { } static importJSON(serializedNode: SerializedTableRowNode): TableRowNode { - return $createTableRowNode(serializedNode.height); + return $createTableRowNode().updateFromJSON(serializedNode); + } + + updateFromJSON( + serializedNode: LexicalUpdateJSON, + ): this { + return super + .updateFromJSON(serializedNode) + .setHeight(serializedNode.height); } constructor(height?: number, key?: NodeKey) { @@ -62,11 +70,10 @@ export class TableRowNode extends ElementNode { } exportJSON(): SerializedTableRowNode { + const height = this.getHeight(); return { ...super.exportJSON(), - ...(this.getHeight() && {height: this.getHeight()}), - type: 'tablerow', - version: 1, + ...(height === undefined ? undefined : {height}), }; } @@ -94,10 +101,10 @@ export class TableRowNode extends ElementNode { return true; } - setHeight(height: number): number | null | undefined { + setHeight(height?: number | undefined): this { const self = this.getWritable(); self.__height = height; - return this.__height; + return self; } getHeight(): number | undefined { diff --git a/packages/lexical-table/src/LexicalTableSelectionHelpers.ts b/packages/lexical-table/src/LexicalTableSelectionHelpers.ts index 5d010cc0bc2..2aadd81723c 100644 --- a/packages/lexical-table/src/LexicalTableSelectionHelpers.ts +++ b/packages/lexical-table/src/LexicalTableSelectionHelpers.ts @@ -456,6 +456,10 @@ export function applyTableHandlers( return false; } + if (!$isSelectionInTable(selection, tableNode)) { + return false; + } + if ($isTableSelection(selection)) { if (event) { event.preventDefault(); @@ -559,6 +563,12 @@ export function applyTableHandlers( return false; } + // Align the table if the entire table is selected + if ($isFullTableSelection(selection, tableNode)) { + tableNode.setFormat(formatType); + return true; + } + const [tableMap, anchorCell, focusCell] = $computeTableMap( tableNode, anchorNode, @@ -1576,6 +1586,24 @@ function $isSelectionInTable( return false; } +function $isFullTableSelection( + selection: null | BaseSelection, + tableNode: TableNode, +): boolean { + if ($isTableSelection(selection)) { + const anchorNode = selection.anchor.getNode() as TableCellNode; + const focusNode = selection.focus.getNode() as TableCellNode; + if (tableNode && anchorNode && focusNode) { + const [map] = $computeTableMap(tableNode, anchorNode, focusNode); + return ( + anchorNode.getKey() === map[0][0].cell.getKey() && + focusNode.getKey() === map[map.length - 1].at(-1)!.cell.getKey() + ); + } + } + return false; +} + function selectTableCellNode(tableCell: TableCellNode, fromStart: boolean) { if (fromStart) { tableCell.selectStart(); diff --git a/packages/lexical-table/src/LexicalTableUtils.ts b/packages/lexical-table/src/LexicalTableUtils.ts index 84e4ab3f5a7..b3d148ed238 100644 --- a/packages/lexical-table/src/LexicalTableUtils.ts +++ b/packages/lexical-table/src/LexicalTableUtils.ts @@ -856,6 +856,7 @@ export function $computeTableMapSkipCellCheck( $isTableRowNode(row), 'Expected TableNode children to be TableRowNode', ); + const startMapRow = getMapRow(rowIdx); for ( let cell = row.getFirstChild(), colIdx = 0; cell != null; @@ -866,7 +867,6 @@ export function $computeTableMapSkipCellCheck( 'Expected TableRowNode children to be TableCellNode', ); // Skip past any columns that were merged from a higher row - const startMapRow = getMapRow(rowIdx); while (startMapRow[colIdx] !== undefined) { colIdx++; } diff --git a/packages/lexical-table/src/__tests__/unit/LexicalTableNode.test.tsx b/packages/lexical-table/src/__tests__/unit/LexicalTableNode.test.tsx index c5f208c51f8..136516733f2 100644 --- a/packages/lexical-table/src/__tests__/unit/LexicalTableNode.test.tsx +++ b/packages/lexical-table/src/__tests__/unit/LexicalTableNode.test.tsx @@ -73,6 +73,10 @@ const editorConfig = Object.freeze({ namespace: '', theme: { table: 'test-table-class', + tableAlignment: { + center: 'test-table-alignment-center', + right: 'test-table-alignment-right', + }, tableRowStriping: 'test-table-row-striping-class', tableScrollableWrapper: 'table-scrollable-wrapper', }, @@ -1040,6 +1044,69 @@ describe('LexicalTableNode tests', () => { }); }); + test('Change Table-level alignment', async () => { + const {editor} = testEnv; + + await editor.update(() => { + const root = $getRoot(); + const table = $createTableNodeWithDimensions(4, 4, true); + root.append(table); + }); + await editor.update(() => { + const root = $getRoot(); + const table = root.getLastChild(); + if (table) { + table.setFormat('center'); + } + }); + + await editor.update(() => { + const root = $getRoot(); + const table = root.getLastChild(); + expectTableHtmlToBeEqual( + table!.createDOM(editorConfig).outerHTML, + html` + + + + + + + +
+ `, + ); + }); + + await editor.update(() => { + const root = $getRoot(); + const table = root.getLastChild(); + if (table) { + table.setFormat('left'); + } + }); + + await editor.update(() => { + const root = $getRoot(); + const table = root.getLastChild(); + expectTableHtmlToBeEqual( + table!.createDOM(editorConfig).outerHTML, + html` + + + + + + + +
+ `, + ); + }); + }); + test('Update column widths', async () => { const {editor} = testEnv; diff --git a/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx b/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx index cd95aca65bc..dace11e3e0a 100644 --- a/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx +++ b/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx @@ -135,6 +135,8 @@ describe('table selection', () => { __prev: null, __size: 1, __style: '', + __textFormat: 0, + __textStyle: '', __type: 'root', }); expect(parsedParagraph).toEqual({ diff --git a/packages/lexical-text/package.json b/packages/lexical-text/package.json index 28f28996d11..3579057f588 100644 --- a/packages/lexical-text/package.json +++ b/packages/lexical-text/package.json @@ -9,7 +9,7 @@ "text" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalText.js", "types": "index.d.ts", "repository": { @@ -37,6 +37,6 @@ } }, "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" } } diff --git a/packages/lexical-utils/package.json b/packages/lexical-utils/package.json index 1119cc3c614..33381e24b08 100644 --- a/packages/lexical-utils/package.json +++ b/packages/lexical-utils/package.json @@ -8,14 +8,14 @@ "utils" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalUtils.js", "types": "index.d.ts", "dependencies": { - "@lexical/list": "0.21.0", - "@lexical/selection": "0.21.0", - "@lexical/table": "0.21.0", - "lexical": "0.21.0" + "@lexical/list": "0.23.1", + "@lexical/selection": "0.23.1", + "@lexical/table": "0.23.1", + "lexical": "0.23.1" }, "repository": { "type": "git", diff --git a/packages/lexical-utils/src/__tests__/unit/LexicalNodeHelpers.test.ts b/packages/lexical-utils/src/__tests__/unit/LexicalNodeHelpers.test.ts index 40fab2f26bc..dcd8f52f6de 100644 --- a/packages/lexical-utils/src/__tests__/unit/LexicalNodeHelpers.test.ts +++ b/packages/lexical-utils/src/__tests__/unit/LexicalNodeHelpers.test.ts @@ -12,7 +12,9 @@ import { $getNodeByKey, $getRoot, $isElementNode, + ElementNode, LexicalEditor, + LexicalNode, NodeKey, } from 'lexical'; import { @@ -21,132 +23,231 @@ import { invariant, } from 'lexical/src/__tests__/utils'; -import {$dfs, $getNextSiblingOrParentSibling} from '../..'; +import { + $dfs, + $firstToLastIterator, + $getNextSiblingOrParentSibling, + $lastToFirstIterator, + $reverseDfs, +} from '../..'; + +interface DFSKeyPair { + depth: number; + node: NodeKey; +} describe('LexicalNodeHelpers tests', () => { initializeUnitTest((testEnv) => { - /** - * R - * P1 P2 - * B1 B2 T4 T5 B3 - * T1 T2 T3 T6 - * - * DFS: R, P1, B1, T1, B2, T2, T3, P2, T4, T5, B3, T6 - */ - test('DFS node order', async () => { - const editor: LexicalEditor = testEnv.editor; + describe('dfs order', () => { + let expectedKeys: DFSKeyPair[]; + let reverseExpectedKeys: DFSKeyPair[]; + + /** + * R + * P1 P2 + * B1 B2 T4 T5 B3 + * T1 T2 T3 T6 + * + * DFS: R, P1, B1, T1, B2, T2, T3, P2, T4, T5, B3, T6 + * + * Reverse DFS: R, P2, B3, T6, T5, T4, P1, B2, T3, T2, B1, T1 + */ + beforeEach(async () => { + const editor: LexicalEditor = testEnv.editor; + await editor.update(() => { + const root = $getRoot(); + + const paragraph1 = $createParagraphNode(); + const paragraph2 = $createParagraphNode(); + + const block1 = $createTestElementNode(); + const block2 = $createTestElementNode(); + const block3 = $createTestElementNode(); + + const text1 = $createTextNode('text1'); + const text2 = $createTextNode('text2'); + const text3 = $createTextNode('text3'); + const text4 = $createTextNode('text4'); + const text5 = $createTextNode('text5'); + const text6 = $createTextNode('text6'); + + root.append(paragraph1, paragraph2); + paragraph1.append(block1, block2); + paragraph2.append(text4, text5); + + text5.toggleFormat('bold'); // Prevent from merging with text 4 + + paragraph2.append(block3); + block1.append(text1); + block2.append(text2, text3); + + text3.toggleFormat('bold'); // Prevent from merging with text2 + + block3.append(text6); + + function* keysForNode( + depth: number, + node: LexicalNode, + $getChildren: (element: ElementNode) => Iterable, + ): Iterable { + yield {depth, node: node.getKey()}; + if ($isElementNode(node)) { + const childDepth = depth + 1; + for (const child of $getChildren(node)) { + yield* keysForNode(childDepth, child, $getChildren); + } + } + } + + expectedKeys = [...keysForNode(0, root, $firstToLastIterator)]; + reverseExpectedKeys = [...keysForNode(0, root, $lastToFirstIterator)]; + // R, P1, B1, T1, B2, T2, T3, P2, T4, T5, B3, T6 + expect(expectedKeys).toEqual( + [ + root, + paragraph1, + block1, + text1, + block2, + text2, + text3, + paragraph2, + text4, + text5, + block3, + text6, + ].map((n) => ({depth: n.getParentKeys().length, node: n.getKey()})), + ); + // R, P2, B3, T6, T5, T4, P1, B2, T3, T2, B1, T1 + expect(reverseExpectedKeys).toEqual( + [ + root, + paragraph2, + block3, + text6, + text5, + text4, + paragraph1, + block2, + text3, + text2, + block1, + text1, + ].map((n) => ({depth: n.getParentKeys().length, node: n.getKey()})), + ); + }); + }); + + test('DFS node order', async () => { + const editor: LexicalEditor = testEnv.editor; + editor.getEditorState().read(() => { + const expectedNodes = expectedKeys.map(({depth, node: nodeKey}) => ({ + depth, + node: $getNodeByKey(nodeKey)!.getLatest(), + })); + + const first = expectedNodes[0]; + const second = expectedNodes[1]; + const last = expectedNodes[expectedNodes.length - 1]; + const secondToLast = expectedNodes[expectedNodes.length - 2]; + + expect($dfs(first.node, last.node)).toEqual(expectedNodes); + expect($dfs(second.node, secondToLast.node)).toEqual( + expectedNodes.slice(1, expectedNodes.length - 1), + ); + expect($dfs()).toEqual(expectedNodes); + expect($dfs($getRoot())).toEqual(expectedNodes); + }); + }); - let expectedKeys: Array<{ - depth: number; - node: NodeKey; - }> = []; + test('Reverse DFS node order', async () => { + const editor: LexicalEditor = testEnv.editor; + editor.getEditorState().read(() => { + const expectedNodes = reverseExpectedKeys.map( + ({depth, node: nodeKey}) => ({ + depth, + node: $getNodeByKey(nodeKey)!.getLatest(), + }), + ); + + const first = expectedNodes[0]; + const second = expectedNodes[1]; + const last = expectedNodes[expectedNodes.length - 1]; + const secondToLast = expectedNodes[expectedNodes.length - 2]; + + expect($reverseDfs(first.node, last.node)).toEqual(expectedNodes); + expect($reverseDfs(second.node, secondToLast.node)).toEqual( + expectedNodes.slice(1, expectedNodes.length - 1), + ); + expect($reverseDfs()).toEqual(expectedNodes); + expect($reverseDfs($getRoot())).toEqual(expectedNodes); + }); + }); + }); + + test('DFS triggers getLatest()', async () => { + const editor: LexicalEditor = testEnv.editor; + let rootKey: string; + let paragraphKey: string; + let block1Key: string; + let block2Key: string; await editor.update(() => { const root = $getRoot(); - const paragraph1 = $createParagraphNode(); - const paragraph2 = $createParagraphNode(); - + const paragraph = $createParagraphNode(); const block1 = $createTestElementNode(); const block2 = $createTestElementNode(); - const block3 = $createTestElementNode(); - const text1 = $createTextNode('text1'); - const text2 = $createTextNode('text2'); - const text3 = $createTextNode('text3'); - const text4 = $createTextNode('text4'); - const text5 = $createTextNode('text5'); - const text6 = $createTextNode('text6'); - - root.append(paragraph1, paragraph2); - paragraph1.append(block1, block2); - paragraph2.append(text4, text5); + rootKey = root.getKey(); + paragraphKey = paragraph.getKey(); + block1Key = block1.getKey(); + block2Key = block2.getKey(); - text5.toggleFormat('bold'); // Prevent from merging with text 4 + root.append(paragraph); + paragraph.append(block1, block2); + }); - paragraph2.append(block3); - block1.append(text1); - block2.append(text2, text3); + await editor.update(() => { + const root = $getNodeByKey(rootKey); + const paragraph = $getNodeByKey(paragraphKey); + const block1 = $getNodeByKey(block1Key); + const block2 = $getNodeByKey(block2Key); - text3.toggleFormat('bold'); // Prevent from merging with text2 + const block3 = $createTestElementNode(); + invariant($isElementNode(block1)); - block3.append(text6); + // this will (only) change the latest state of block1 + // all other nodes will be the same version + block1.append(block3); - expectedKeys = [ + expect($dfs(root!)).toEqual([ { depth: 0, - node: root.getKey(), + node: root!.getLatest(), }, { depth: 1, - node: paragraph1.getKey(), - }, - { - depth: 2, - node: block1.getKey(), - }, - { - depth: 3, - node: text1.getKey(), + node: paragraph!.getLatest(), }, { depth: 2, - node: block2.getKey(), - }, - { - depth: 3, - node: text2.getKey(), + node: block1.getLatest(), }, { depth: 3, - node: text3.getKey(), - }, - { - depth: 1, - node: paragraph2.getKey(), - }, - { - depth: 2, - node: text4.getKey(), - }, - { - depth: 2, - node: text5.getKey(), + node: block3.getLatest(), }, { depth: 2, - node: block3.getKey(), - }, - { - depth: 3, - node: text6.getKey(), + node: block2!.getLatest(), }, - ]; - }); - - editor.getEditorState().read(() => { - const expectedNodes = expectedKeys.map(({depth, node: nodeKey}) => ({ - depth, - node: $getNodeByKey(nodeKey)!.getLatest(), - })); - - const first = expectedNodes[0]; - const second = expectedNodes[1]; - const last = expectedNodes[expectedNodes.length - 1]; - const secondToLast = expectedNodes[expectedNodes.length - 2]; - - expect($dfs(first.node, last.node)).toEqual(expectedNodes); - expect($dfs(second.node, secondToLast.node)).toEqual( - expectedNodes.slice(1, expectedNodes.length - 1), - ); - expect($dfs()).toEqual(expectedNodes); - expect($dfs($getRoot())).toEqual(expectedNodes); + ]); }); }); - test('DFS triggers getLatest()', async () => { + test('reverse DFS triggers getLatest()', async () => { const editor: LexicalEditor = testEnv.editor; - let rootKey: string; let paragraphKey: string; let block1Key: string; @@ -177,9 +278,11 @@ describe('LexicalNodeHelpers tests', () => { const block3 = $createTestElementNode(); invariant($isElementNode(block1)); + // this will (only) change the latest state of block1 + // all other nodes will be the same version block1.append(block3); - expect($dfs(root!)).toEqual([ + expect($reverseDfs()).toEqual([ { depth: 0, node: root!.getLatest(), @@ -188,6 +291,10 @@ describe('LexicalNodeHelpers tests', () => { depth: 1, node: paragraph!.getLatest(), }, + { + depth: 2, + node: block2!.getLatest(), + }, { depth: 2, node: block1.getLatest(), @@ -196,17 +303,12 @@ describe('LexicalNodeHelpers tests', () => { depth: 3, node: block3.getLatest(), }, - { - depth: 2, - node: block2!.getLatest(), - }, ]); }); }); test('DFS of empty ParagraphNode returns only itself', async () => { const editor: LexicalEditor = testEnv.editor; - let paragraphKey: string; await editor.update(() => { @@ -233,9 +335,49 @@ describe('LexicalNodeHelpers tests', () => { }); }); - test('$getNextSiblingOrParentSibling', async () => { + test('reverse DFS of empty ParagraphNode returns only itself', async () => { const editor: LexicalEditor = testEnv.editor; + let paragraphKey: string; + + await editor.update(() => { + const root = $getRoot(); + + const paragraph = $createParagraphNode(); + const paragraph2 = $createParagraphNode(); + const text = $createTextNode('test'); + paragraphKey = paragraph.getKey(); + + paragraph2.append(text); + root.append(paragraph, paragraph2); + }); + await editor.update(() => { + const paragraph = $getNodeByKey(paragraphKey)!; + + expect($reverseDfs(paragraph, paragraph)).toEqual([ + { + depth: 1, + node: paragraph?.getLatest(), + }, + ]); + }); + }); + + test('reverse DFS of empty RootNode returns only itself', async () => { + const editor: LexicalEditor = testEnv.editor; + + await editor.update(() => { + expect($reverseDfs()).toEqual([ + { + depth: 0, + node: $getRoot().getLatest(), + }, + ]); + }); + }); + + test('$getNextSiblingOrParentSibling', async () => { + const editor: LexicalEditor = testEnv.editor; await editor.update(() => { const root = $getRoot(); const paragraph = $createParagraphNode(); diff --git a/packages/lexical-utils/src/__tests__/unit/LexicalUtilsInsertNodeToNearestRoot.test.tsx b/packages/lexical-utils/src/__tests__/unit/LexicalUtilsInsertNodeToNearestRoot.test.tsx index 0e46573e7f6..51902c01532 100644 --- a/packages/lexical-utils/src/__tests__/unit/LexicalUtilsInsertNodeToNearestRoot.test.tsx +++ b/packages/lexical-utils/src/__tests__/unit/LexicalUtilsInsertNodeToNearestRoot.test.tsx @@ -163,10 +163,16 @@ describe('LexicalUtils#insertNodeToNearestRoot', () => { // to use whatever was passed (e.g. keep selection on root node) const selection = $createRangeSelection(); const type = $isElementNode(selectionNode) ? 'element' : 'text'; - selection.anchor.key = selection.focus.key = selectionNode.getKey(); - selection.anchor.offset = selection.focus.offset = - testCase.selectionOffset; - selection.anchor.type = selection.focus.type = type; + selection.anchor.set( + selectionNode.getKey(), + testCase.selectionOffset, + type, + ); + selection.focus.set( + selectionNode.getKey(), + testCase.selectionOffset, + type, + ); $setSelection(selection); $insertNodeToNearestRoot($createTestDecoratorNode()); diff --git a/packages/lexical-utils/src/index.ts b/packages/lexical-utils/src/index.ts index 0a758f40f2f..b850a6052d5 100644 --- a/packages/lexical-utils/src/index.ts +++ b/packages/lexical-utils/src/index.ts @@ -185,6 +185,21 @@ export function $dfs( return Array.from($dfsIterator(startNode, endNode)); } +/** + * A function which will return exactly the reversed order of $dfs. That means that the tree is traversed + * from right to left, starting at the leaf and working towards the root. + * @param startNode - The node to start the search. If omitted, it will start at the last leaf node in the tree. + * @param endNode - The node to end the search. If omitted, it will work backwards all the way to the root node + * @returns An array of objects of all the nodes found by the search, including their depth into the tree. + * \\{depth: number, node: LexicalNode\\} It will always return at least 1 node (the start node). + */ +export function $reverseDfs( + startNode?: LexicalNode, + endNode?: LexicalNode, +): Array { + return Array.from($reverseDfsIterator(startNode, endNode)); +} + type DFSIterator = { next: () => IteratorResult; [Symbol.iterator]: () => DFSIterator; @@ -199,7 +214,7 @@ const iteratorNotDone: (value: T) => Readonly<{done: false; value: T}> = ( ) => ({done: false, value}); /** - * $dfs iterator. Tree traversal is done on the fly as new values are requested with O(1) memory. + * $dfs iterator (left to right). Tree traversal is done on the fly as new values are requested with O(1) memory. * @param startNode - The node to start the search, if omitted, it will start at the root node. * @param endNode - The node to end the search, if omitted, it will find all descendants of the startingNode. * @returns An iterator, each yielded value is a DFSNode. It will always return at least 1 node (the start node). @@ -285,6 +300,39 @@ export function $getNextSiblingOrParentSibling( return [node_, depthDiff]; } +/** + * Returns the Node's previous sibling when this exists, otherwise the closest parent previous sibling. For example + * R -> P -> T1, T2 + * -> P2 + * returns T1 for node T2, P for node P2, and null for node P + * @param node LexicalNode. + * @returns An array (tuple) containing the found Lexical node and the depth difference, or null, if this node doesn't exist. + */ +function $getPreviousSiblingOrParentSibling( + node: LexicalNode, +): null | [LexicalNode, number] { + let node_: null | LexicalNode = node; + // Find immediate sibling or nearest parent sibling + let sibling = null; + let depthDiff = 0; + + while (sibling === null && node_ !== null) { + sibling = node_.getPreviousSibling(); + + if (sibling === null) { + node_ = node_.getParent(); + depthDiff--; + } else { + node_ = sibling; + } + } + + if (node_ === null) { + return null; + } + return [node_, depthDiff]; +} + export function $getDepth(node: LexicalNode): number { let innerNode: LexicalNode | null = node; let depth = 0; @@ -327,6 +375,63 @@ export function $getNextRightPreorderNode( return node; } +/** + * $dfs iterator (right to left). Tree traversal is done on the fly as new values are requested with O(1) memory. + * @param startNode - The node to start the search, if omitted, it will start at the root node. + * @param endNode - The node to end the search, if omitted, it will find all descendants of the startingNode. + * @returns An iterator, each yielded value is a DFSNode. It will always return at least 1 node (the start node). + */ +export function $reverseDfsIterator( + startNode?: LexicalNode, + endNode?: LexicalNode, +): DFSIterator { + const start = (startNode || $getRoot()).getLatest(); + const startDepth = $getDepth(start); + const end = endNode; + let node: null | LexicalNode = start; + let depth = startDepth; + let isFirstNext = true; + + const iterator: DFSIterator = { + next(): IteratorResult { + if (node === null) { + return iteratorDone; + } + if (isFirstNext) { + isFirstNext = false; + return iteratorNotDone({depth, node}); + } + if (node === end) { + return iteratorDone; + } + + if ($isElementNode(node) && node.getChildrenSize() > 0) { + node = node.getLastChild(); + depth++; + } else { + let depthDiff; + [node, depthDiff] = $getPreviousSiblingOrParentSibling(node) || [ + null, + 0, + ]; + depth += depthDiff; + if (end == null && depth <= startDepth) { + node = null; + } + } + + if (node === null) { + return iteratorDone; + } + return iteratorNotDone({depth, node}); + }, + [Symbol.iterator](): DFSIterator { + return iterator; + }, + }; + return iterator; +} + /** * Takes a node and traverses up its ancestors (toward the root node) * in order to find a specific type of node. diff --git a/packages/lexical-website/docs/concepts/dom-events.md b/packages/lexical-website/docs/concepts/dom-events.md index c45b5d7615b..785b159f341 100644 --- a/packages/lexical-website/docs/concepts/dom-events.md +++ b/packages/lexical-website/docs/concepts/dom-events.md @@ -2,7 +2,7 @@ # Working with DOM Events -Sometimes, when working with Lexical, it might be necessary or useful for you to attach a DOM Event Listener to the underlying DOM nodes that Lexical controls. For instance, you might want to to show a popover when a user mouses over a specific node or open a modal when they click on a node. Either of these use cases (and many others) can be accomplished via native DOM Event Listeners. There are 3 main ways that you can listen for DOM Events on nodes controlled by Lexical: +Sometimes, when working with Lexical, it might be necessary or useful for you to attach a DOM Event Listener to the underlying DOM nodes that Lexical controls. For instance, you might want to show a popover when a user mouses over a specific node or open a modal when they click on a node. Either of these use cases (and many others) can be accomplished via native DOM Event Listeners. There are 3 main ways that you can listen for DOM Events on nodes controlled by Lexical: ## 1. Event Delegation @@ -40,7 +40,7 @@ const removeMutationListener = editor.registerMutationListener(nodeType, (mutati const element: null | HTMLElement = editor.getElementByKey(key); if ( // Updated might be a move, so that might mean a new DOM element - // is created. In this case, we need to add and event listener too. + // is created. In this case, we need to add an event listener too. (mutation === 'created' || mutation === 'updated') && element !== null && !registeredElements.has(element) diff --git a/packages/lexical-website/docs/concepts/listeners.md b/packages/lexical-website/docs/concepts/listeners.md index ef95f1c6d0b..9c180f22bce 100644 --- a/packages/lexical-website/docs/concepts/listeners.md +++ b/packages/lexical-website/docs/concepts/listeners.md @@ -2,7 +2,7 @@ # Listeners -Listeners are a mechanism that lets the Editor instance inform the user when a certain operation has occured. All listeners follow a reactive pattern where you can do an operation upon something happening in the future. All listeners also return a function that easily allows for the +Listeners are a mechanism that lets the Editor instance inform the user when a certain operation has occurred. All listeners follow a reactive pattern where you can do an operation upon something happening in the future. All listeners also return a function that easily allows for the listener to be unregistered. Below are the different listeners that Lexical supports today: ## `registerUpdateListener` @@ -31,7 +31,7 @@ The update listener callbacks receives a single argument containing the follow p - `tags` a Set of all tags that were passed to the update One thing to be aware of is "waterfall" updates. This is where you might schedule an update inside an update -listener, as show below: +listener, as shown below: ```js editor.registerUpdateListener(({editorState}) => { @@ -48,7 +48,7 @@ editor.registerUpdateListener(({editorState}) => { ``` The problem with this pattern is that it means we end up doing two DOM updates, when we likely could have -done it in a single DOM update. This can have an impact on performance, which is important in text editor. +done it in a single DOM update. This can have an impact on performance, which is important in a text editor. To avoid this, we recommend looking into [Node Transforms](https://lexical.dev/docs/concepts/transforms), which allow you to listen to node changes and transform them as part of the same given update, meaning no waterfalls! diff --git a/packages/lexical-website/docs/concepts/selection.md b/packages/lexical-website/docs/concepts/selection.md index 0923b3befa1..9b8577bc871 100644 --- a/packages/lexical-website/docs/concepts/selection.md +++ b/packages/lexical-website/docs/concepts/selection.md @@ -44,7 +44,7 @@ TableSelection represents a grid-like selection like tables. It stores the key o - `tableKey` representing the parent node key where the selection takes place - `anchor` representing a `TableSelection` point -- `focus` reprensenting a `TableSelection` point +- `focus` representing a `TableSelection` point For example, a table where you select row = 1 col = 1 to row 2 col = 2 could be stored as follows: - `tableKey = 2` table key diff --git a/packages/lexical-website/docs/concepts/serialization.md b/packages/lexical-website/docs/concepts/serialization.md index 90eaf313fe3..20e2c8d5300 100644 --- a/packages/lexical-website/docs/concepts/serialization.md +++ b/packages/lexical-website/docs/concepts/serialization.md @@ -170,7 +170,7 @@ const jsonString = JSON.stringify(editorState); #### `LexicalNode.exportJSON()` -You can control how a `LexicalNode` is represented as JSON by adding an `exportJSON()` method. It's important to ensure your serialized JSON node has a `type` field and a `children` field if it's an `ElementNode`. +You can control how a `LexicalNode` is represented as JSON by adding an `exportJSON()` method. It's important that you extend the serialization of the superclass by invoking `super`: e.g. `{ ...super.exportJSON(), /* your other properties */ }`. ```js export type SerializedLexicalNode = { @@ -197,15 +197,13 @@ exportJSON(): SerializedHeadingNode { return { ...super.exportJSON(), tag: this.getTag(), - type: 'heading', - version: 1, }; } ``` #### `LexicalNode.importJSON()` -You can control how a `LexicalNode` is serialized back into a node from JSON by adding an `importJSON()` method. +You can control how a `LexicalNode` is deserialized back into a node from JSON by adding an `importJSON()` method. ```js export type SerializedLexicalNode = { @@ -218,23 +216,62 @@ importJSON(jsonNode: SerializedLexicalNode): LexicalNode This method works in the opposite way to how `exportJSON` works. Lexical uses the `type` field on the JSON object to determine what Lexical node class it needs to map to, so keeping the `type` field consistent with the `getType()` of the LexicalNode is essential. +You should use the `updateFromJSON` method in your `importJSON` to simplify the implementation and allow for future extension by the base classes. + Here's an example of `importJSON` for the `HeadingNode`: -```js +```ts static importJSON(serializedNode: SerializedHeadingNode): HeadingNode { - const node = $createHeadingNode(serializedNode.tag); - node.setFormat(serializedNode.format); - node.setIndent(serializedNode.indent); - node.setDirection(serializedNode.direction); - return node; + return $createHeadingNode().updateFromJSON(serializedNode); +} + +updateFromJSON( + serializedNode: LexicalUpdateJSON, +): this { + return super.updateFromJSON(serializedNode).setTag(serializedNode.tag); } ``` +#### `LexicalNode.updateFromJSON()` + +`updateFromJSON` is a method introduced in Lexical 0.23 to simplify the implementation of `importJSON`, so that a base class can expose the code that it is using to set all of the node's properties based on the JSON to any subclass. + +:::note + +The input type used in this method is not sound in the general case, but it is safe if subclasses only add optional properties to the JSON. Even though it is not sound, the usage in this library is safe as long as your `importJSON` method does not upcast the node before calling `updateFromJSON`. + +```ts +export type SerializedExtendedTextNode = Spread< + // UNSAFE. This property is not optional + { newProperty: string }, + SerializedTextNode +>; +``` + +```ts +export type SerializedExtendedTextNode = Spread< + // SAFE. This property is not optional + { newProperty?: string }, + SerializedTextNode +>; +``` + +This is because it's possible to cast to a more general type, e.g. + +```ts +const serializedNode: SerializedTextNode = { /* ... */ }; +const newNode: TextNode = $createExtendedTextNode(); +// This passes the type check, but would fail at runtime if the updateFromJSON method required newProperty +newNode.updateFromJSON(serializedNode); +``` + +::: + ### Versioning & Breaking Changes It's important to note that you should avoid making breaking changes to existing fields in your JSON object, especially if backwards compatibility is an important part of your editor. That's why we recommend using a version field to separate the different changes in your node as you add or change functionality of custom nodes. Here's the serialized type definition for Lexical's base `TextNode` class: -```js +```ts import type {Spread} from 'lexical'; // Spread is a Typescript utility that allows us to spread the properties @@ -251,21 +288,10 @@ export type SerializedTextNode = Spread< >; ``` -If we wanted to make changes to the above `TextNode`, we should be sure to not remove or change an existing property, as this can cause data corruption. Instead, opt to add the functionality as a new property field instead, and use the version to determine how to handle the differences in your node. - -```js -export type SerializedTextNodeV1 = Spread< - { - detail: number; - format: number; - mode: TextModeType; - style: string; - text: string; - }, - SerializedLexicalNode ->; +If we wanted to make changes to the above `TextNode`, we should be sure to not remove or change an existing property, as this can cause data corruption. Instead, opt to add the functionality as a new optional property field instead. -export type SerializedTextNodeV2 = Spread< +```ts +export type SerializedTextNode = Spread< { detail: number; format: number; @@ -273,15 +299,53 @@ export type SerializedTextNodeV2 = Spread< style: string; text: string; // Our new field we've added - newField: string, - // Notice the version is now 2 - version: 2, + newField?: string, }, SerializedLexicalNode >; +``` -export type SerializedTextNode = SerializedTextNodeV1 | SerializedTextNodeV2; +### Dangers of a flat version property + +The `updateFromJSON` method should ignore `type` and `version`, to support subclassing and code re-use. Ideally, you should only evolve your types in a backwards compatible way (new fields are optional), and/or have a uniquely named property to store the version in your class. Generally speaking, it's best if nearly all properties are optional and the node provides defaults for each property. This allows you to write less boilerplate code and produce smaller JSON. + +The reason that `version` is no longer recommended is that it does not compose with subclasses. Consider this hierarchy: + +```ts +class TextNode { + exportJSON() { + return { /* ... */, version: 1 }; + } +} +class ExtendedTextNode extends TextNode { + exportJSON() { + return { ...super.exportJSON() }; + } +} ``` + +If `TextNode` is updated to `version: 2` then this version and new serialization will propagate to `ExtendedTextNode` via the `super.exportJSON()` call, but this leaves nowhere to store a version for `ExtendedTextNode` or vice versa. If the `ExtendedTextNode` explicitly specified a `version`, then the version of the base class will be ignored even though the representation of the JSON from the base class may change: + +```ts +class TextNode { + exportJSON() { + return { /* ... */, version: 2 }; + } +} +class ExtendedTextNode extends TextNode { + exportJSON() { + // The super's layout has changed, but the version information is lost + return { ...super.exportJSON(), version: 1 }; + } +} +``` + +So then you have a situation where there are possibly two JSON layouts for `ExtendedTextNode` with the same version, because the base class version changed due to a package upgrade. + +If you do have incompatible representations, it's probably best to choose a new type. This is basically the only way that will force old configurations to fail, as `importJSON` implementations often don't do runtime validation and dangerously assume that the values are the correct type. + +There are other schemes that would allow for composable versions, such as nesting the superclass data, or choosing a different name for a version property in each subclass. In practice, explicit versioning is generally redundant if the serialization is properly parsed, so it is recommended that you use the simpler approach with a flat representation with mostly optional properties. + ### Handling extended HTML styling Since the TextNode is foundational to all Lexical packages, including the plain text use case. Handling any rich text logic is undesirable. This creates the need to override the TextNode to handle serialization and deserialization of HTML/CSS styling properties to achieve full fidelity between JSON \<-\> HTML. Since this is a very popular use case, below we are proving a recipe to handle the most common use cases. @@ -366,23 +430,17 @@ export class ExtendedTextNode extends TextNode { } static importJSON(serializedNode: SerializedTextNode): TextNode { - return TextNode.importJSON(serializedNode); + return $createExtendedTextNode().updateFromJSON(serializedNode); } isSimpleText() { return this.__type === 'extended-text' && this.__mode === 0; } - exportJSON(): SerializedTextNode { - return { - ...super.exportJSON(), - type: 'extended-text', - version: 1, - } - } + // no need to add exportJSON here, since we are not adding any new properties } -export function $createExtendedTextNode(text: string): ExtendedTextNode { +export function $createExtendedTextNode(text: string = ''): ExtendedTextNode { return $applyNodeReplacement(new ExtendedTextNode(text)); } diff --git a/packages/lexical-website/docs/getting-started/creating-plugin.md b/packages/lexical-website/docs/getting-started/creating-plugin.md index 32791754217..1a302019121 100644 --- a/packages/lexical-website/docs/getting-started/creating-plugin.md +++ b/packages/lexical-website/docs/getting-started/creating-plugin.md @@ -69,13 +69,12 @@ export class EmojiNode extends TextNode { } static importJSON(serializedNode: SerializedEmojiNode): EmojiNode { - return $createEmojiNode(serializedNode.unifiedID); + return $createEmojiNode(serializedNode.unifiedID).updateFromJSON(serializedNode); } exportJSON(): SerializedEmojiNode { return { ...super.exportJSON(), - type: 'emoji', unifiedID: this.__unifiedID, }; } diff --git a/packages/lexical-website/docs/react/create_plugin.md b/packages/lexical-website/docs/react/create_plugin.md index 6ebf19263fe..0d1f742ca4a 100644 --- a/packages/lexical-website/docs/react/create_plugin.md +++ b/packages/lexical-website/docs/react/create_plugin.md @@ -70,6 +70,6 @@ TwitterPlugin is just a React component that accesses the Lexical editor via Rea 1. Verifies that there is a TweetNode registered on the editor (if you forget to register the node, you can't do #2) 2. registers a "command", passing a callback that will run when that command is dispatched. The command callback creates and inserts a TweetNode in the editor. -You can see how it's used in the playground [here](https://github.com/facebook/lexical/blob/0775ab929e65723433626fa8c25900941e7f232f/packages/lexical-playground/src/Editor.tsx#L137). It's added it as a child of a LexicalComposer component, which does the job of providing the Context necessary for access to the editor instance. To actually trigger this command callback and insert a [TweetNode](https://github.com/facebook/lexical/blob/b0fa38615c03f1c4fc7c8c5ea26412b723770e55/packages/lexical-playground/src/nodes/TweetNode.tsx#L212), we have a [button](https://github.com/facebook/lexical/blob/b0fa38615c03f1c4fc7c8c5ea26412b723770e55/packages/lexical-playground/src/plugins/ToolbarPlugin.tsx#L534) that "dispatches" the Tweet command we registered in the plugin. +You can see how [TwitterPlugin is used in the playground](https://github.com/facebook/lexical/blob/0775ab929e65723433626fa8c25900941e7f232f/packages/lexical-playground/src/Editor.tsx#L137). It's added as a child of a LexicalComposer component, which does the job of providing the Context necessary for access to the editor instance. To actually trigger this command callback and insert a [TweetNode](https://github.com/facebook/lexical/blob/b0fa38615c03f1c4fc7c8c5ea26412b723770e55/packages/lexical-playground/src/nodes/TweetNode.tsx#L212), we have a [button](https://github.com/facebook/lexical/blob/b0fa38615c03f1c4fc7c8c5ea26412b723770e55/packages/lexical-playground/src/plugins/ToolbarPlugin.tsx#L534) that "dispatches" the Tweet command we registered in the plugin. While the TwitterPlugin registers a command that inserts a custom node, this is only one example of what can be done with a plugin. To get a better idea of what's possible, take a look at the [plugins defined in the playground](https://github.com/facebook/lexical/tree/0775ab929e65723433626fa8c25900941e7f232f/packages/lexical-playground/src/plugins). diff --git a/packages/lexical-website/package.json b/packages/lexical-website/package.json index 72a81071855..5e0a5e86345 100644 --- a/packages/lexical-website/package.json +++ b/packages/lexical-website/package.json @@ -1,6 +1,6 @@ { "name": "@lexical/website", - "version": "0.21.0", + "version": "0.23.1", "private": true, "scripts": { "docusaurus": "docusaurus", diff --git a/packages/lexical-yjs/package.json b/packages/lexical-yjs/package.json index c0e59c45cbc..c29d39acb52 100644 --- a/packages/lexical-yjs/package.json +++ b/packages/lexical-yjs/package.json @@ -11,13 +11,13 @@ "crdt" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "LexicalYjs.js", "types": "index.d.ts", "dependencies": { - "@lexical/offset": "0.21.0", - "@lexical/selection": "0.21.0", - "lexical": "0.21.0" + "@lexical/offset": "0.23.1", + "@lexical/selection": "0.23.1", + "lexical": "0.23.1" }, "peerDependencies": { "yjs": ">=13.5.22" diff --git a/packages/lexical-yjs/src/CollabElementNode.ts b/packages/lexical-yjs/src/CollabElementNode.ts index c38171af0e8..14fd1fbf0c8 100644 --- a/packages/lexical-yjs/src/CollabElementNode.ts +++ b/packages/lexical-yjs/src/CollabElementNode.ts @@ -129,6 +129,7 @@ export class CollabElementNode { ): void { const children = this._children; let currIndex = 0; + let pendingSplitText = null; for (let i = 0; i < deltas.length; i++) { const delta = deltas[i]; @@ -211,7 +212,7 @@ export class CollabElementNode { currIndex += insertDelta.length; } else { const sharedType = insertDelta; - const {nodeIndex} = getPositionFromElementAndOffset( + const {node, nodeIndex, length} = getPositionFromElementAndOffset( this, currIndex, false, @@ -221,7 +222,30 @@ export class CollabElementNode { sharedType as XmlText | YMap | XmlElement, this, ); - children.splice(nodeIndex, 0, collabNode); + if ( + node instanceof CollabTextNode && + length > 0 && + length < node._text.length + ) { + // Trying to insert in the middle of a text node; split the text. + const text = node._text; + const splitIdx = text.length - length; + node._text = spliceString(text, splitIdx, length, ''); + children.splice(nodeIndex + 1, 0, collabNode); + // The insert that triggers the text split might not be a text node. Need to keep a + // reference to the remaining text so that it can be added when we do create one. + pendingSplitText = spliceString(text, 0, splitIdx, ''); + } else { + children.splice(nodeIndex, 0, collabNode); + } + if ( + pendingSplitText !== null && + collabNode instanceof CollabTextNode + ) { + // Found a text node to insert the pending text into. + collabNode._text = pendingSplitText + collabNode._text; + pendingSplitText = null; + } currIndex += 1; } } else { diff --git a/packages/lexical-yjs/src/SyncCursors.ts b/packages/lexical-yjs/src/SyncCursors.ts index a34c7538409..31cf7010c6d 100644 --- a/packages/lexical-yjs/src/SyncCursors.ts +++ b/packages/lexical-yjs/src/SyncCursors.ts @@ -26,7 +26,7 @@ import { createRelativePositionFromTypeIndex, } from 'yjs'; -import {Provider} from '.'; +import {Provider, UserState} from '.'; import {CollabDecoratorNode} from './CollabDecoratorNode'; import {CollabElementNode} from './CollabElementNode'; import {CollabLineBreakNode} from './CollabLineBreakNode'; @@ -295,50 +295,73 @@ function updateCursor( } } -export function $syncLocalCursorPosition( - binding: Binding, - provider: Provider, -): void { - const awareness = provider.awareness; - const localState = awareness.getLocalState(); +type AnyCollabNode = + | CollabDecoratorNode + | CollabElementNode + | CollabTextNode + | CollabLineBreakNode; - if (localState === null) { - return; - } +export function getAnchorAndFocusCollabNodesForUserState( + binding: Binding, + userState: UserState, +) { + const {anchorPos, focusPos} = userState; - const anchorPos = localState.anchorPos; - const focusPos = localState.focusPos; + let anchorCollabNode: AnyCollabNode | null = null; + let anchorOffset = 0; + let focusCollabNode: AnyCollabNode | null = null; + let focusOffset = 0; if (anchorPos !== null && focusPos !== null) { const anchorAbsPos = createAbsolutePosition(anchorPos, binding); const focusAbsPos = createAbsolutePosition(focusPos, binding); if (anchorAbsPos !== null && focusAbsPos !== null) { - const [anchorCollabNode, anchorOffset] = getCollabNodeAndOffset( + [anchorCollabNode, anchorOffset] = getCollabNodeAndOffset( anchorAbsPos.type, anchorAbsPos.index, ); - const [focusCollabNode, focusOffset] = getCollabNodeAndOffset( + [focusCollabNode, focusOffset] = getCollabNodeAndOffset( focusAbsPos.type, focusAbsPos.index, ); + } + } + + return { + anchorCollabNode, + anchorOffset, + focusCollabNode, + focusOffset, + }; +} + +export function $syncLocalCursorPosition( + binding: Binding, + provider: Provider, +): void { + const awareness = provider.awareness; + const localState = awareness.getLocalState(); - if (anchorCollabNode !== null && focusCollabNode !== null) { - const anchorKey = anchorCollabNode.getKey(); - const focusKey = focusCollabNode.getKey(); + if (localState === null) { + return; + } - const selection = $getSelection(); + const {anchorCollabNode, anchorOffset, focusCollabNode, focusOffset} = + getAnchorAndFocusCollabNodesForUserState(binding, localState); - if (!$isRangeSelection(selection)) { - return; - } - const anchor = selection.anchor; - const focus = selection.focus; + if (anchorCollabNode !== null && focusCollabNode !== null) { + const anchorKey = anchorCollabNode.getKey(); + const focusKey = focusCollabNode.getKey(); - $setPoint(anchor, anchorKey, anchorOffset); - $setPoint(focus, focusKey, focusOffset); - } + const selection = $getSelection(); + + if (!$isRangeSelection(selection)) { + return; } + + $setPoint(selection.anchor, anchorKey, anchorOffset); + $setPoint(selection.focus, focusKey, focusOffset); } } @@ -363,16 +386,7 @@ function getCollabNodeAndOffset( // eslint-disable-next-line @typescript-eslint/no-explicit-any sharedType: any, offset: number, -): [ - ( - | null - | CollabDecoratorNode - | CollabElementNode - | CollabTextNode - | CollabLineBreakNode - ), - number, -] { +): [null | AnyCollabNode, number] { const collabNode = sharedType._collabNode; if (collabNode === undefined) { @@ -396,6 +410,11 @@ function getCollabNodeAndOffset( return [null, 0]; } +export type SyncCursorPositionsFn = ( + binding: Binding, + provider: Provider, +) => void; + export function syncCursorPositions( binding: Binding, provider: Provider, @@ -413,7 +432,7 @@ export function syncCursorPositions( if (clientID !== localClientID) { visitedClientIDs.add(clientID); - const {anchorPos, focusPos, name, color, focusing} = awareness; + const {name, color, focusing} = awareness; let selection = null; let cursor = cursors.get(clientID); @@ -423,41 +442,30 @@ export function syncCursorPositions( cursors.set(clientID, cursor); } - if (anchorPos !== null && focusPos !== null && focusing) { - const anchorAbsPos = createAbsolutePosition(anchorPos, binding); - const focusAbsPos = createAbsolutePosition(focusPos, binding); - - if (anchorAbsPos !== null && focusAbsPos !== null) { - const [anchorCollabNode, anchorOffset] = getCollabNodeAndOffset( - anchorAbsPos.type, - anchorAbsPos.index, - ); - const [focusCollabNode, focusOffset] = getCollabNodeAndOffset( - focusAbsPos.type, - focusAbsPos.index, - ); - - if (anchorCollabNode !== null && focusCollabNode !== null) { - const anchorKey = anchorCollabNode.getKey(); - const focusKey = focusCollabNode.getKey(); - selection = cursor.selection; - - if (selection === null) { - selection = createCursorSelection( - cursor, - anchorKey, - anchorOffset, - focusKey, - focusOffset, - ); - } else { - const anchor = selection.anchor; - const focus = selection.focus; - anchor.key = anchorKey; - anchor.offset = anchorOffset; - focus.key = focusKey; - focus.offset = focusOffset; - } + if (focusing) { + const {anchorCollabNode, anchorOffset, focusCollabNode, focusOffset} = + getAnchorAndFocusCollabNodesForUserState(binding, awareness); + + if (anchorCollabNode !== null && focusCollabNode !== null) { + const anchorKey = anchorCollabNode.getKey(); + const focusKey = focusCollabNode.getKey(); + selection = cursor.selection; + + if (selection === null) { + selection = createCursorSelection( + cursor, + anchorKey, + anchorOffset, + focusKey, + focusOffset, + ); + } else { + const anchor = selection.anchor; + const focus = selection.focus; + anchor.key = anchorKey; + anchor.offset = anchorOffset; + focus.key = focusKey; + focus.offset = focusOffset; } } } diff --git a/packages/lexical-yjs/src/SyncEditorStates.ts b/packages/lexical-yjs/src/SyncEditorStates.ts index beca7904176..c5f87d0c954 100644 --- a/packages/lexical-yjs/src/SyncEditorStates.ts +++ b/packages/lexical-yjs/src/SyncEditorStates.ts @@ -26,6 +26,7 @@ import {CollabTextNode} from './CollabTextNode'; import { $syncLocalCursorPosition, syncCursorPositions, + SyncCursorPositionsFn, syncLexicalSelectionToYjs, } from './SyncCursors'; import { @@ -83,6 +84,7 @@ export function syncYjsChangesToLexical( provider: Provider, events: Array>, isFromUndoManger: boolean, + syncCursorPositionsFn: SyncCursorPositionsFn = syncCursorPositions, ): void { const editor = binding.editor; const currentEditorState = editor._editorState; @@ -129,7 +131,7 @@ export function syncYjsChangesToLexical( }, { onUpdate: () => { - syncCursorPositions(binding, provider); + syncCursorPositionsFn(binding, provider); // If there was a collision on the top level paragraph // we need to re-add a paragraph. To ensure this insertion properly syncs with other clients, // it must be placed outside of the update block above that has tags 'collaboration' or 'historic'. diff --git a/packages/lexical-yjs/src/index.ts b/packages/lexical-yjs/src/index.ts index 62b5fbbe8fc..21ace2cb1bb 100644 --- a/packages/lexical-yjs/src/index.ts +++ b/packages/lexical-yjs/src/index.ts @@ -111,7 +111,11 @@ export function setLocalStateFocus( localState.focusing = focusing; awareness.setLocalState(localState); } -export {syncCursorPositions} from './SyncCursors'; +export { + getAnchorAndFocusCollabNodesForUserState, + syncCursorPositions, + type SyncCursorPositionsFn, +} from './SyncCursors'; export { syncLexicalUpdateToYjs, syncYjsChangesToLexical, diff --git a/packages/lexical/README.md b/packages/lexical/README.md index 57efd413fa9..72bf99b5779 100644 --- a/packages/lexical/README.md +++ b/packages/lexical/README.md @@ -14,10 +14,10 @@ editor implementations to be built on top. Lexical's engine provides three main By design, the core of Lexical tries to be as minimal as possible. Lexical doesn't directly concern itself with things that monolithic editors tend to do – such as UI components, toolbars or rich-text features and markdown. Instead the logic for those features can be included via a plugin interface and used as and when they're needed. This ensures great extensibility and keeps code-sizes -to a minimal – ensuring apps only pay the cost for what they actually import. +to a minimum – ensuring apps only pay the cost for what they actually import. For React apps, Lexical has tight integration with React 18+ via the optional `@lexical/react` package. This package provides -production-ready utility functions, helpers and React hooks that make it seemless to create text editors within React. +production-ready utility functions, helpers and React hooks that make it seamless to create text editors within React. ## Usage diff --git a/packages/lexical/flow/Lexical.js.flow b/packages/lexical/flow/Lexical.js.flow index 1779c2f272a..32fce6535da 100644 --- a/packages/lexical/flow/Lexical.js.flow +++ b/packages/lexical/flow/Lexical.js.flow @@ -262,6 +262,7 @@ export type EditorThemeClasses = { ulDepth?: Array, ol?: EditorThemeClassName, olDepth?: Array, + checklist?: EditorThemeClassName, listitem?: EditorThemeClassName, listitemChecked?: EditorThemeClassName, listitemUnchecked?: EditorThemeClassName, @@ -361,7 +362,7 @@ export type DOMConversion = { conversion: DOMConversionFn, priority: 0 | 1 | 2 | 3 | 4, }; -export type DOMConversionFn = (element: Node) => DOMConversionOutput; +export type DOMConversionFn = (element: Node) => DOMConversionOutput | null; export type DOMChildConversion = ( lexicalNode: LexicalNode, parentLexicalNode: ?LexicalNode | null, @@ -392,6 +393,7 @@ declare export class LexicalNode { constructor(key?: NodeKey): void; exportDOM(editor: LexicalEditor): DOMExportOutput; exportJSON(): SerializedLexicalNode; + updateFromJSON(serializedNode: $FlowFixMe): this; getType(): string; isAttached(): boolean; isSelected(): boolean; @@ -421,7 +423,8 @@ declare export class LexicalNode { getTextContentSize(includeDirectionless?: boolean): number; createDOM(config: EditorConfig, editor: LexicalEditor): HTMLElement; updateDOM( - prevNode: this, + // $FlowFixMe[unclear-type] + prevNode: any, dom: HTMLElement, config: EditorConfig, ): boolean; @@ -451,13 +454,16 @@ declare export function $isBlockElementNode( ): node is ElementNode; export interface BaseSelection { - clone(): BaseSelection; dirty: boolean; + clone(): BaseSelection; extract(): Array; getNodes(): Array; + getStartEndPoints(): null | [PointType, PointType]; getTextContent(): string; insertRawText(text: string): void; is(selection: null | BaseSelection): boolean; + isBackward(): boolean; + isCollapsed(): boolean; insertText(text: string): void; insertNodes(nodes: Array): void; getCachedNodes(): null | Array; @@ -469,6 +475,8 @@ declare export class NodeSelection implements BaseSelection { dirty: boolean; constructor(objects: Set): void; is(selection: null | BaseSelection): boolean; + isBackward(): boolean; + isCollapsed(): boolean; add(key: NodeKey): void; delete(key: NodeKey): void; clear(): void; @@ -478,6 +486,7 @@ declare export class NodeSelection implements BaseSelection { insertRawText(): void; insertText(): void; getNodes(): Array; + getStartEndPoints(): null; getTextContent(): string; insertNodes(nodes: Array): void; getCachedNodes(): null | Array; @@ -493,6 +502,7 @@ declare export class RangeSelection implements BaseSelection { focus: PointType; dirty: boolean; format: number; + style: string; constructor(anchor: PointType, focus: PointType, format: number): void; is(selection: null | BaseSelection): boolean; isBackward(): boolean; @@ -530,6 +540,8 @@ declare export class RangeSelection implements BaseSelection { insertNodes(nodes: Array): void; getCachedNodes(): null | Array; setCachedNodes(nodes: null | Array): void; + forwardDeletion(anchor: PointType, anchorNode: ElementNode | TextNode, isBackward: boolean): boolean; + getStartEndPoints(): null | [PointType, PointType]; } export type TextPoint = TextPointType; type TextPointType = { @@ -562,7 +574,7 @@ declare class _Point { is(point: PointType): boolean; isBefore(b: PointType): boolean; getNode(): LexicalNode; - set(key: NodeKey, offset: number, type: 'text' | 'element'): void; + set(key: NodeKey, offset: number, type: 'text' | 'element', onlyIfChanged?: boolean): void; } declare export function $createRangeSelection(): RangeSelection; diff --git a/packages/lexical/package.json b/packages/lexical/package.json index 4d1dfb2f096..e4c552dd407 100644 --- a/packages/lexical/package.json +++ b/packages/lexical/package.json @@ -9,7 +9,7 @@ "rich-text" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "main": "Lexical.js", "types": "index.d.ts", "repository": { diff --git a/packages/lexical/src/LexicalConstants.ts b/packages/lexical/src/LexicalConstants.ts index aead3dbddff..2204cc6d09f 100644 --- a/packages/lexical/src/LexicalConstants.ts +++ b/packages/lexical/src/LexicalConstants.ts @@ -23,6 +23,8 @@ import { // DOM export const DOM_ELEMENT_TYPE = 1; export const DOM_TEXT_TYPE = 3; +export const DOM_DOCUMENT_TYPE = 9; +export const DOM_DOCUMENT_FRAGMENT_TYPE = 11; // Reconciling export const NO_DIRTY_NODES = 0; diff --git a/packages/lexical/src/LexicalEditor.ts b/packages/lexical/src/LexicalEditor.ts index 1961c8f4f34..ab014a28e45 100644 --- a/packages/lexical/src/LexicalEditor.ts +++ b/packages/lexical/src/LexicalEditor.ts @@ -21,7 +21,7 @@ import {$getRoot, $getSelection, TextNode} from '.'; import {FULL_RECONCILE, NO_DIRTY_NODES} from './LexicalConstants'; import {cloneEditorState, createEmptyEditorState} from './LexicalEditorState'; import {addRootElementEvents, removeRootElementEvents} from './LexicalEvents'; -import {$flushRootMutations, initMutationObserver} from './LexicalMutations'; +import {flushRootMutations, initMutationObserver} from './LexicalMutations'; import {LexicalNode} from './LexicalNode'; import { $commitPendingUpdates, @@ -29,8 +29,11 @@ import { parseEditorState, triggerListeners, updateEditor, + updateEditorSync, } from './LexicalUpdates'; import { + $addUpdateTag, + $onUpdate, createUID, dispatchCommand, getCachedClassNameArray, @@ -40,7 +43,7 @@ import { markNodesWithTypesAsDirty, } from './LexicalUtils'; import {ArtificialNode__DO_NOT_USE} from './nodes/ArtificialNode'; -import {DecoratorNode} from './nodes/LexicalDecoratorNode'; +import {$isDecoratorNode} from './nodes/LexicalDecoratorNode'; import {LineBreakNode} from './nodes/LexicalLineBreakNode'; import {ParagraphNode} from './nodes/LexicalParagraphNode'; import {RootNode} from './nodes/LexicalRootNode'; @@ -85,6 +88,8 @@ export type EditorUpdateOptions = { skipTransforms?: true; tag?: string | Array; discrete?: true; + /** @internal */ + event?: undefined | UIEvent | Event | null; }; export type EditorSetOptions = { @@ -442,7 +447,7 @@ export function createEditor(editorConfig?: CreateEditorArgs): LexicalEditor { ]; const {onError, html} = config; const isEditable = config.editable !== undefined ? config.editable : true; - let registeredNodes: Map; + let registeredNodes: RegisteredNodes; if (editorConfig === undefined && activeEditor !== null) { registeredNodes = activeEditor._nodes; @@ -498,7 +503,7 @@ export function createEditor(editorConfig?: CreateEditorArgs): LexicalEditor { `${name} should implement "importDOM" if using a custom "exportDOM" method to ensure HTML serialization (important for copy & paste) works as expected`, ); } - if (proto instanceof DecoratorNode) { + if ($isDecoratorNode(proto)) { // eslint-disable-next-line no-prototype-builtins if (!proto.hasOwnProperty('decorate')) { console.warn( @@ -514,14 +519,6 @@ export function createEditor(editorConfig?: CreateEditorArgs): LexicalEditor { `${name} should implement "importJSON" method to ensure JSON and default HTML serialization works as expected`, ); } - if ( - // eslint-disable-next-line no-prototype-builtins - !proto.hasOwnProperty('exportJSON') - ) { - console.warn( - `${name} should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected`, - ); - } } } const type = klass.getType(); @@ -1104,11 +1101,15 @@ export class LexicalEditor { } } } else { - // If content editable is unmounted we'll reset editor state back to original - // (or pending) editor state since there will be no reconciliation - this._editorState = pendingEditorState; - this._pendingEditorState = null; + // When the content editable is unmounted we will still trigger a + // reconciliation so that any pending updates are flushed, + // to match the previous state change when + // `_editorState = pendingEditorState` was used, but by + // using a commit we preserve the readOnly invariant + // for editor.getEditorState(). this._window = null; + this._updateTags.add('history-merge'); + $commitPendingUpdates(this); } triggerListeners('root', this, false, nextRootElement, prevRootElement); @@ -1155,7 +1156,7 @@ export class LexicalEditor { : null; } - $flushRootMutations(this); + flushRootMutations(this); const pendingEditorState = this._pendingEditorState; const tags = this._updateTags; const tag = options !== undefined ? options.tag : null; @@ -1247,33 +1248,28 @@ export class LexicalEditor { if (rootElement !== null) { // This ensures that iOS does not trigger caps lock upon focus rootElement.setAttribute('autocapitalize', 'off'); - updateEditor( - this, - () => { - const selection = $getSelection(); - const root = $getRoot(); - - if (selection !== null) { - // Marking the selection dirty will force the selection back to it - selection.dirty = true; - } else if (root.getChildrenSize() !== 0) { - if (options.defaultSelection === 'rootStart') { - root.selectStart(); - } else { - root.selectEnd(); - } + updateEditorSync(this, () => { + const selection = $getSelection(); + const root = $getRoot(); + + if (selection !== null) { + // Marking the selection dirty will force the selection back to it + selection.dirty = true; + } else if (root.getChildrenSize() !== 0) { + if (options.defaultSelection === 'rootStart') { + root.selectStart(); + } else { + root.selectEnd(); } - }, - { - onUpdate: () => { - rootElement.removeAttribute('autocapitalize'); - if (callbackFn) { - callbackFn(); - } - }, - tag: 'focus', - }, - ); + } + $addUpdateTag('focus'); + $onUpdate(() => { + rootElement.removeAttribute('autocapitalize'); + if (callbackFn) { + callbackFn(); + } + }); + }); // In the case where onUpdate doesn't fire (due to the focus update not // occuring). if (this._pendingEditorState === null) { diff --git a/packages/lexical/src/LexicalEvents.ts b/packages/lexical/src/LexicalEvents.ts index 662cd81fe2d..87b9a84cf4d 100644 --- a/packages/lexical/src/LexicalEvents.ts +++ b/packages/lexical/src/LexicalEvents.ts @@ -59,7 +59,6 @@ import { KEY_TAB_COMMAND, MOVE_TO_END, MOVE_TO_START, - ParagraphNode, PASTE_COMMAND, REDO_COMMAND, REMOVE_TEXT_COMMAND, @@ -69,8 +68,6 @@ import { import {KEY_MODIFIER_COMMAND, SELECT_ALL_COMMAND} from './LexicalCommands'; import { COMPOSITION_START_CHAR, - DOM_ELEMENT_TYPE, - DOM_TEXT_TYPE, DOUBLE_LINE_BREAK, IS_ALL_FORMATTING, } from './LexicalConstants'; @@ -78,8 +75,9 @@ import { $internalCreateRangeSelection, RangeSelection, } from './LexicalSelection'; -import {getActiveEditor, updateEditor} from './LexicalUpdates'; +import {getActiveEditor, updateEditorSync} from './LexicalUpdates'; import { + $findMatchingParent, $flushMutations, $getNodeByKey, $isSelectionCapturedInDecorator, @@ -92,6 +90,7 @@ import { doesContainGrapheme, getAnchorTextFromDOM, getDOMSelection, + getDOMSelectionFromTarget, getDOMTextNode, getEditorPropertyFromDOMNode, getEditorsToPropagate, @@ -109,8 +108,10 @@ import { isDeleteWordBackward, isDeleteWordForward, isDOMNode, + isDOMTextNode, isEscape, isFirefoxClipboardEvents, + isHTMLElement, isItalic, isLexicalEditor, isLineBreak, @@ -175,6 +176,8 @@ let isSelectionChangeFromDOMUpdate = false; let isSelectionChangeFromMouseDown = false; let isInsertLineBreak = false; let isFirefoxEndingComposition = false; +let isSafariEndingComposition = false; +let safariEndCompositionEventData = ''; let collapsedSelectionFormat: [number, string, number, NodeKey, number] = [ 0, '', @@ -189,7 +192,6 @@ let collapsedSelectionFormat: [number, string, number, NodeKey, number] = [ // work as intended between different browsers and across word, line and character // boundary/formats. It also is important for text replacement, node schemas and // composition mechanics. - function $shouldPreventDefaultAndInsertText( selection: RangeSelection, domTargetRange: null | StaticRange, @@ -201,7 +203,7 @@ function $shouldPreventDefaultAndInsertText( const focus = selection.focus; const anchorNode = anchor.getNode(); const editor = getActiveEditor(); - const domSelection = getDOMSelection(editor._window); + const domSelection = getDOMSelection(getWindow(editor)); const domAnchorNode = domSelection !== null ? domSelection.anchorNode : null; const anchorKey = anchor.key; const backingAnchorElement = editor.getElementByKey(anchorKey); @@ -254,9 +256,8 @@ function shouldSkipSelectionChange( offset: number, ): boolean { return ( - domNode !== null && + isDOMTextNode(domNode) && domNode.nodeValue !== null && - domNode.nodeType === DOM_TEXT_TYPE && offset !== 0 && offset !== domNode.nodeValue.length ); @@ -291,7 +292,7 @@ function onSelectionChange( return; } } - updateEditor(editor, () => { + updateEditorSync(editor, () => { // Non-active editor don't need any extra logic for selection, it only needs update // to reconcile selection (set it to null) to ensure that only one editor has non-null selection. if (!isActive) { @@ -349,11 +350,15 @@ function onSelectionChange( selection.format = anchorNode.getFormat(); selection.style = anchorNode.getStyle(); } else if (anchor.type === 'element' && !isRootTextContentEmpty) { + invariant( + $isElementNode(anchorNode), + 'Point.getNode() must return ElementNode when type is element', + ); const lastNode = anchor.getNode(); selection.style = ''; if ( - lastNode instanceof ParagraphNode && - lastNode.getChildrenSize() === 0 + // This previously applied to all ParagraphNode + lastNode.isEmpty() ) { selection.format = lastNode.getTextFormat(); selection.style = lastNode.getTextStyle(); @@ -414,9 +419,9 @@ function onSelectionChange( // also help other browsers when selection might "appear" lost, when it // really isn't. function onClick(event: PointerEvent, editor: LexicalEditor): void { - updateEditor(editor, () => { + updateEditorSync(editor, () => { const selection = $getSelection(); - const domSelection = getDOMSelection(editor._window); + const domSelection = getDOMSelection(getWindow(editor)); const lastSelection = $getPreviousSelection(); if (domSelection) { @@ -444,10 +449,12 @@ function onClick(event: PointerEvent, editor: LexicalEditor): void { const focus = selection.focus; const focusNode = focus.getNode(); if (anchorNode !== focusNode) { - if ($isElementNode(anchorNode)) { - anchorNode.select(0); - } else { - anchorNode.getParentOrThrow().select(0); + const parentNode = $findMatchingParent( + anchorNode, + (node) => $isElementNode(node) && !node.isInline(), + ); + if ($isElementNode(parentNode)) { + parentNode.select(0); } } } @@ -455,21 +462,18 @@ function onClick(event: PointerEvent, editor: LexicalEditor): void { // This is used to update the selection on touch devices when the user clicks on text after a // node selection. See isSelectionChangeFromMouseDown for the inverse const domAnchorNode = domSelection.anchorNode; - if (domAnchorNode !== null) { - const nodeType = domAnchorNode.nodeType; - // If the user is attempting to click selection back onto text, then - // we should attempt create a range selection. - // When we click on an empty paragraph node or the end of a paragraph that ends - // with an image/poll, the nodeType will be ELEMENT_NODE - if (nodeType === DOM_ELEMENT_TYPE || nodeType === DOM_TEXT_TYPE) { - const newSelection = $internalCreateRangeSelection( - lastSelection, - domSelection, - editor, - event, - ); - $setSelection(newSelection); - } + // If the user is attempting to click selection back onto text, then + // we should attempt create a range selection. + // When we click on an empty paragraph node or the end of a paragraph that ends + // with an image/poll, the nodeType will be ELEMENT_NODE + if (isHTMLElement(domAnchorNode) || isDOMTextNode(domAnchorNode)) { + const newSelection = $internalCreateRangeSelection( + lastSelection, + domSelection, + editor, + event, + ); + $setSelection(newSelection); } } } @@ -483,7 +487,7 @@ function onPointerDown(event: PointerEvent, editor: LexicalEditor) { const target = event.target; const pointerType = event.pointerType; if (isDOMNode(target) && pointerType !== 'touch' && event.button === 0) { - updateEditor(editor, () => { + updateEditorSync(editor, () => { // Drag & drop should not recompute selection until mouse up; otherwise the initially // selected content is lost. if (!$isSelectionCapturedInDecorator(target)) { @@ -543,7 +547,7 @@ function onBeforeInput(event: InputEvent, editor: LexicalEditor): void { return; } - updateEditor(editor, () => { + updateEditorSync(editor, () => { const selection = $getSelection(); if (inputType === 'deleteContentBackward') { @@ -571,7 +575,7 @@ function onBeforeInput(event: InputEvent, editor: LexicalEditor): void { lastKeyDownTimeStamp = 0; // Fixes an Android bug where selection flickers when backspacing setTimeout(() => { - updateEditor(editor, () => { + updateEditorSync(editor, () => { $setCompositionKey(null); }); }, ANDROID_COMPOSITION_LATENCY); @@ -807,93 +811,103 @@ function onBeforeInput(event: InputEvent, editor: LexicalEditor): void { } function onInput(event: InputEvent, editor: LexicalEditor): void { + // Note that the MutationObserver may or may not have already fired, + // but the the DOM and selection may have already changed. + // See also: + // - https://github.com/facebook/lexical/issues/7028 + // - https://github.com/facebook/lexical/pull/794 + // We don't want the onInput to bubble, in the case of nested editors. event.stopPropagation(); - updateEditor(editor, () => { - const selection = $getSelection(); - const data = event.data; - const targetRange = getTargetRange(event); + updateEditorSync( + editor, + () => { + const selection = $getSelection(); + const data = event.data; + const targetRange = getTargetRange(event); - if ( - data != null && - $isRangeSelection(selection) && - $shouldPreventDefaultAndInsertText( - selection, - targetRange, - data, - event.timeStamp, - false, - ) - ) { - // Given we're over-riding the default behavior, we will need - // to ensure to disable composition before dispatching the - // insertText command for when changing the sequence for FF. - if (isFirefoxEndingComposition) { - $onCompositionEndImpl(editor, data); - isFirefoxEndingComposition = false; - } - const anchor = selection.anchor; - const anchorNode = anchor.getNode(); - const domSelection = getDOMSelection(editor._window); - if (domSelection === null) { - return; - } - const isBackward = selection.isBackward(); - const startOffset = isBackward - ? selection.anchor.offset - : selection.focus.offset; - const endOffset = isBackward - ? selection.focus.offset - : selection.anchor.offset; - // If the content is the same as inserted, then don't dispatch an insertion. - // Given onInput doesn't take the current selection (it uses the previous) - // we can compare that against what the DOM currently says. if ( - !CAN_USE_BEFORE_INPUT || - selection.isCollapsed() || - !$isTextNode(anchorNode) || - domSelection.anchorNode === null || - anchorNode.getTextContent().slice(0, startOffset) + - data + - anchorNode.getTextContent().slice(startOffset + endOffset) !== - getAnchorTextFromDOM(domSelection.anchorNode) + data != null && + $isRangeSelection(selection) && + $shouldPreventDefaultAndInsertText( + selection, + targetRange, + data, + event.timeStamp, + false, + ) ) { - dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data); - } + // Given we're over-riding the default behavior, we will need + // to ensure to disable composition before dispatching the + // insertText command for when changing the sequence for FF. + if (isFirefoxEndingComposition) { + $onCompositionEndImpl(editor, data); + isFirefoxEndingComposition = false; + } + const anchor = selection.anchor; + const anchorNode = anchor.getNode(); + const domSelection = getDOMSelection(getWindow(editor)); + if (domSelection === null) { + return; + } + const isBackward = selection.isBackward(); + const startOffset = isBackward + ? selection.anchor.offset + : selection.focus.offset; + const endOffset = isBackward + ? selection.focus.offset + : selection.anchor.offset; + // If the content is the same as inserted, then don't dispatch an insertion. + // Given onInput doesn't take the current selection (it uses the previous) + // we can compare that against what the DOM currently says. + if ( + !CAN_USE_BEFORE_INPUT || + selection.isCollapsed() || + !$isTextNode(anchorNode) || + domSelection.anchorNode === null || + anchorNode.getTextContent().slice(0, startOffset) + + data + + anchorNode.getTextContent().slice(startOffset + endOffset) !== + getAnchorTextFromDOM(domSelection.anchorNode) + ) { + dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data); + } - const textLength = data.length; + const textLength = data.length; - // Another hack for FF, as it's possible that the IME is still - // open, even though compositionend has already fired (sigh). - if ( - IS_FIREFOX && - textLength > 1 && - event.inputType === 'insertCompositionText' && - !editor.isComposing() - ) { - selection.anchor.offset -= textLength; - } + // Another hack for FF, as it's possible that the IME is still + // open, even though compositionend has already fired (sigh). + if ( + IS_FIREFOX && + textLength > 1 && + event.inputType === 'insertCompositionText' && + !editor.isComposing() + ) { + selection.anchor.offset -= textLength; + } - // This ensures consistency on Android. - if (!IS_SAFARI && !IS_IOS && !IS_APPLE_WEBKIT && editor.isComposing()) { - lastKeyDownTimeStamp = 0; - $setCompositionKey(null); - } - } else { - const characterData = data !== null ? data : undefined; - $updateSelectedTextFromDOM(false, editor, characterData); + // This ensures consistency on Android. + if (!IS_SAFARI && !IS_IOS && !IS_APPLE_WEBKIT && editor.isComposing()) { + lastKeyDownTimeStamp = 0; + $setCompositionKey(null); + } + } else { + const characterData = data !== null ? data : undefined; + $updateSelectedTextFromDOM(false, editor, characterData); - // onInput always fires after onCompositionEnd for FF. - if (isFirefoxEndingComposition) { - $onCompositionEndImpl(editor, data || undefined); - isFirefoxEndingComposition = false; + // onInput always fires after onCompositionEnd for FF. + if (isFirefoxEndingComposition) { + $onCompositionEndImpl(editor, data || undefined); + isFirefoxEndingComposition = false; + } } - } - // Also flush any other mutations that might have occurred - // since the change. - $flushMutations(); - }); + // Also flush any other mutations that might have occurred + // since the change. + $flushMutations(); + }, + {event}, + ); unprocessedBeforeInputData = null; } @@ -901,7 +915,7 @@ function onCompositionStart( event: CompositionEvent, editor: LexicalEditor, ): void { - updateEditor(editor, () => { + updateEditorSync(editor, () => { const selection = $getSelection(); if ($isRangeSelection(selection) && !editor.isComposing()) { @@ -994,8 +1008,16 @@ function onCompositionEnd( // the logic in onInput. if (IS_FIREFOX) { isFirefoxEndingComposition = true; + } else if (!IS_IOS && (IS_SAFARI || IS_APPLE_WEBKIT)) { + // Fix:https://github.com/facebook/lexical/pull/7061 + // In safari, onCompositionEnd triggers before keydown + // This will cause an extra character to be deleted when exiting the IME + // Therefore, a flag is used to mark that the keydown event is triggered after onCompositionEnd + // Ensure that an extra character is not deleted due to the backspace event being triggered in the keydown event. + isSafariEndingComposition = true; + safariEndCompositionEventData = event.data; } else { - updateEditor(editor, () => { + updateEditorSync(editor, () => { $onCompositionEndImpl(editor, event.data); }); } @@ -1017,6 +1039,14 @@ function onKeyDown(event: KeyboardEvent, editor: LexicalEditor): void { if (key == null) { return; } + if (isSafariEndingComposition && isBackspace(lastKeyCode)) { + updateEditorSync(editor, () => { + $onCompositionEndImpl(editor, safariEndCompositionEventData); + }); + isSafariEndingComposition = false; + safariEndCompositionEventData = ''; + return; + } if (isMoveForward(key, ctrlKey, altKey, metaKey)) { dispatchCommand(editor, KEY_ARROW_RIGHT_COMMAND, event); @@ -1133,14 +1163,7 @@ function getRootElementRemoveHandles( const activeNestedEditorsMap: Map = new Map(); function onDocumentSelectionChange(event: Event): void { - const target = event.target as null | Element | Document; - const targetWindow = - target == null - ? null - : target.nodeType === 9 - ? (target as Document).defaultView - : (target as Element).ownerDocument.defaultView; - const domSelection = getDOMSelection(targetWindow); + const domSelection = getDOMSelectionFromTarget(event.target); if (domSelection === null) { return; } @@ -1151,27 +1174,22 @@ function onDocumentSelectionChange(event: Event): void { if (isSelectionChangeFromMouseDown) { isSelectionChangeFromMouseDown = false; - updateEditor(nextActiveEditor, () => { + updateEditorSync(nextActiveEditor, () => { const lastSelection = $getPreviousSelection(); const domAnchorNode = domSelection.anchorNode; - if (domAnchorNode === null) { - return; - } - const nodeType = domAnchorNode.nodeType; - // If the user is attempting to click selection back onto text, then - // we should attempt create a range selection. - // When we click on an empty paragraph node or the end of a paragraph that ends - // with an image/poll, the nodeType will be ELEMENT_NODE - if (nodeType !== DOM_ELEMENT_TYPE && nodeType !== DOM_TEXT_TYPE) { - return; + if (isHTMLElement(domAnchorNode) || isDOMTextNode(domAnchorNode)) { + // If the user is attempting to click selection back onto text, then + // we should attempt create a range selection. + // When we click on an empty paragraph node or the end of a paragraph that ends + // with an image/poll, the nodeType will be ELEMENT_NODE + const newSelection = $internalCreateRangeSelection( + lastSelection, + domSelection, + nextActiveEditor, + event, + ); + $setSelection(newSelection); } - const newSelection = $internalCreateRangeSelection( - lastSelection, - domSelection, - nextActiveEditor, - event, - ); - $setSelection(newSelection); }); } diff --git a/packages/lexical/src/LexicalMutations.ts b/packages/lexical/src/LexicalMutations.ts index f4864f60f67..01ed4eac1e6 100644 --- a/packages/lexical/src/LexicalMutations.ts +++ b/packages/lexical/src/LexicalMutations.ts @@ -21,8 +21,7 @@ import { $isTextNode, $setSelection, } from '.'; -import {DOM_TEXT_TYPE} from './LexicalConstants'; -import {updateEditor} from './LexicalUpdates'; +import {updateEditorSync} from './LexicalUpdates'; import { $getNodeByKey, $getNodeFromDOMNode, @@ -32,6 +31,7 @@ import { getParentElement, getWindow, internalGetRoot, + isDOMTextNode, isDOMUnmanaged, isFirefoxClipboardEvents, isHTMLElement, @@ -83,7 +83,7 @@ function $handleTextMutation( node: TextNode, editor: LexicalEditor, ): void { - const domSelection = getDOMSelection(editor._window); + const domSelection = getDOMSelection(getWindow(editor)); let anchorOffset = null; let focusOffset = null; @@ -112,7 +112,7 @@ function shouldUpdateTextNodeFromMutation( return false; } } - return targetDOM.nodeType === DOM_TEXT_TYPE && targetNode.isAttached(); + return isDOMTextNode(targetDOM) && targetNode.isAttached(); } function $getNearestManagedNodePairFromDOMNode( @@ -141,7 +141,7 @@ function $getNearestManagedNodePairFromDOMNode( } } -export function $flushMutations( +function flushMutations( editor: LexicalEditor, mutations: Array, observer: MutationObserver, @@ -149,9 +149,8 @@ export function $flushMutations( isProcessingMutations = true; const shouldFlushTextMutations = performance.now() - lastTextEntryTimeStamp > TEXT_MUTATION_VARIANCE; - try { - updateEditor(editor, () => { + updateEditorSync(editor, () => { const selection = $getSelection() || getLastSelection(editor); const badDOMTargets = new Map(); const rootElement = editor.getRootElement(); @@ -183,14 +182,10 @@ export function $flushMutations( if ( shouldFlushTextMutations && $isTextNode(targetNode) && + isDOMTextNode(targetDOM) && shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode) ) { - $handleTextMutation( - // nodeType === DOM_TEXT_TYPE is a Text DOM node - targetDOM as Text, - targetNode, - editor, - ); + $handleTextMutation(targetDOM, targetNode, editor); } } else if (type === 'childList') { shouldRevertSelection = true; @@ -293,7 +288,6 @@ export function $flushMutations( if (selection !== null) { if (shouldRevertSelection) { - selection.dirty = true; $setSelection(selection); } @@ -307,12 +301,12 @@ export function $flushMutations( } } -export function $flushRootMutations(editor: LexicalEditor): void { +export function flushRootMutations(editor: LexicalEditor): void { const observer = editor._observer; if (observer !== null) { const mutations = observer.takeRecords(); - $flushMutations(editor, mutations, observer); + flushMutations(editor, mutations, observer); } } @@ -320,7 +314,7 @@ export function initMutationObserver(editor: LexicalEditor): void { initTextEntryListener(editor); editor._observer = new MutationObserver( (mutations: Array, observer: MutationObserver) => { - $flushMutations(editor, mutations, observer); + flushMutations(editor, mutations, observer); }, ); } diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index d39db3ea387..0a8ab879205 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -51,12 +51,25 @@ import { export type NodeMap = Map; +/** + * The base type for all serialized nodes + */ export type SerializedLexicalNode = { + /** The type string used by the Node class */ type: string; + /** A numeric version for this schema, defaulting to 1, but not generally recommended for use */ version: number; state?: State; }; +/** + * Omit the children, type, and version properties from the given SerializedLexicalNode definition. + */ +export type LexicalUpdateJSON = Omit< + T, + 'children' | 'type' | 'version' +>; + /** @internal */ export interface LexicalPrivateDOM { __lexicalTextContent?: string | undefined | null; @@ -892,7 +905,7 @@ export class LexicalNode { * */ exportJSON(): SerializedLexicalNode { return { - type: this.constructor.getType(), + type: this.__type, version: 1, ...(objetcIsEmpty(this.__state) ? {} : {state: this.__state}), }; @@ -912,6 +925,41 @@ export class LexicalNode { this.name, ); } + + /** + * Update this LexicalNode instance from serialized JSON. It's recommended + * to implement as much logic as possible in this method instead of the + * static importJSON method, so that the functionality can be inherited in subclasses. + * + * The LexicalUpdateJSON utility type should be used to ignore any type, version, + * or children properties in the JSON so that the extended JSON from subclasses + * are acceptable parameters for the super call. + * + * If overridden, this method must call super. + * + * @example + * ```ts + * class MyTextNode extends TextNode { + * // ... + * static importJSON(serializedNode: SerializedMyTextNode): MyTextNode { + * return $createMyTextNode() + * .updateFromJSON(serializedNode); + * } + * updateFromJSON( + * serializedNode: LexicalUpdateJSON, + * ): this { + * return super.updateFromJSON(serializedNode) + * .setMyProperty(serializedNode.myProperty); + * } + * } + * ``` + **/ + updateFromJSON( + serializedNode: LexicalUpdateJSON, + ): this { + return this; + } + /** * @experimental * diff --git a/packages/lexical/src/LexicalNormalization.ts b/packages/lexical/src/LexicalNormalization.ts index 59a7be64489..0c9d5406515 100644 --- a/packages/lexical/src/LexicalNormalization.ts +++ b/packages/lexical/src/LexicalNormalization.ts @@ -110,6 +110,7 @@ function $normalizePoint(point: PointType): void { nextNode.__key, nextOffsetAtEnd ? nextNode.getTextContentSize() : 0, 'text', + true, ); break; } else if (!$isElementNode(nextNode)) { @@ -119,6 +120,7 @@ function $normalizePoint(point: PointType): void { nextNode.__key, nextOffsetAtEnd ? nextNode.getChildrenSize() : 0, 'element', + true, ); } } diff --git a/packages/lexical/src/LexicalReconciler.ts b/packages/lexical/src/LexicalReconciler.ts index 6fa946f61d6..091ab3436fe 100644 --- a/packages/lexical/src/LexicalReconciler.ts +++ b/packages/lexical/src/LexicalReconciler.ts @@ -23,7 +23,6 @@ import { $isDecoratorNode, $isElementNode, $isLineBreakNode, - $isParagraphNode, $isRootNode, $isTextNode, } from '.'; @@ -332,9 +331,8 @@ function reconcileElementTerminatingLineBreak( } } -function reconcileParagraphFormat(element: ElementNode): void { +function reconcileTextFormat(element: ElementNode): void { if ( - $isParagraphNode(element) && subTreeTextFormat != null && subTreeTextFormat !== element.__textFormat && !activeEditorStateReadOnly @@ -344,9 +342,8 @@ function reconcileParagraphFormat(element: ElementNode): void { } } -function reconcileParagraphStyle(element: ElementNode): void { +function reconcileTextStyle(element: ElementNode): void { if ( - $isParagraphNode(element) && subTreeTextStyle !== '' && subTreeTextStyle !== element.__textStyle && !activeEditorStateReadOnly @@ -438,8 +435,8 @@ function $reconcileChildrenWithDirection( subTreeTextStyle = ''; $reconcileChildren(prevElement, nextElement, nextElement.getDOMSlot(dom)); reconcileBlockDirection(nextElement, dom); - reconcileParagraphFormat(nextElement); - reconcileParagraphStyle(nextElement); + reconcileTextFormat(nextElement); + reconcileTextStyle(nextElement); subTreeDirectionedTextContent = previousSubTreeDirectionTextContent; } diff --git a/packages/lexical/src/LexicalSelection.ts b/packages/lexical/src/LexicalSelection.ts index fb7a62dbea0..a071dc3111c 100644 --- a/packages/lexical/src/LexicalSelection.ts +++ b/packages/lexical/src/LexicalSelection.ts @@ -21,20 +21,20 @@ import { $isDecoratorNode, $isElementNode, $isLineBreakNode, - $isParagraphNode, $isRootNode, $isTextNode, $setSelection, SELECTION_CHANGE_COMMAND, TextNode, } from '.'; -import {DOM_ELEMENT_TYPE, TEXT_TYPE_TO_FORMAT} from './LexicalConstants'; +import {TEXT_TYPE_TO_FORMAT} from './LexicalConstants'; import { markCollapsedSelectionFormat, markSelectionChangeFromDOMUpdate, } from './LexicalEvents'; import {getIsProcessingMutations} from './LexicalMutations'; import {insertRangeAfter, LexicalNode} from './LexicalNode'; +import {$normalizeSelection} from './LexicalNormalization'; import { getActiveEditor, getActiveEditorState, @@ -56,7 +56,9 @@ import { getDOMTextNode, getElementByKeyOrThrow, getTextNodeOffset, + getWindow, INTERNAL_$isBlock, + isHTMLElement, isSelectionCapturedInDecoratorInput, isSelectionWithinEditor, removeDOMBlockCursorElement, @@ -72,7 +74,12 @@ export type TextPointType = { isBefore: (point: PointType) => boolean; key: NodeKey; offset: number; - set: (key: NodeKey, offset: number, type: 'text' | 'element') => void; + set: ( + key: NodeKey, + offset: number, + type: 'text' | 'element', + onlyIfChanged?: boolean, + ) => void; type: 'text'; }; @@ -83,7 +90,12 @@ export type ElementPointType = { isBefore: (point: PointType) => boolean; key: NodeKey; offset: number; - set: (key: NodeKey, offset: number, type: 'text' | 'element') => void; + set: ( + key: NodeKey, + offset: number, + type: 'text' | 'element', + onlyIfChanged?: boolean, + ) => void; type: 'element'; }; @@ -96,6 +108,14 @@ export class Point { _selection: BaseSelection | null; constructor(key: NodeKey, offset: number, type: 'text' | 'element') { + if (__DEV__) { + // This prevents a circular reference error when serialized as JSON, + // which happens on unit test failures + Object.defineProperty(this, '_selection', { + enumerable: false, + writable: true, + }); + } this._selection = null; this.key = key; this.offset = offset; @@ -139,9 +159,22 @@ export class Point { return node; } - set(key: NodeKey, offset: number, type: 'text' | 'element'): void { + set( + key: NodeKey, + offset: number, + type: 'text' | 'element', + onlyIfChanged?: boolean, + ): void { const selection = this._selection; const oldKey = this.key; + if ( + onlyIfChanged && + this.key === key && + this.offset === offset && + this.type === type + ) { + return; + } this.key = key; this.offset = offset; this.type = type; @@ -235,17 +268,6 @@ function $transferStartingElementPointToTextPoint( start.set(textNode.__key, 0, 'text'); } -function $setPointValues( - point: PointType, - key: NodeKey, - offset: number, - type: 'text' | 'element', -): void { - point.key = key; - point.offset = offset; - point.type = type; -} - export interface BaseSelection { _cachedNodes: Array | null; dirty: boolean; @@ -473,6 +495,10 @@ export class RangeSelection implements BaseSelection { const lastPoint = isBefore ? focus : anchor; let firstNode = firstPoint.getNode(); let lastNode = lastPoint.getNode(); + const overselectedFirstNode = + $isElementNode(firstNode) && + firstPoint.offset > 0 && + firstPoint.offset >= firstNode.getChildrenSize(); const startOffset = firstPoint.offset; const endOffset = lastPoint.offset; @@ -506,6 +532,13 @@ export class RangeSelection implements BaseSelection { } } else { nodes = firstNode.getNodesBetween(lastNode); + // Prevent over-selection due to the edge case of getDescendantByIndex always returning something #6974 + if (overselectedFirstNode) { + const deleteCount = nodes.findIndex( + (node) => !node.is(firstNode) && !node.isBefore(firstNode), + ); + nodes.splice(0, deleteCount); + } } if (!isCurrentlyReadOnlyMode()) { this._cachedNodes = nodes; @@ -527,10 +560,8 @@ export class RangeSelection implements BaseSelection { focusNode: TextNode, focusOffset: number, ): void { - $setPointValues(this.anchor, anchorNode.__key, anchorOffset, 'text'); - $setPointValues(this.focus, focusNode.__key, focusOffset, 'text'); - this._cachedNodes = null; - this.dirty = true; + this.anchor.set(anchorNode.__key, anchorOffset, 'text'); + this.focus.set(focusNode.__key, focusOffset, 'text'); } /** @@ -622,19 +653,16 @@ export class RangeSelection implements BaseSelection { return; } const [anchorPoint, focusPoint] = resolvedSelectionPoints; - $setPointValues( - this.anchor, + this.anchor.set( anchorPoint.key, anchorPoint.offset, anchorPoint.type, + true, ); - $setPointValues( - this.focus, - focusPoint.key, - focusPoint.offset, - focusPoint.type, - ); - this._cachedNodes = null; + this.focus.set(focusPoint.key, focusPoint.offset, focusPoint.type, true); + // Firefox will use an element point rather than a text point in some cases, + // so we normalize for that + $normalizeSelection(this); } /** @@ -1123,13 +1151,13 @@ export class RangeSelection implements BaseSelection { firstNode.isToken() && firstPoint.offset < firstNode.getTextContentSize() ) { - firstPoint.offset = 0; + firstPoint.set(firstNode.getKey(), 0, 'text'); } if (lastPoint.offset > 0 && $isTextNode(lastNode) && lastNode.isToken()) { - lastPoint.offset = lastNode.getTextContentSize(); + lastPoint.set(lastNode.getKey(), lastNode.getTextContentSize(), 'text'); } - selectedNodes.forEach((node) => { + for (const node of selectedNodes) { if ( !$hasAncestor(firstNode, node) && !$hasAncestor(lastNode, node) && @@ -1138,7 +1166,7 @@ export class RangeSelection implements BaseSelection { ) { node.remove(); } - }); + } const fixText = (node: TextNode, del: number) => { if (node.getTextContent() === '') { @@ -1180,6 +1208,7 @@ export class RangeSelection implements BaseSelection { } } + // TO-DO: Migrate this method to the new utility function $forEachSelectedTextNode (share similar logic) /** * Applies the provided format to the TextNodes in the Selection, splitting or * merging nodes as necessary. @@ -1205,9 +1234,9 @@ export class RangeSelection implements BaseSelection { selectedTextNodes.push(selectedNode); } } - const applyFormatToParagraphs = (alignWith: number | null) => { + const applyFormatToElements = (alignWith: number | null) => { selectedNodes.forEach((node) => { - if ($isParagraphNode(node)) { + if ($isElementNode(node)) { const newFormat = node.getFormatFlags(formatType, alignWith); node.setTextFormat(newFormat); } @@ -1219,7 +1248,7 @@ export class RangeSelection implements BaseSelection { this.toggleFormat(formatType); // When changing format, we should stop composition $setCompositionKey(null); - applyFormatToParagraphs(alignWithFormat); + applyFormatToElements(alignWithFormat); return; } @@ -1251,7 +1280,7 @@ export class RangeSelection implements BaseSelection { formatType, alignWithFormat, ); - applyFormatToParagraphs(firstNextFormat); + applyFormatToElements(firstNextFormat); const lastIndex = selectedTextNodesLength - 1; let lastNode = selectedTextNodes[lastIndex]; @@ -1612,7 +1641,7 @@ export class RangeSelection implements BaseSelection { } } const editor = getActiveEditor(); - const domSelection = getDOMSelection(editor._window); + const domSelection = getDOMSelection(getWindow(editor)); if (!domSelection) { return; @@ -1947,9 +1976,8 @@ function $swapPoints(selection: RangeSelection): void { const anchorOffset = anchor.offset; const anchorType = anchor.type; - $setPointValues(anchor, focus.key, focus.offset, focus.type); - $setPointValues(focus, anchorKey, anchorOffset, anchorType); - selection._cachedNodes = null; + anchor.set(focus.key, focus.offset, focus.type, true); + focus.set(anchorKey, anchorOffset, anchorType, true); } function moveNativeSelection( @@ -1989,9 +2017,9 @@ function $updateCaretSelectionForUnicodeCharacter( const text = anchorNode.getTextContent().slice(startOffset, endOffset); if (!doesContainGrapheme(text)) { if (isBackward) { - focus.offset = characterOffset; + focus.set(focus.key, characterOffset, focus.type); } else { - anchor.offset = characterOffset; + anchor.set(anchor.key, characterOffset, anchor.type); } } } @@ -2066,7 +2094,7 @@ function $internalResolveSelectionPoint( // need to figure out (using the offset) what text // node should be selected. - if (dom.nodeType === DOM_ELEMENT_TYPE) { + if (isHTMLElement(dom)) { // Resolve element to a ElementNode, or TextNode, or null let moveSelectionToEnd = false; // Given we're moving selection to another node, selection is @@ -2212,13 +2240,13 @@ function resolveSelectionPointOnBoundary( !isCollapsed && prevSibling.isInline() ) { - point.key = prevSibling.__key; - point.offset = prevSibling.getChildrenSize(); - // @ts-expect-error: intentional - point.type = 'element'; + point.set(prevSibling.__key, prevSibling.getChildrenSize(), 'element'); } else if ($isTextNode(prevSibling)) { - point.key = prevSibling.__key; - point.offset = prevSibling.getTextContent().length; + point.set( + prevSibling.__key, + prevSibling.getTextContent().length, + 'text', + ); } } else if ( (isCollapsed || !isBackward) && @@ -2228,8 +2256,11 @@ function resolveSelectionPointOnBoundary( ) { const parentSibling = parent.getPreviousSibling(); if ($isTextNode(parentSibling)) { - point.key = parentSibling.__key; - point.offset = parentSibling.getTextContent().length; + point.set( + parentSibling.__key, + parentSibling.getTextContent().length, + 'text', + ); } } } else if (offset === node.getTextContent().length) { @@ -2237,10 +2268,7 @@ function resolveSelectionPointOnBoundary( const parent = node.getParent(); if (isBackward && $isElementNode(nextSibling) && nextSibling.isInline()) { - point.key = nextSibling.__key; - point.offset = 0; - // @ts-expect-error: intentional - point.type = 'element'; + point.set(nextSibling.__key, 0, 'element'); } else if ( (isCollapsed || isBackward) && nextSibling === null && @@ -2250,8 +2278,7 @@ function resolveSelectionPointOnBoundary( ) { const parentSibling = parent.getNextSibling(); if ($isTextNode(parentSibling)) { - point.key = parentSibling.__key; - point.offset = 0; + point.set(parentSibling.__key, 0, 'text'); } } } @@ -2272,9 +2299,7 @@ function $normalizeSelectionPointsForBoundaries( resolveSelectionPointOnBoundary(focus, !isBackward, isCollapsed); if (isCollapsed) { - focus.key = anchor.key; - focus.offset = anchor.offset; - focus.type = anchor.type; + focus.set(anchor.key, anchor.offset, anchor.type); } const editor = getActiveEditor(); @@ -2285,13 +2310,8 @@ function $normalizeSelectionPointsForBoundaries( ) { const lastAnchor = lastSelection.anchor; const lastFocus = lastSelection.focus; - $setPointValues( - anchor, - lastAnchor.key, - lastAnchor.offset, - lastAnchor.type, - ); - $setPointValues(focus, lastFocus.key, lastFocus.offset, lastFocus.type); + anchor.set(lastAnchor.key, lastAnchor.offset, lastAnchor.type, true); + focus.set(lastFocus.key, lastFocus.offset, lastFocus.type, true); } } } @@ -2320,9 +2340,6 @@ function $internalResolveSelectionPoints( if (resolvedAnchorPoint === null) { return null; } - if (__DEV__) { - $validatePoint(editor, 'anchor', resolvedAnchorPoint); - } const resolvedFocusPoint = $internalResolveSelectionPoint( focusDOM, focusOffset, @@ -2333,6 +2350,7 @@ function $internalResolveSelectionPoints( return null; } if (__DEV__) { + $validatePoint(editor, 'anchor', resolvedAnchorPoint); $validatePoint(editor, 'focus', resolvedAnchorPoint); } if ( @@ -2401,17 +2419,18 @@ export function $createNodeSelection(): NodeSelection { export function $internalCreateSelection( editor: LexicalEditor, + event: UIEvent | Event | null, ): null | BaseSelection { const currentEditorState = editor.getEditorState(); const lastSelection = currentEditorState._selection; - const domSelection = getDOMSelection(editor._window); + const domSelection = getDOMSelection(getWindow(editor)); if ($isRangeSelection(lastSelection) || lastSelection == null) { return $internalCreateRangeSelection( lastSelection, domSelection, editor, - null, + event, ); } return lastSelection.clone(); @@ -2754,12 +2773,9 @@ export function adjustPointOffsetForMergedSibling( textLength: number, ): void { if (point.type === 'text') { - point.key = key; - if (!isBefore) { - point.offset += textLength; - } + point.set(key, point.offset + (isBefore ? 0 : textLength), 'text'); } else if (point.offset > target.getIndexWithinParent()) { - point.offset -= 1; + point.set(point.key, point.offset - 1, 'element'); } } @@ -2904,7 +2920,7 @@ export function updateDOMSelection( rootElement === document.activeElement ) { const selectionTarget: null | Range | HTMLElement | Text = - nextSelection instanceof RangeSelection && + $isRangeSelection(nextSelection) && nextSelection.anchor.type === 'element' ? (nextAnchorNode.childNodes[nextAnchorOffset] as HTMLElement | Text) || null @@ -2966,7 +2982,11 @@ function $removeTextAndSplitBlock(selection: RangeSelection): number { let offset = anchor.offset; while (!INTERNAL_$isBlock(node)) { + const prevNode = node; [node, offset] = $splitNodeAtPoint(node, offset); + if (prevNode.is(node)) { + break; + } } return offset; diff --git a/packages/lexical/src/LexicalUpdates.ts b/packages/lexical/src/LexicalUpdates.ts index 1b2a83070dc..542b2cf20bb 100644 --- a/packages/lexical/src/LexicalUpdates.ts +++ b/packages/lexical/src/LexicalUpdates.ts @@ -51,6 +51,7 @@ import { getEditorStateTextContent, getEditorsToPropagate, getRegisteredNodeOrThrow, + getWindow, isLexicalEditor, removeDOMBlockCursorElement, scheduleMicroTask, @@ -599,7 +600,9 @@ export function $commitPendingUpdates( // Reconciliation has finished. Now update selection and trigger listeners. // ====== - const domSelection = shouldSkipDOM ? null : getDOMSelection(editor._window); + const domSelection = shouldSkipDOM + ? null + : getDOMSelection(getWindow(editor)); // Attempt to update the DOM selection, including focusing of the root element, // and scroll into view if needed. @@ -633,10 +636,10 @@ export function $commitPendingUpdates( ); } updateDOMBlockCursorElement(editor, rootElement, pendingSelection); + } finally { if (observer !== null) { observer.observe(rootElement, observerOptions); } - } finally { activeEditor = previousActiveEditor; activeEditorState = previousActiveEditorState; } @@ -909,15 +912,19 @@ function $beginUpdate( isReadOnlyMode = false; editor._updating = true; activeEditor = editor; + const headless = editor._headless || editor.getRootElement() === null; try { if (editorStateWasCloned) { - if (editor._headless) { + if (headless) { if (currentEditorState._selection !== null) { pendingEditorState._selection = currentEditorState._selection.clone(); } } else { - pendingEditorState._selection = $internalCreateSelection(editor); + pendingEditorState._selection = $internalCreateSelection( + editor, + (options && options.event) || null, + ); } } @@ -1022,6 +1029,25 @@ function $beginUpdate( } } +/** + * A variant of updateEditor that will not defer if it is nested in an update + * to the same editor, much like if it was an editor.dispatchCommand issued + * within an update + */ +export function updateEditorSync( + editor: LexicalEditor, + updateFn: () => void, + options?: EditorUpdateOptions, +): void { + if (!editor._updating) { + $beginUpdate(editor, updateFn, options); + } else if (activeEditor === editor) { + updateFn(); + } else { + editor._updates.push([updateFn, options]); + } +} + export function updateEditor( editor: LexicalEditor, updateFn: () => void, diff --git a/packages/lexical/src/LexicalUtils.ts b/packages/lexical/src/LexicalUtils.ts index de2e019dd20..695d45d05c2 100644 --- a/packages/lexical/src/LexicalUtils.ts +++ b/packages/lexical/src/LexicalUtils.ts @@ -55,6 +55,9 @@ import { } from '.'; import { COMPOSITION_SUFFIX, + DOM_DOCUMENT_FRAGMENT_TYPE, + DOM_DOCUMENT_TYPE, + DOM_ELEMENT_TYPE, DOM_TEXT_TYPE, HAS_DIRTY_NODES, LTR_REGEX, @@ -62,7 +65,7 @@ import { TEXT_TYPE_TO_FORMAT, } from './LexicalConstants'; import {LexicalEditor} from './LexicalEditor'; -import {$flushRootMutations} from './LexicalMutations'; +import {flushRootMutations} from './LexicalMutations'; import {$normalizeSelection} from './LexicalNormalization'; import { errorOnInfiniteTransforms, @@ -193,8 +196,20 @@ export function $isTokenOrSegmented(node: TextNode): boolean { return node.isToken() || node.isSegmented(); } -export function isDOMTextNode(node: Node): node is Text { - return node.nodeType === DOM_TEXT_TYPE; +/** + * @param node - The element being tested + * @returns Returns true if node is an DOM Text node, false otherwise. + */ +export function isDOMTextNode(node: unknown): node is Text { + return isDOMNode(node) && node.nodeType === DOM_TEXT_TYPE; +} + +/** + * @param node - The element being tested + * @returns Returns true if node is an DOM Document node, false otherwise. + */ +export function isDOMDocumentNode(node: unknown): node is Document { + return isDOMNode(node) && node.nodeType === DOM_DOCUMENT_TYPE; } export function getDOMTextNode(element: Node | null): Text | null { @@ -528,8 +543,13 @@ export function markNodesWithTypesAsDirty( editor.update( () => { for (const nodeMap of dirtyNodeMaps) { - for (const node of nodeMap.values()) { - node.markDirty(); + for (const nodeKey of nodeMap.keys()) { + // We are only concerned with nodes that are still in the latest NodeMap, + // if they no longer exist then markDirty would raise an exception + const latest = $getNodeByKey(nodeKey); + if (latest) { + latest.markDirty(); + } } } }, @@ -570,7 +590,7 @@ export function $setSelection(selection: null | BaseSelection): void { export function $flushMutations(): void { errorOnReadOnly(); const editor = getActiveEditor(); - $flushRootMutations(editor); + flushRootMutations(editor); } export function $getNodeFromDOM(dom: Node): null | LexicalNode { @@ -633,10 +653,7 @@ export function createUID(): string { } export function getAnchorTextFromDOM(anchorNode: Node): null | string { - if (anchorNode.nodeType === DOM_TEXT_TYPE) { - return anchorNode.nodeValue; - } - return null; + return isDOMTextNode(anchorNode) ? anchorNode.nodeValue : null; } export function $updateSelectedTextFromDOM( @@ -645,7 +662,7 @@ export function $updateSelectedTextFromDOM( data?: string, ): void { // Update the text content with the latest composition text - const domSelection = getDOMSelection(editor._window); + const domSelection = getDOMSelection(getWindow(editor)); if (domSelection === null) { return; } @@ -1304,15 +1321,25 @@ export function getParentElement(node: Node): HTMLElement | null { : parentElement; } +export function getDOMOwnerDocument( + target: EventTarget | null, +): Document | null { + return isDOMDocumentNode(target) + ? target + : isHTMLElement(target) + ? target.ownerDocument + : null; +} + export function scrollIntoViewIfNeeded( editor: LexicalEditor, selectionRect: DOMRect, rootElement: HTMLElement, ): void { - const doc = rootElement.ownerDocument; - const defaultView = doc.defaultView; + const doc = getDOMOwnerDocument(rootElement); + const defaultView = getDefaultView(doc); - if (defaultView === null) { + if (doc === null || defaultView === null) { return; } let {top: currentTop, bottom: currentBottom} = selectionRect; @@ -1414,9 +1441,9 @@ export function $hasAncestor( return false; } -export function getDefaultView(domElem: HTMLElement): Window | null { - const ownerDoc = domElem.ownerDocument; - return (ownerDoc && ownerDoc.defaultView) || null; +export function getDefaultView(domElem: EventTarget | null): Window | null { + const ownerDoc = getDOMOwnerDocument(domElem); + return ownerDoc ? ownerDoc.defaultView : null; } export function getWindow(editor: LexicalEditor): Window { @@ -1658,6 +1685,19 @@ export function getDOMSelection(targetWindow: null | Window): null | Selection { return !CAN_USE_DOM ? null : (targetWindow || window).getSelection(); } +/** + * Returns the selection for the defaultView of the ownerDocument of given EventTarget. + * + * @param eventTarget The node to get the selection from + * @returns a Selection or null + */ +export function getDOMSelectionFromTarget( + eventTarget: null | EventTarget, +): null | Selection { + const defaultView = getDefaultView(eventTarget); + return defaultView ? defaultView.getSelection() : null; +} + export function $splitNode( node: ElementNode, offset: number, @@ -1736,7 +1776,7 @@ export function isHTMLAnchorElement(x: unknown): x is HTMLAnchorElement { * @returns Returns true if x is an HTML element, false otherwise. */ export function isHTMLElement(x: unknown): x is HTMLElement { - return isDOMNode(x) && x.nodeType === 1; + return isDOMNode(x) && x.nodeType === DOM_ELEMENT_TYPE; } /** @@ -1757,7 +1797,7 @@ export function isDOMNode(x: unknown): x is Node { * @returns Returns true if x is a document fragment, false otherwise. */ export function isDocumentFragment(x: unknown): x is DocumentFragment { - return isDOMNode(x) && x.nodeType === 11; + return isDOMNode(x) && x.nodeType === DOM_DOCUMENT_FRAGMENT_TYPE; } /** @@ -1787,8 +1827,17 @@ export function isBlockDomNode(node: Node) { } /** + * @internal + * * This function is for internal use of the library. * Please do not use it as it may change in the future. + * + * This function returns true for a DecoratorNode that is not inline OR + * an ElementNode that is: + * - not a root or shadow root + * - not inline + * - can't be empty + * - has no children or an inline first child */ export function INTERNAL_$isBlock( node: LexicalNode, diff --git a/packages/lexical/src/__tests__/unit/HTMLCopyAndPaste.test.ts b/packages/lexical/src/__tests__/unit/HTMLCopyAndPaste.test.ts index b146548383c..0a6cd197873 100644 --- a/packages/lexical/src/__tests__/unit/HTMLCopyAndPaste.test.ts +++ b/packages/lexical/src/__tests__/unit/HTMLCopyAndPaste.test.ts @@ -7,6 +7,7 @@ */ import {$insertDataTransferForRichText} from '@lexical/clipboard'; +import {$patchStyleText} from '@lexical/selection'; import { $createParagraphNode, $getRoot, @@ -110,6 +111,35 @@ describe('HTMLCopyAndPaste tests', () => { expect(testEnv.innerHTML).toBe(testCase.expectedHTML); }); }); + + test('iOS fix: Word predictions should be handled as plain text to maintain selection formatting', async () => { + const {editor} = testEnv; + + const dataTransfer = new DataTransferMock(); + + // we simulate choosing an iOS Safari `autocorrect` or `word prediction` + // which pastes the word into the editor with both the `text/plain` and `text/html` data types + dataTransfer.setData('text/plain', 'Prediction'); + dataTransfer.setData('text/html', 'Prediction'); + + // to compensate, the clipboard content will only be inserted as HTML if the `text/html` content differs from the `text/plain` content + await editor.update(() => { + const selection = $getSelection(); + invariant( + $isRangeSelection(selection), + 'isRangeSelection(selection)', + ); + $patchStyleText(selection, { + 'background-color': 'rgb(255,170,45)', + }); + $insertDataTransferForRichText(dataTransfer, selection, editor); + }); + + // the editor's selection formatting is maintained because the text has been inserted as plain text + expect(testEnv.innerHTML).toBe( + '

Prediction

', + ); + }); }, { namespace: 'test', diff --git a/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx b/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx index af71d8f681c..5bfed2efef9 100644 --- a/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx +++ b/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {$generateHtmlFromNodes, $generateNodesFromDOM} from '@lexical/html'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {ContentEditable} from '@lexical/react/LexicalContentEditable'; @@ -63,6 +65,7 @@ import invariant from 'shared/invariant'; import * as ReactTestUtils from 'shared/react-test-utils'; import {emptyFunction} from '../../LexicalUtils'; +import {SerializedParagraphNode} from '../../nodes/LexicalParagraphNode'; import { $createTestDecoratorNode, $createTestElementNode, @@ -102,6 +105,10 @@ describe('LexicalEditor tests', () => { nodes: nodes ?? [], onError: onError || jest.fn(), theme: { + tableAlignment: { + center: 'editor-table-alignment-center', + right: 'editor-table-alignment-right', + }, text: { bold: 'editor-text-bold', italic: 'editor-text-italic', @@ -1016,7 +1023,7 @@ describe('LexicalEditor tests', () => { }); expect(rootListener).toHaveBeenCalledTimes(3); - expect(updateListener).toHaveBeenCalledTimes(3); + expect(updateListener).toHaveBeenCalledTimes(4); expect(container.innerHTML).toBe( '

Change successful

', ); @@ -1027,11 +1034,17 @@ describe('LexicalEditor tests', () => { editable ? 'editable' : 'non-editable' })`, async () => { const JSON_EDITOR_STATE = - '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"123","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"root","version":1}}'; + '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"123","type":"text","version":1}],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"root","version":1}}'; init(); const contentEditable = editor.getRootElement(); editor.setEditable(editable); + editor.update(() => { + // Cause the editor to become dirty, so we can ensure + // that the getEditorState()._readOnly invariant holds + $getRoot().markDirty(); + }); editor.setRootElement(null); + expect(editor.getEditorState()._readOnly).toBe(true); const editorState = editor.parseEditorState(JSON_EDITOR_STATE); editor.setEditorState(editorState); editor.update(() => { @@ -1194,6 +1207,8 @@ describe('LexicalEditor tests', () => { __prev: null, __size: 1, __style: '', + __textFormat: 0, + __textStyle: '', __type: 'root', }); expect(paragraph).toEqual({ @@ -1281,6 +1296,8 @@ describe('LexicalEditor tests', () => { __prev: null, __size: 1, __style: '', + __textFormat: 0, + __textStyle: '', __type: 'root', }); expect(parsedParagraph).toEqual({ @@ -1363,6 +1380,8 @@ describe('LexicalEditor tests', () => { __prev: null, __size: 1, __style: '', + __textFormat: 0, + __textStyle: '', __type: 'root', }); expect(parsedParagraph).toEqual({ @@ -2775,12 +2794,8 @@ describe('LexicalEditor tests', () => { return new CustomParagraphNode(node.__key); } - static importJSON() { - return new CustomParagraphNode(); - } - - exportJSON() { - return {...super.exportJSON(), type: 'custom-paragraph'}; + static importJSON(serializedNode: SerializedParagraphNode) { + return new CustomParagraphNode().updateFromJSON(serializedNode); } } diff --git a/packages/lexical/src/__tests__/unit/LexicalEditorState.test.ts b/packages/lexical/src/__tests__/unit/LexicalEditorState.test.ts index 09b49b738d7..8e6e3a6eb00 100644 --- a/packages/lexical/src/__tests__/unit/LexicalEditorState.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalEditorState.test.ts @@ -63,6 +63,8 @@ describe('LexicalEditorState tests', () => { __prev: null, __size: 1, __style: '', + __textFormat: 0, + __textStyle: '', __type: 'root', }); expect(paragraph).toEqual({ @@ -149,6 +151,8 @@ describe('LexicalEditorState tests', () => { __prev: null, __size: 0, __style: '', + __textFormat: 0, + __textStyle: '', __type: 'root', }, ], diff --git a/packages/lexical/src/__tests__/unit/LexicalListPlugin.test.tsx b/packages/lexical/src/__tests__/unit/LexicalListPlugin.test.tsx index 41c999e66dc..da669e83ec6 100644 --- a/packages/lexical/src/__tests__/unit/LexicalListPlugin.test.tsx +++ b/packages/lexical/src/__tests__/unit/LexicalListPlugin.test.tsx @@ -5,14 +5,23 @@ * LICENSE file in the root directory of this source tree. * */ + +import type {JSX} from 'react'; + import {ListItemNode, ListNode} from '@lexical/list'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {ContentEditable} from '@lexical/react/LexicalContentEditable'; import {LexicalErrorBoundary} from '@lexical/react/LexicalErrorBoundary'; import {ListPlugin} from '@lexical/react/LexicalListPlugin'; import {RichTextPlugin} from '@lexical/react/LexicalRichTextPlugin'; +import {$setBlocksType} from '@lexical/selection'; import { + $createParagraphNode, + $createTextNode, + $getSelection, + $insertNodes, INDENT_CONTENT_COMMAND, + KEY_ENTER_COMMAND, LexicalEditor, OUTDENT_CONTENT_COMMAND, } from 'lexical'; @@ -209,4 +218,83 @@ describe('@lexical/list tests', () => { `, ); }); + + test('$setBlocksType does not cause invalid ListItemNode children - regression #7036', async () => { + ReactTestUtils.act(() => { + reactRoot.render(); + }); + + await ReactTestUtils.act(async () => { + await editor.update(() => { + editor.focus(); + editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined); + $insertNodes([$createTextNode('First item')]); + editor.dispatchCommand(KEY_ENTER_COMMAND, null); + editor.dispatchCommand(INDENT_CONTENT_COMMAND, undefined); + $insertNodes([$createTextNode('Nested item')]); + editor.dispatchCommand(KEY_ENTER_COMMAND, null); + $setBlocksType($getSelection(), $createParagraphNode); + }); + }); + expectHtmlToBeEqual( + container.innerHTML, + html` +
+
    +
  • + First item +
  • +
  • +
      +
    • + Nested item +
    • +
    +
  • +
+


+
+ `, + ); + await ReactTestUtils.act(async () => { + await editor.update(() => { + $insertNodes([$createTextNode('more text')]); + editor.dispatchCommand(KEY_ENTER_COMMAND, null); + $insertNodes([$createTextNode('even more text')]); + }); + }); + expectHtmlToBeEqual( + container.innerHTML, + html` +
+
    +
  • + First item +
  • +
  • +
      +
    • + Nested item +
    • +
    +
  • +
+

+ more text +

+

even more text

+
+ `, + ); + }); }); diff --git a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts index 7373f898d80..3210f2ad5d1 100644 --- a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts @@ -21,6 +21,7 @@ import { NodeKey, ParagraphNode, RangeSelection, + SerializedLexicalNode, SerializedTextNode, TextNode, } from 'lexical'; @@ -48,12 +49,8 @@ class TestNode extends LexicalNode { return document.createElement('div'); } - static importJSON() { - return new TestNode(); - } - - exportJSON() { - return {type: 'test', version: 1}; + static importJSON(serializedNode: SerializedLexicalNode) { + return new TestNode().updateFromJSON(serializedNode); } } @@ -66,12 +63,8 @@ class InlineDecoratorNode extends DecoratorNode { return new InlineDecoratorNode(); } - static importJSON() { - return new InlineDecoratorNode(); - } - - exportJSON() { - return {type: 'inline-decorator', version: 1}; + static importJSON(serializedNode: SerializedLexicalNode) { + return new InlineDecoratorNode().updateFromJSON(serializedNode); } createDOM(): HTMLElement { @@ -166,9 +159,6 @@ describe('LexicalNode tests', () => { static importJSON(node: SerializedTextNode): VersionedTextNode { throw new Error('Not implemented'); } - exportJSON(): SerializedTextNode { - throw new Error('Not implemented'); - } afterCloneFrom(node: this): void { super.afterCloneFrom(node); this.__version = node.__version + 1; @@ -318,12 +308,8 @@ describe('LexicalNode tests', () => { return; } - selection.anchor.type = 'text'; - selection.anchor.offset = 1; - selection.anchor.key = textNode.getKey(); - selection.focus.type = 'text'; - selection.focus.offset = 1; - selection.focus.key = newTextNode.getKey(); + selection.anchor.set(textNode.getKey(), 1, 'text'); + selection.focus.set(newTextNode.getKey(), 1, 'text'); }); await Promise.resolve().then(); @@ -363,12 +349,8 @@ describe('LexicalNode tests', () => { await editor.update(() => { const rangeSelection = $createRangeSelection(); - rangeSelection.anchor.type = 'text'; - rangeSelection.anchor.offset = 1; - rangeSelection.anchor.key = textNode.getKey(); - rangeSelection.focus.type = 'text'; - rangeSelection.focus.offset = 1; - rangeSelection.focus.key = newTextNode.getKey(); + rangeSelection.anchor.set(textNode.getKey(), 1, 'text'); + rangeSelection.focus.set(newTextNode.getKey(), 1, 'text'); expect(paragraphNode.isSelected(rangeSelection)).toBe(true); expect(textNode.isSelected(rangeSelection)).toBe(true); diff --git a/packages/lexical/src/__tests__/unit/LexicalSelection.test.ts b/packages/lexical/src/__tests__/unit/LexicalSelection.test.ts index 97be0aac4f1..f0116549f43 100644 --- a/packages/lexical/src/__tests__/unit/LexicalSelection.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalSelection.test.ts @@ -24,6 +24,7 @@ import { TextNode, } from 'lexical'; +import {SerializedElementNode} from '../..'; import {$assertRangeSelection, initializeUnitTest, invariant} from '../utils'; describe('LexicalSelection tests', () => { @@ -801,15 +802,12 @@ describe('Regression tests for #6701', () => { static getType() { return 'inline-element-node'; } - static importJSON() { - return new InlineElementNode(); + static importJSON(serializedNode: SerializedElementNode) { + return new InlineElementNode().updateFromJSON(serializedNode); } isInline() { return true; } - exportJSON() { - return {...super.exportJSON(), type: this.getType()}; - } createDOM() { return document.createElement('span'); } diff --git a/packages/lexical/src/__tests__/unit/LexicalSerialization.test.ts b/packages/lexical/src/__tests__/unit/LexicalSerialization.test.ts index 9237bc9d3dd..f4d96b3c982 100644 --- a/packages/lexical/src/__tests__/unit/LexicalSerialization.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalSerialization.test.ts @@ -112,14 +112,15 @@ describe('LexicalSerialization tests', () => { const stringifiedEditorState = JSON.stringify(editor.getEditorState()); const expectedStringifiedEditorState = `{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Welcome to the playground","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"In case you were wondering what the black box at the bottom is – it's the debug view, showing the current state of the editor. You can disable it by pressing on the settings control in the bottom-left of your screen and toggling the debug view setting.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"quote","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"The playground is a demo environment built with ","type":"text","version":1},{"detail":0,"format":16,"mode":"normal","style":"","text":"@lexical/react","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":". Try typing in ","type":"text","version":1},{"detail":0,"format":1,"mode":"normal","style":"","text":"some text","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" with ","type":"text","version":1},{"detail":0,"format":2,"mode":"normal","style":"","text":"different","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" formats.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Make sure to check out the various plugins in the toolbar. You can also use #hashtags or @-mentions too!","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"If you'd like to find out more about Lexical, you can:","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""},{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Visit the ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lexical website","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://lexical.dev/"},{"detail":0,"format":0,"mode":"normal","style":"","text":" for documentation and more information.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Check out the code on our ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"GitHub repository","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://github.com/facebook/lexical"},{"detail":0,"format":0,"mode":"normal","style":"","text":".","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":2},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Playground code can be found ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"here","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://github.com/facebook/lexical/tree/main/packages/lexical-playground"},{"detail":0,"format":0,"mode":"normal","style":"","text":".","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":3},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Join our ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Discord Server","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://discord.com/invite/KmG4wQnnD9"},{"detail":0,"format":0,"mode":"normal","style":"","text":" and chat with the team.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":4}],"direction":"ltr","format":"","indent":0,"type":"list","version":1,"listType":"bullet","start":1,"tag":"ul"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lastly, we're constantly adding cool new features to this playground. So make sure you check back here when you next get a chance :).","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"const lexical = \\"awesome\\"","type":"code-highlight","version":1}],"direction":"ltr","format":"","indent":0,"type":"code","version":1,"language":"javascript"},{"children":[{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":3,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":1,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":1,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":1,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":1,"rowSpan":1}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":2,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":2,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":2,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":2,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1}],"direction":"ltr","format":"","indent":0,"type":"tablerow","version":1}],"direction":"ltr","format":"","indent":0,"type":"table","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}`; - expect(stringifiedEditorState).toBe(expectedStringifiedEditorState); + expect(JSON.parse(stringifiedEditorState)).toEqual( + JSON.parse(expectedStringifiedEditorState), + ); + // Check that this JSON round-trips const editorState = editor.parseEditorState(stringifiedEditorState); - const otherStringifiedEditorState = JSON.stringify(editorState); - - expect(otherStringifiedEditorState).toBe( - `{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Welcome to the playground","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"heading","version":1,"tag":"h1"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"In case you were wondering what the black box at the bottom is – it's the debug view, showing the current state of the editor. You can disable it by pressing on the settings control in the bottom-left of your screen and toggling the debug view setting.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"quote","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"The playground is a demo environment built with ","type":"text","version":1},{"detail":0,"format":16,"mode":"normal","style":"","text":"@lexical/react","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":". Try typing in ","type":"text","version":1},{"detail":0,"format":1,"mode":"normal","style":"","text":"some text","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" with ","type":"text","version":1},{"detail":0,"format":2,"mode":"normal","style":"","text":"different","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" formats.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Make sure to check out the various plugins in the toolbar. You can also use #hashtags or @-mentions too!","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"If you'd like to find out more about Lexical, you can:","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""},{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Visit the ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lexical website","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://lexical.dev/"},{"detail":0,"format":0,"mode":"normal","style":"","text":" for documentation and more information.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Check out the code on our ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"GitHub repository","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://github.com/facebook/lexical"},{"detail":0,"format":0,"mode":"normal","style":"","text":".","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":2},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Playground code can be found ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"here","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://github.com/facebook/lexical/tree/main/packages/lexical-playground"},{"detail":0,"format":0,"mode":"normal","style":"","text":".","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":3},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Join our ","type":"text","version":1},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Discord Server","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"link","version":1,"rel":null,"target":null,"title":null,"url":"https://discord.com/invite/KmG4wQnnD9"},{"detail":0,"format":0,"mode":"normal","style":"","text":" and chat with the team.","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"listitem","version":1,"value":4}],"direction":"ltr","format":"","indent":0,"type":"list","version":1,"listType":"bullet","start":1,"tag":"ul"},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Lastly, we're constantly adding cool new features to this playground. So make sure you check back here when you next get a chance :).","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""},{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"const lexical = \\"awesome\\"","type":"code-highlight","version":1}],"direction":"ltr","format":"","indent":0,"type":"code","version":1,"language":"javascript"},{"children":[{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":3,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":1,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":1,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":1,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":1,"rowSpan":1}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":2,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":2,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":2,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1},{"children":[{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":2,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1},{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":null,"format":"","indent":0,"type":"tablecell","version":1,"backgroundColor":null,"colSpan":1,"headerState":0,"rowSpan":1}],"direction":null,"format":"","indent":0,"type":"tablerow","version":1}],"direction":null,"format":"","indent":0,"type":"table","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}`, + expect(JSON.parse(otherStringifiedEditorState)).toEqual( + JSON.parse(expectedStringifiedEditorState), ); }); }); diff --git a/packages/lexical/src/__tests__/unit/LexicalUtils.test.ts b/packages/lexical/src/__tests__/unit/LexicalUtils.test.ts index 6b7e913c1ba..7e99ff29e27 100644 --- a/packages/lexical/src/__tests__/unit/LexicalUtils.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalUtils.test.ts @@ -372,24 +372,13 @@ describe('$applyNodeReplacement', () => { static clone(node: ExtendedTextNode): ExtendedTextNode { return new ExtendedTextNode(node.__text, node.getKey()); } - exportJSON(): SerializedTextNode { - return {...super.exportJSON(), type: this.getType()}; - } initWithTextNode(node: TextNode): this { - this.__text = node.__text; - TextNode.prototype.afterCloneFrom.call(this, node); - return this; - } - initWithJSON(serializedNode: SerializedTextNode): this { - this.setTextContent(serializedNode.text); - this.setFormat(serializedNode.format); - this.setDetail(serializedNode.detail); - this.setMode(serializedNode.mode); - this.setStyle(serializedNode.style); - return this; + const self = this.getWritable(); + TextNode.prototype.updateFromJSON.call(self, node.exportJSON()); + return self; } static importJSON(serializedNode: SerializedTextNode): ExtendedTextNode { - return $createExtendedTextNode().initWithJSON(serializedNode); + return $createExtendedTextNode().updateFromJSON(serializedNode); } } class ExtendedExtendedTextNode extends ExtendedTextNode { @@ -405,10 +394,7 @@ describe('$applyNodeReplacement', () => { static importJSON( serializedNode: SerializedTextNode, ): ExtendedExtendedTextNode { - return $createExtendedExtendedTextNode().initWithJSON(serializedNode); - } - exportJSON(): SerializedTextNode { - return {...super.exportJSON(), type: this.getType()}; + return $createExtendedExtendedTextNode().updateFromJSON(serializedNode); } } function $createExtendedTextNode(text: string = '') { diff --git a/packages/lexical/src/__tests__/utils/index.tsx b/packages/lexical/src/__tests__/utils/index.tsx index 4bb096f874d..8206d550579 100644 --- a/packages/lexical/src/__tests__/utils/index.tsx +++ b/packages/lexical/src/__tests__/utils/index.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {CodeHighlightNode, CodeNode} from '@lexical/code'; import {HashtagNode} from '@lexical/hashtag'; import {createHeadlessEditor} from '@lexical/headless'; @@ -175,19 +177,7 @@ export class TestElementNode extends ElementNode { static importJSON( serializedNode: SerializedTestElementNode, ): TestInlineElementNode { - const node = $createTestInlineElementNode(); - node.setFormat(serializedNode.format); - node.setIndent(serializedNode.indent); - node.setDirection(serializedNode.direction); - return node; - } - - exportJSON(): SerializedTestElementNode { - return { - ...super.exportJSON(), - type: 'test_block', - version: 1, - }; + return $createTestInlineElementNode().updateFromJSON(serializedNode); } createDOM() { @@ -215,15 +205,7 @@ export class TestTextNode extends TextNode { } static importJSON(serializedNode: SerializedTestTextNode): TestTextNode { - return new TestTextNode(serializedNode.text); - } - - exportJSON(): SerializedTestTextNode { - return { - ...super.exportJSON(), - type: 'test_text', - version: 1, - }; + return new TestTextNode().updateFromJSON(serializedNode); } } @@ -241,19 +223,7 @@ export class TestInlineElementNode extends ElementNode { static importJSON( serializedNode: SerializedTestInlineElementNode, ): TestInlineElementNode { - const node = $createTestInlineElementNode(); - node.setFormat(serializedNode.format); - node.setIndent(serializedNode.indent); - node.setDirection(serializedNode.direction); - return node; - } - - exportJSON(): SerializedTestInlineElementNode { - return { - ...super.exportJSON(), - type: 'test_inline_block', - version: 1, - }; + return $createTestInlineElementNode().updateFromJSON(serializedNode); } createDOM() { @@ -287,19 +257,7 @@ export class TestShadowRootNode extends ElementNode { static importJSON( serializedNode: SerializedTestShadowRootNode, ): TestShadowRootNode { - const node = $createTestShadowRootNode(); - node.setFormat(serializedNode.format); - node.setIndent(serializedNode.indent); - node.setDirection(serializedNode.direction); - return node; - } - - exportJSON(): SerializedTestShadowRootNode { - return { - ...super.exportJSON(), - type: 'test_block', - version: 1, - }; + return $createTestShadowRootNode().updateFromJSON(serializedNode); } createDOM() { @@ -333,24 +291,11 @@ export class TestSegmentedNode extends TextNode { static importJSON( serializedNode: SerializedTestSegmentedNode, ): TestSegmentedNode { - const node = $createTestSegmentedNode(serializedNode.text); - node.setFormat(serializedNode.format); - node.setDetail(serializedNode.detail); - node.setMode(serializedNode.mode); - node.setStyle(serializedNode.style); - return node; - } - - exportJSON(): SerializedTestSegmentedNode { - return { - ...super.exportJSON(), - type: 'test_segmented', - version: 1, - }; + return $createTestSegmentedNode().updateFromJSON(serializedNode); } } -export function $createTestSegmentedNode(text: string): TestSegmentedNode { +export function $createTestSegmentedNode(text: string = ''): TestSegmentedNode { return new TestSegmentedNode(text).setMode('segmented'); } @@ -368,19 +313,9 @@ export class TestExcludeFromCopyElementNode extends ElementNode { static importJSON( serializedNode: SerializedTestExcludeFromCopyElementNode, ): TestExcludeFromCopyElementNode { - const node = $createTestExcludeFromCopyElementNode(); - node.setFormat(serializedNode.format); - node.setIndent(serializedNode.indent); - node.setDirection(serializedNode.direction); - return node; - } - - exportJSON(): SerializedTestExcludeFromCopyElementNode { - return { - ...super.exportJSON(), - type: 'test_exclude_from_copy_block', - version: 1, - }; + return $createTestExcludeFromCopyElementNode().updateFromJSON( + serializedNode, + ); } createDOM() { @@ -414,15 +349,7 @@ export class TestDecoratorNode extends DecoratorNode { static importJSON( serializedNode: SerializedTestDecoratorNode, ): TestDecoratorNode { - return $createTestDecoratorNode(); - } - - exportJSON(): SerializedTestDecoratorNode { - return { - ...super.exportJSON(), - type: 'test_decorator', - version: 1, - }; + return $createTestDecoratorNode().updateFromJSON(serializedNode); } static importDOM() { diff --git a/packages/lexical/src/index.ts b/packages/lexical/src/index.ts index 0c7e1d7318b..7d89f3e2daf 100644 --- a/packages/lexical/src/index.ts +++ b/packages/lexical/src/index.ts @@ -45,6 +45,7 @@ export type { DOMExportOutput, DOMExportOutputMap, LexicalNode, + LexicalUpdateJSON, NodeKey, NodeMap, SerializedLexicalNode, @@ -180,12 +181,16 @@ export { $setCompositionKey, $setSelection, $splitNode, + getDOMOwnerDocument, getDOMSelection, + getDOMSelectionFromTarget, getDOMTextNode, getEditorPropertyFromDOMNode, getNearestEditorFromDOMNode, + INTERNAL_$isBlock, isBlockDomNode, isDocumentFragment, + isDOMDocumentNode, isDOMNode, isDOMTextNode, isDOMUnmanaged, diff --git a/packages/lexical/src/nodes/LexicalDecoratorNode.ts b/packages/lexical/src/nodes/LexicalDecoratorNode.ts index 5c5c7cb11c4..3090eb02c77 100644 --- a/packages/lexical/src/nodes/LexicalDecoratorNode.ts +++ b/packages/lexical/src/nodes/LexicalDecoratorNode.ts @@ -7,7 +7,6 @@ */ import type {KlassConstructor, LexicalEditor} from '../LexicalEditor'; -import type {NodeKey} from '../LexicalNode'; import type {ElementNode} from './LexicalElementNode'; import {EditorConfig} from 'lexical'; @@ -25,9 +24,6 @@ export interface DecoratorNode { // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging export class DecoratorNode extends LexicalNode { ['constructor']!: KlassConstructor>; - constructor(key?: NodeKey) { - super(key); - } /** * The returned value is added to the LexicalEditor._decorators diff --git a/packages/lexical/src/nodes/LexicalElementNode.ts b/packages/lexical/src/nodes/LexicalElementNode.ts index 19e54b0cfa6..8baa703ecbd 100644 --- a/packages/lexical/src/nodes/LexicalElementNode.ts +++ b/packages/lexical/src/nodes/LexicalElementNode.ts @@ -17,7 +17,13 @@ import type { PointType, RangeSelection, } from '../LexicalSelection'; -import type {KlassConstructor, LexicalEditor, Spread} from 'lexical'; +import type { + KlassConstructor, + LexicalEditor, + LexicalUpdateJSON, + Spread, + TextFormatType, +} from 'lexical'; import {IS_IOS, IS_SAFARI} from 'shared/environment'; import invariant from 'shared/invariant'; @@ -27,6 +33,7 @@ import { DOUBLE_LINE_BREAK, ELEMENT_FORMAT_TO_TYPE, ELEMENT_TYPE_TO_FORMAT, + TEXT_TYPE_TO_FORMAT, } from '../LexicalConstants'; import {LexicalNode} from '../LexicalNode'; import { @@ -41,6 +48,7 @@ import { $isRootOrShadowRoot, isHTMLElement, removeFromParent, + toggleTextFormatType, } from '../LexicalUtils'; export type SerializedElementNode< @@ -51,6 +59,8 @@ export type SerializedElementNode< direction: 'ltr' | 'rtl' | null; format: ElementFormatType; indent: number; + textFormat?: number; + textStyle?: string; }, SerializedLexicalNode >; @@ -307,6 +317,10 @@ export class ElementNode extends LexicalNode { __indent: number; /** @internal */ __dir: 'ltr' | 'rtl' | null; + /** @internal */ + __textFormat: number; + /** @internal */ + __textStyle: string; constructor(key?: NodeKey) { super(key); @@ -317,6 +331,8 @@ export class ElementNode extends LexicalNode { this.__style = ''; this.__indent = 0; this.__dir = null; + this.__textFormat = 0; + this.__textStyle = ''; } afterCloneFrom(prevNode: this) { @@ -328,6 +344,8 @@ export class ElementNode extends LexicalNode { this.__format = prevNode.__format; this.__style = prevNode.__style; this.__dir = prevNode.__dir; + this.__textFormat = prevNode.__textFormat; + this.__textStyle = prevNode.__textStyle; } getFormat(): number { @@ -527,6 +545,10 @@ export class ElementNode extends LexicalNode { const self = this.getLatest(); return self.__dir; } + getTextFormat(): number { + const self = this.getLatest(); + return self.__textFormat; + } hasFormat(type: ElementFormatType): boolean { if (type !== '') { const formatFlag = ELEMENT_TYPE_TO_FORMAT[type]; @@ -534,6 +556,25 @@ export class ElementNode extends LexicalNode { } return false; } + hasTextFormat(type: TextFormatType): boolean { + const formatFlag = TEXT_TYPE_TO_FORMAT[type]; + return (this.getTextFormat() & formatFlag) !== 0; + } + /** + * Returns the format flags applied to the node as a 32-bit integer. + * + * @returns a number representing the TextFormatTypes applied to the node. + */ + getFormatFlags(type: TextFormatType, alignWithFormat: null | number): number { + const self = this.getLatest(); + const format = self.__textFormat; + return toggleTextFormatType(format, type, alignWithFormat); + } + + getTextStyle(): string { + const self = this.getLatest(); + return self.__textStyle; + } // Mutators @@ -614,6 +655,16 @@ export class ElementNode extends LexicalNode { self.__style = style || ''; return this; } + setTextFormat(type: number): this { + const self = this.getWritable(); + self.__textFormat = type; + return self; + } + setTextStyle(style: string): this { + const self = this.getWritable(); + self.__textStyle = style; + return self; + } setIndent(indentLevel: number): this { const self = this.getWritable(); self.__indent = indentLevel; @@ -787,14 +838,36 @@ export class ElementNode extends LexicalNode { } // JSON serialization exportJSON(): SerializedElementNode { - return { + const json: SerializedElementNode = { children: [], direction: this.getDirection(), format: this.getFormatType(), indent: this.getIndent(), - type: 'element', - version: 1, + // As an exception here we invoke super at the end for historical reasons. + // Namely, to preserve the order of the properties and not to break the tests + // that use the serialized string representation. + ...super.exportJSON(), }; + const textFormat = this.getTextFormat(); + const textStyle = this.getTextStyle(); + if (textFormat !== 0) { + json.textFormat = textFormat; + } + if (textStyle !== '') { + json.textStyle = textStyle; + } + return json; + } + updateFromJSON( + serializedNode: LexicalUpdateJSON, + ): this { + return super + .updateFromJSON(serializedNode) + .setFormat(serializedNode.format) + .setIndent(serializedNode.indent) + .setDirection(serializedNode.direction) + .setTextFormat(serializedNode.textFormat || 0) + .setTextStyle(serializedNode.textStyle || ''); } // These are intended to be extends for specific element heuristics. insertNewAfter( diff --git a/packages/lexical/src/nodes/LexicalLineBreakNode.ts b/packages/lexical/src/nodes/LexicalLineBreakNode.ts index 2d28db08c12..a0bbece45d0 100644 --- a/packages/lexical/src/nodes/LexicalLineBreakNode.ts +++ b/packages/lexical/src/nodes/LexicalLineBreakNode.ts @@ -14,9 +14,12 @@ import type { SerializedLexicalNode, } from '../LexicalNode'; -import {DOM_TEXT_TYPE} from '../LexicalConstants'; import {LexicalNode} from '../LexicalNode'; -import {$applyNodeReplacement, isBlockDomNode} from '../LexicalUtils'; +import { + $applyNodeReplacement, + isBlockDomNode, + isDOMTextNode, +} from '../LexicalUtils'; export type SerializedLineBreakNode = SerializedLexicalNode; @@ -64,14 +67,7 @@ export class LineBreakNode extends LexicalNode { static importJSON( serializedLineBreakNode: SerializedLineBreakNode, ): LineBreakNode { - return $createLineBreakNode(); - } - - exportJSON(): SerializedLexicalNode { - return { - type: 'linebreak', - version: 1, - }; + return $createLineBreakNode().updateFromJSON(serializedLineBreakNode); } } @@ -135,8 +131,5 @@ function isLastChildInBlockNode(node: Node): boolean { } function isWhitespaceDomTextNode(node: Node): boolean { - return ( - node.nodeType === DOM_TEXT_TYPE && - /^( |\t|\r?\n)+$/.test(node.textContent || '') - ); + return isDOMTextNode(node) && /^( |\t|\r?\n)+$/.test(node.textContent || ''); } diff --git a/packages/lexical/src/nodes/LexicalParagraphNode.ts b/packages/lexical/src/nodes/LexicalParagraphNode.ts index 1fec9c8b257..022b9934514 100644 --- a/packages/lexical/src/nodes/LexicalParagraphNode.ts +++ b/packages/lexical/src/nodes/LexicalParagraphNode.ts @@ -17,24 +17,21 @@ import type { DOMConversionOutput, DOMExportOutput, LexicalNode, - NodeKey, } from '../LexicalNode'; +import type {RangeSelection} from '../LexicalSelection'; import type { ElementFormatType, SerializedElementNode, } from './LexicalElementNode'; -import type {RangeSelection} from 'lexical'; -import {TEXT_TYPE_TO_FORMAT} from '../LexicalConstants'; import { $applyNodeReplacement, getCachedClassNameArray, isHTMLElement, setNodeIndentFromDOM, - toggleTextFormatType, } from '../LexicalUtils'; import {ElementNode} from './LexicalElementNode'; -import {$isTextNode, TextFormatType} from './LexicalTextNode'; +import {$isTextNode} from './LexicalTextNode'; export type SerializedParagraphNode = Spread< { @@ -47,68 +44,15 @@ export type SerializedParagraphNode = Spread< /** @noInheritDoc */ export class ParagraphNode extends ElementNode { ['constructor']!: KlassConstructor; - /** @internal */ - __textFormat: number; - __textStyle: string; - - constructor(key?: NodeKey) { - super(key); - this.__textFormat = 0; - this.__textStyle = ''; - } static getType(): string { return 'paragraph'; } - getTextFormat(): number { - const self = this.getLatest(); - return self.__textFormat; - } - - setTextFormat(type: number): this { - const self = this.getWritable(); - self.__textFormat = type; - return self; - } - - hasTextFormat(type: TextFormatType): boolean { - const formatFlag = TEXT_TYPE_TO_FORMAT[type]; - return (this.getTextFormat() & formatFlag) !== 0; - } - - /** - * Returns the format flags applied to the node as a 32-bit integer. - * - * @returns a number representing the TextFormatTypes applied to the node. - */ - getFormatFlags(type: TextFormatType, alignWithFormat: null | number): number { - const self = this.getLatest(); - const format = self.__textFormat; - return toggleTextFormatType(format, type, alignWithFormat); - } - - getTextStyle(): string { - const self = this.getLatest(); - return self.__textStyle; - } - - setTextStyle(style: string): this { - const self = this.getWritable(); - self.__textStyle = style; - return self; - } - static clone(node: ParagraphNode): ParagraphNode { return new ParagraphNode(node.__key); } - afterCloneFrom(prevNode: this) { - super.afterCloneFrom(prevNode); - this.__textFormat = prevNode.__textFormat; - this.__textStyle = prevNode.__textStyle; - } - // View createDOM(config: EditorConfig): HTMLElement { @@ -160,21 +104,15 @@ export class ParagraphNode extends ElementNode { } static importJSON(serializedNode: SerializedParagraphNode): ParagraphNode { - const node = $createParagraphNode(); - node.setFormat(serializedNode.format); - node.setIndent(serializedNode.indent); - node.setDirection(serializedNode.direction); - node.setTextFormat(serializedNode.textFormat); - return node; + return $createParagraphNode().updateFromJSON(serializedNode); } exportJSON(): SerializedParagraphNode { return { ...super.exportJSON(), + // These are included explicitly for backwards compatibility textFormat: this.getTextFormat(), textStyle: this.getTextStyle(), - type: 'paragraph', - version: 1, }; } diff --git a/packages/lexical/src/nodes/LexicalRootNode.ts b/packages/lexical/src/nodes/LexicalRootNode.ts index 7e4782061f1..10ceb1263e4 100644 --- a/packages/lexical/src/nodes/LexicalRootNode.ts +++ b/packages/lexical/src/nodes/LexicalRootNode.ts @@ -98,22 +98,7 @@ export class RootNode extends ElementNode { static importJSON(serializedNode: SerializedRootNode): RootNode { // We don't create a root, and instead use the existing root. - const node = $getRoot(); - node.setFormat(serializedNode.format); - node.setIndent(serializedNode.indent); - node.setDirection(serializedNode.direction); - return node; - } - - exportJSON(): SerializedRootNode { - return { - children: [], - direction: this.getDirection(), - format: this.getFormatType(), - indent: this.getIndent(), - type: 'root', - version: 1, - }; + return $getRoot().updateFromJSON(serializedNode); } collapseAtStart(): true { diff --git a/packages/lexical/src/nodes/LexicalTabNode.ts b/packages/lexical/src/nodes/LexicalTabNode.ts index 8c5999b33c2..11fe4d5243b 100644 --- a/packages/lexical/src/nodes/LexicalTabNode.ts +++ b/packages/lexical/src/nodes/LexicalTabNode.ts @@ -33,12 +33,6 @@ export class TabNode extends TextNode { return new TabNode(node.__key); } - afterCloneFrom(prevNode: this): void { - super.afterCloneFrom(prevNode); - // TabNode __text can be either '\t' or ''. insertText will remove the empty Node - this.__text = prevNode.__text; - } - constructor(key?: NodeKey) { super('\t', key); this.__detail = IS_UNMERGEABLE; @@ -60,30 +54,25 @@ export class TabNode extends TextNode { } static importJSON(serializedTabNode: SerializedTabNode): TabNode { - const node = $createTabNode(); - node.setFormat(serializedTabNode.format); - node.setStyle(serializedTabNode.style); - return node; - } - - exportJSON(): SerializedTabNode { - return { - ...super.exportJSON(), - type: 'tab', - version: 1, - }; + return $createTabNode().updateFromJSON(serializedTabNode); } - setTextContent(_text: string): this { - invariant(false, 'TabNode does not support setTextContent'); + setTextContent(text: string): this { + invariant( + text === '\t' || text === '', + 'TabNode does not support setTextContent', + ); + return super.setTextContent(text); } - setDetail(_detail: TextDetailType | number): this { - invariant(false, 'TabNode does not support setDetail'); + setDetail(detail: TextDetailType | number): this { + invariant(detail === IS_UNMERGEABLE, 'TabNode does not support setDetail'); + return this; } - setMode(_type: TextModeType): this { - invariant(false, 'TabNode does not support setMode'); + setMode(type: TextModeType): this { + invariant(type === 'normal', 'TabNode does not support setMode'); + return this; } canInsertTextBefore(): boolean { diff --git a/packages/lexical/src/nodes/LexicalTextNode.ts b/packages/lexical/src/nodes/LexicalTextNode.ts index ed57345627f..15d6e4afb6e 100644 --- a/packages/lexical/src/nodes/LexicalTextNode.ts +++ b/packages/lexical/src/nodes/LexicalTextNode.ts @@ -17,6 +17,7 @@ import type { DOMConversionMap, DOMConversionOutput, DOMExportOutput, + LexicalUpdateJSON, NodeKey, SerializedLexicalNode, } from '../LexicalNode'; @@ -29,8 +30,6 @@ import invariant from 'shared/invariant'; import { COMPOSITION_SUFFIX, DETAIL_TYPE_TO_DETAIL, - DOM_ELEMENT_TYPE, - DOM_TEXT_TYPE, IS_BOLD, IS_CODE, IS_DIRECTIONLESS, @@ -62,6 +61,7 @@ import { $setCompositionKey, getCachedClassNameArray, internalMarkSiblingsAsDirty, + isDOMTextNode, isHTMLElement, isInlineDomNode, toggleTextFormatType, @@ -308,13 +308,14 @@ export class TextNode extends LexicalNode { afterCloneFrom(prevNode: this): void { super.afterCloneFrom(prevNode); + this.__text = prevNode.__text; this.__format = prevNode.__format; this.__style = prevNode.__style; this.__mode = prevNode.__mode; this.__detail = prevNode.__detail; } - constructor(text: string, key?: NodeKey) { + constructor(text: string = '', key?: NodeKey) { super(key); this.__text = text; this.__format = 0; @@ -606,12 +607,17 @@ export class TextNode extends LexicalNode { } static importJSON(serializedNode: SerializedTextNode): TextNode { - const node = $createTextNode(serializedNode.text); - node.setFormat(serializedNode.format); - node.setDetail(serializedNode.detail); - node.setMode(serializedNode.mode); - node.setStyle(serializedNode.style); - return node; + return $createTextNode().updateFromJSON(serializedNode); + } + + updateFromJSON(serializedNode: LexicalUpdateJSON): this { + return super + .updateFromJSON(serializedNode) + .setTextContent(serializedNode.text) + .setFormat(serializedNode.format) + .setDetail(serializedNode.detail) + .setMode(serializedNode.mode) + .setStyle(serializedNode.style); } // This improves Lexical's basic text output in copy+paste plus @@ -652,8 +658,10 @@ export class TextNode extends LexicalNode { mode: this.getMode(), style: this.getStyle(), text: this.getTextContent(), - type: 'text', - version: 1, + // As an exception here we invoke super at the end for historical reasons. + // Namely, to preserve the order of the properties and not to break the tests + // that use the serialized string representation. + ...super.exportJSON(), }; } @@ -1072,7 +1080,6 @@ export class TextNode extends LexicalNode { target, textLength, ); - selection.dirty = true; } if (focus !== null && focus.key === targetKey) { adjustPointOffsetForMergedSibling( @@ -1082,7 +1089,6 @@ export class TextNode extends LexicalNode { target, textLength, ); - selection.dirty = true; } } const targetText = target.__text; @@ -1136,13 +1142,13 @@ function convertBringAttentionToElement( const preParentCache = new WeakMap(); function isNodePre(node: Node): boolean { - return ( - node.nodeName === 'PRE' || - (node.nodeType === DOM_ELEMENT_TYPE && - (node as HTMLElement).style !== undefined && - (node as HTMLElement).style.whiteSpace !== undefined && - (node as HTMLElement).style.whiteSpace.startsWith('pre')) - ); + if (!isHTMLElement(node)) { + return false; + } else if (node.nodeName === 'PRE') { + return true; + } + const whiteSpace = node.style.whiteSpace; + return typeof whiteSpace === 'string' && whiteSpace.startsWith('pre'); } export function findParentPreDOMNode(node: Node) { @@ -1258,8 +1264,8 @@ function findTextInLine(text: Text, forward: boolean): null | Text { node = parentElement; } node = sibling; - if (node.nodeType === DOM_ELEMENT_TYPE) { - const display = (node as HTMLElement).style.display; + if (isHTMLElement(node)) { + const display = node.style.display; if ( (display === '' && !isInlineDomNode(node)) || (display !== '' && !display.startsWith('inline')) @@ -1271,8 +1277,8 @@ function findTextInLine(text: Text, forward: boolean): null | Text { while ((descendant = forward ? node.firstChild : node.lastChild) !== null) { node = descendant; } - if (node.nodeType === DOM_TEXT_TYPE) { - return node as Text; + if (isDOMTextNode(node)) { + return node; } else if (node.nodeName === 'BR') { return null; } diff --git a/packages/lexical/src/nodes/__tests__/unit/LexicalTabNode.test.tsx b/packages/lexical/src/nodes/__tests__/unit/LexicalTabNode.test.tsx index 0c06273eca1..1b70bf5ce9f 100644 --- a/packages/lexical/src/nodes/__tests__/unit/LexicalTabNode.test.tsx +++ b/packages/lexical/src/nodes/__tests__/unit/LexicalTabNode.test.tsx @@ -23,6 +23,7 @@ import { $insertNodes, $isElementNode, $isRangeSelection, + $isTabNode, $isTextNode, $setSelection, KEY_TAB_COMMAND, @@ -253,5 +254,30 @@ describe('LexicalTabNode tests', () => { '

\tf\t

', ); }); + + test('can be serialized and deserialized', async () => { + const {editor} = testEnv; + await editor.update(() => { + $getRoot() + .clear() + .append($createParagraphNode().append($createTabNode())); + const textNodes = $getRoot().getAllTextNodes(); + expect(textNodes).toHaveLength(1); + expect($isTabNode(textNodes[0])).toBe(true); + }); + const json = editor.getEditorState().toJSON(); + await editor.update(() => { + $getRoot().clear().append($createParagraphNode()); + }); + editor.read(() => { + expect($getRoot().getAllTextNodes()).toHaveLength(0); + }); + await editor.setEditorState(editor.parseEditorState(json)); + editor.read(() => { + const textNodes = $getRoot().getAllTextNodes(); + expect(textNodes).toHaveLength(1); + expect($isTabNode(textNodes[0])).toBe(true); + }); + }); }); }); diff --git a/packages/shared/package.json b/packages/shared/package.json index 573101e318f..6580c6befb1 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -8,9 +8,9 @@ "rich-text" ], "license": "MIT", - "version": "0.21.0", + "version": "0.23.1", "dependencies": { - "lexical": "0.21.0" + "lexical": "0.23.1" }, "repository": { "type": "git", diff --git a/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/package-lock.json b/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/package-lock.json index 6432ca3af37..bdf7b5963e2 100644 --- a/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/package-lock.json +++ b/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/package-lock.json @@ -1,21 +1,21 @@ { "name": "lexical-esm-astro-react", - "version": "0.20.0", + "version": "0.22.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lexical-esm-astro-react", - "version": "0.20.0", + "version": "0.22.0", "dependencies": { "@astrojs/check": "^0.9.3", "@astrojs/react": "^3.1.0", - "@lexical/react": "0.20.0", - "@lexical/utils": "0.20.0", + "@lexical/react": "0.22.0", + "@lexical/utils": "0.22.0", "@types/react": "^18.2.66", "@types/react-dom": "^18.2.22", "astro": "^4.5.4", - "lexical": "0.20.0", + "lexical": "0.22.0", "react": "^18.2.0", "react-dom": "^18.2.0", "typescript": "^5.4.2" @@ -60,9 +60,10 @@ "integrity": "sha512-bL/O7YBxsFt55YHU021oL+xz+B/9HvGNId3F9xURN16aeqDK9juHGktdkCSXz+U4nqFACq6ZFvWomOzhV+zfPw==" }, "node_modules/@astrojs/internal-helpers": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.4.0.tgz", - "integrity": "sha512-6B13lz5n6BrbTqCTwhXjJXuR1sqiX/H6rTxzlXx+lN1NnV4jgnq/KJldCQaUWJzPL5SiWahQyinxAbxQtwgPHA==" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.4.1.tgz", + "integrity": "sha512-bMf9jFihO8YP940uD70SI/RDzIhUHJAolWVcO1v5PUivxGKvfLZTLTVVxEYzGYyPsA3ivdLNqMnL5VgmQySa+g==", + "license": "MIT" }, "node_modules/@astrojs/language-server": { "version": "2.14.2", @@ -106,39 +107,41 @@ } }, "node_modules/@astrojs/markdown-remark": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-5.0.0.tgz", - "integrity": "sha512-QBXbxXZamVRoqCNN2gjDXa7qYPUkJZq7KYFfg3DX7rze3QL6xiz4N+Wg202dNPRaIkQa16BV6D8+EHibQFubRg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-5.3.0.tgz", + "integrity": "sha512-r0Ikqr0e6ozPb5bvhup1qdWnSPUvQu6tub4ZLYaKyG50BXZ0ej6FhGz3GpChKpH7kglRFPObJd/bDyf2VM9pkg==", + "license": "MIT", "dependencies": { - "@astrojs/prism": "^3.0.0", + "@astrojs/prism": "3.1.0", "github-slugger": "^2.0.0", - "hast-util-from-html": "^2.0.0", - "hast-util-to-text": "^4.0.0", - "import-meta-resolve": "^4.0.0", + "hast-util-from-html": "^2.0.3", + "hast-util-to-text": "^4.0.2", + "import-meta-resolve": "^4.1.0", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", - "rehype-stringify": "^10.0.0", + "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.0", "remark-parse": "^11.0.0", - "remark-rehype": "^11.0.0", - "remark-smartypants": "^2.0.0", - "shiki": "^1.1.2", - "unified": "^11.0.4", + "remark-rehype": "^11.1.1", + "remark-smartypants": "^3.0.2", + "shiki": "^1.22.0", + "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", - "unist-util-visit-parents": "^6.0.0", - "vfile": "^6.0.1" + "unist-util-visit-parents": "^6.0.1", + "vfile": "^6.0.3" } }, "node_modules/@astrojs/prism": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.0.0.tgz", - "integrity": "sha512-g61lZupWq1bYbcBnYZqdjndShr/J3l/oFobBKPA3+qMat146zce3nz2kdO4giGbhYDt4gYdhmoBz0vZJ4sIurQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.1.0.tgz", + "integrity": "sha512-Z9IYjuXSArkAUx3N6xj6+Bnvx8OdUSHA8YoOgyepp3+zJmtVYJIl/I18GozdJVW1p5u/CNpl3Km7/gwTJK85cw==", + "license": "MIT", "dependencies": { "prismjs": "^1.29.0" }, "engines": { - "node": ">=18.14.1" + "node": "^18.17.1 || ^20.3.0 || >=21.0.0" } }, "node_modules/@astrojs/react": { @@ -160,34 +163,21 @@ } }, "node_modules/@astrojs/telemetry": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.0.4.tgz", - "integrity": "sha512-A+0c7k/Xy293xx6odsYZuXiaHO0PL+bnDoXOc47sGDF5ffIKdKQGRPFl2NMlCF4L0NqN4Ynbgnaip+pPF0s7pQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.1.0.tgz", + "integrity": "sha512-/ca/+D8MIKEC8/A9cSaPUqQNZm+Es/ZinRv0ZAzvu2ios7POQSsVD+VOj7/hypWNsNM3T7RpfgNq7H2TU1KEHA==", + "license": "MIT", "dependencies": { - "ci-info": "^3.8.0", + "ci-info": "^4.0.0", "debug": "^4.3.4", "dlv": "^1.1.3", - "dset": "^3.1.2", + "dset": "^3.1.3", "is-docker": "^3.0.0", "is-wsl": "^3.0.0", "which-pm-runs": "^1.1.0" }, "engines": { - "node": ">=18.14.1" - } - }, - "node_modules/@astrojs/telemetry/node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" + "node": "^18.17.1 || ^20.3.0 || >=21.0.0" } }, "node_modules/@astrojs/yaml2ts": { @@ -199,11 +189,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.2", + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", "picocolors": "^1.0.0" }, "engines": { @@ -211,28 +203,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", - "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz", + "integrity": "sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", - "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.4", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.4", - "@babel/parser": "^7.24.4", - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -247,39 +241,52 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/generator": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", - "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", + "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.0", + "@babel/parser": "^7.26.3", + "@babel/types": "^7.26.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -287,58 +294,37 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", - "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.0" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -348,90 +334,62 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", - "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dependencies": { - "@babel/types": "^7.22.5" - }, + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", - "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", - "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "license": "MIT", "dependencies": { - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0" + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", - "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "node_modules/@babel/parser": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", + "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "@babel/types": "^7.26.3" }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", - "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -440,11 +398,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", - "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -454,15 +413,16 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", - "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", + "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-jsx": "^7.23.3", - "@babel/types": "^7.23.4" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -511,31 +471,30 @@ } }, "node_modules/@babel/template": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", - "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0" + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", - "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", - "dependencies": { - "@babel/code-frame": "^7.24.1", - "@babel/generator": "^7.24.1", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.1", - "@babel/types": "^7.24.0", + "version": "7.26.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", + "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.3", + "@babel/parser": "^7.26.3", + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.3", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -544,13 +503,13 @@ } }, "node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", + "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -604,13 +563,24 @@ "resolved": "https://registry.npmjs.org/@emmetio/stream-reader-utils/-/stream-reader-utils-0.1.0.tgz", "integrity": "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==" }, + "node_modules/@emnapi/runtime": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", + "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", - "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], + "license": "MIT", "optional": true, "os": [ "aix" @@ -620,12 +590,13 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", - "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -635,12 +606,13 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", - "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -650,12 +622,13 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", - "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -665,12 +638,13 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", - "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -680,12 +654,13 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", - "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -695,12 +670,13 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", - "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -710,12 +686,13 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", - "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -725,12 +702,13 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", - "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -740,12 +718,13 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", - "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -755,12 +734,13 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", - "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -770,12 +750,13 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", - "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -785,12 +766,13 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", - "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -800,12 +782,13 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", - "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -815,12 +798,13 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", - "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -830,12 +814,13 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", - "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -845,12 +830,13 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", - "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -860,12 +846,13 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", - "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -875,12 +862,13 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", - "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -890,12 +878,13 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", - "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "sunos" @@ -905,12 +894,13 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", - "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -920,12 +910,13 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", - "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -935,12 +926,13 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", - "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -949,231 +941,593 @@ "node": ">=12" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.0.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.0.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@lexical/clipboard": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.20.0.tgz", - "integrity": "sha512-oHmb9kSVHjeFCd2q8VrEXW22doUHMJ6cGXqo7Ican7Ljl4/9OgRWr+cq55yntoSaJfCrRYkTiZCLDejF2ciSiA==", - "license": "MIT", - "dependencies": { - "@lexical/html": "0.20.0", - "@lexical/list": "0.20.0", - "@lexical/selection": "0.20.0", - "@lexical/utils": "0.20.0", - "lexical": "0.20.0" + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@lexical/code": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/code/-/code-0.20.0.tgz", - "integrity": "sha512-zFsVGuzIn4CQxEnlW4AG/Hq6cyATVZ4fZTxozE/f5oK4vDPvnY/goRxrzSuAMX73A/HRX3kTEzMDcm4taRM3Mg==", - "license": "MIT", - "dependencies": { - "@lexical/utils": "0.20.0", - "lexical": "0.20.0", - "prismjs": "^1.27.0" + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@lexical/devtools-core": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/devtools-core/-/devtools-core-0.20.0.tgz", - "integrity": "sha512-/CnL+Dfpzw4koy2BTdUICkvrCkMIYG8Y73KB/S1Bt5UzJpD+PV300puWJ0NvUvAj24H78r73jxvK2QUG67Tdaw==", - "license": "MIT", - "dependencies": { - "@lexical/html": "0.20.0", - "@lexical/link": "0.20.0", - "@lexical/mark": "0.20.0", - "@lexical/table": "0.20.0", - "@lexical/utils": "0.20.0", - "lexical": "0.20.0" - }, - "peerDependencies": { - "react": ">=17.x", - "react-dom": ">=17.x" + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@lexical/dragon": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/dragon/-/dragon-0.20.0.tgz", - "integrity": "sha512-3DAHF8mSKiPZtXCqu2P8ynSwS3fGXzg4G/V0lXNjBxhmozjzUzWZRWIWtmTlWdEu9GXsoyeM3agcaxyDPJJwkA==", - "license": "MIT", - "dependencies": { - "lexical": "0.20.0" + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lexical/clipboard": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.22.0.tgz", + "integrity": "sha512-nG3MX7MYmaf4f4Ia0YaYaJIS1QriuUxNaLHYeAqOPqYZLH1CUnXslCiak6OyQ4dt/QozKKvGM5vpZN2QWvs0Xw==", + "license": "MIT", + "dependencies": { + "@lexical/html": "0.22.0", + "@lexical/list": "0.22.0", + "@lexical/selection": "0.22.0", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" + } + }, + "node_modules/@lexical/code": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/code/-/code-0.22.0.tgz", + "integrity": "sha512-5HQGcv+R7+uOxFGGqGxE5Mj2LcYwxniHejri7s3OJTSeFrGxAXwP2Kxb+5FSvWsyg265snuxZlNNfKVozgJPhA==", + "license": "MIT", + "dependencies": { + "@lexical/utils": "0.22.0", + "lexical": "0.22.0", + "prismjs": "^1.27.0" + } + }, + "node_modules/@lexical/devtools-core": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/devtools-core/-/devtools-core-0.22.0.tgz", + "integrity": "sha512-PFdaN2c+O/eLqNcWzuLBz0AaiLPHs9+iMHUZDQMgAWcKS6uiEBA61VS+ZNZn8zj8RZZvUtxgmZ9wQFFURklfww==", + "license": "MIT", + "dependencies": { + "@lexical/html": "0.22.0", + "@lexical/link": "0.22.0", + "@lexical/mark": "0.22.0", + "@lexical/table": "0.22.0", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" + }, + "peerDependencies": { + "react": ">=17.x", + "react-dom": ">=17.x" + } + }, + "node_modules/@lexical/dragon": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/dragon/-/dragon-0.22.0.tgz", + "integrity": "sha512-68b1EiFbYRqPEhbrFPhfTNe/hSTCFtwBmcIP5cGgEef+lL5XqCxc6NK2g2DK4Dx26DSGwXxTuRG8NuuxFN+CiA==", + "license": "MIT", + "dependencies": { + "lexical": "0.22.0" } }, "node_modules/@lexical/hashtag": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/hashtag/-/hashtag-0.20.0.tgz", - "integrity": "sha512-ldOP/d9tA6V9qvLyr3mRYkcYY5ySOHJ2BFOW/jZPxQcj6lWafS8Lk7XdMUpHHDjRpY2Hizsi5MHJkIqFglYXbw==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/hashtag/-/hashtag-0.22.0.tgz", + "integrity": "sha512-W6Wrz0+ClezZQavjCjYso+LzRP/rWNUIM6cLwnf7oFXsmIXeaLHXecIbRwZ+SChnj4eUlSlnlknMVi3bJKaOjw==", "license": "MIT", "dependencies": { - "@lexical/utils": "0.20.0", - "lexical": "0.20.0" + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/history": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/history/-/history-0.20.0.tgz", - "integrity": "sha512-dXtIS31BU6RmLX2KwLAi1EgGl+USeyi+rshh19azACXHPFqONZgPd2t21LOLSFn7C1/W+cSp/kqVDlQVbZUZRA==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/history/-/history-0.22.0.tgz", + "integrity": "sha512-4e/xL7CtYvsv8X4iGH1tPL8J6jthDpzh0a1WWZfL9ipeOYN9Btctq6o1Obdth5DfbMR7ELq7PSN2FK6+jZ4EQQ==", "license": "MIT", "dependencies": { - "@lexical/utils": "0.20.0", - "lexical": "0.20.0" + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/html": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.20.0.tgz", - "integrity": "sha512-ob7QHkEv+mhaZjlurDj90UmEyN9G4rzBPR5QV42PLnu1qMSviMEdI5V3a5/A5aFf/FDDQ+0GAgWBFnA/MEDczQ==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.22.0.tgz", + "integrity": "sha512-ED2Xik95a4kPg9vbU5pT/sA5hvEyGnuVxg0XvMx/6Gaa7OIhYDiZvSD4DCE+eVfn0xZMnIbX94Ygf4//71kCYw==", "license": "MIT", "dependencies": { - "@lexical/selection": "0.20.0", - "@lexical/utils": "0.20.0", - "lexical": "0.20.0" + "@lexical/selection": "0.22.0", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/link": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/link/-/link-0.20.0.tgz", - "integrity": "sha512-zicDcfgRZPRFZ8WOZv5er0Aqkde+i7QoFVkLQD4dNLLORjoMSJOISJH6VEdjBl3k7QJTxbfrt+xT5d/ZsAN5GA==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/link/-/link-0.22.0.tgz", + "integrity": "sha512-mtlsOYW6sgbgvv1ecPt6/9CdlgP0MhVyrF8iu16JpngphVXu/Lz2BSh7TCfY0xho/H2OIu++9lUGn87cK1Zplw==", "license": "MIT", "dependencies": { - "@lexical/utils": "0.20.0", - "lexical": "0.20.0" + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/list": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.20.0.tgz", - "integrity": "sha512-ufSse8ui3ooUe0HA/yF/9STrG8wYhIDLMRhELOw80GFCkPJaxs6yRvjfmJooH5IC88rpUJ5XXFFiZKfGxEZLEw==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.22.0.tgz", + "integrity": "sha512-DZLzMg1/H+nclV8BNqZe2qk/bz1ogCr7Huzwab5o8jTjpsDJaqyUZasj8wRgBzyLu9jxMQngkarL47nnk+zrbA==", "license": "MIT", "dependencies": { - "@lexical/utils": "0.20.0", - "lexical": "0.20.0" + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/mark": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/mark/-/mark-0.20.0.tgz", - "integrity": "sha512-1P2izmkgZ4VDp+49rWO1KfWivL5aA30y5kkYbFZ/CS05fgbO7ogMjLSajpz+RN/zzW79v3q4YfikrMgaD23InA==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/mark/-/mark-0.22.0.tgz", + "integrity": "sha512-d8Jb9xqhHwUrN2uBs0aIjvA/NgeAZCI5Zorynqq5ihBVSytrol09JyRt4t7SXRH4sCpDMDLMWfTjm820RQFq8g==", "license": "MIT", "dependencies": { - "@lexical/utils": "0.20.0", - "lexical": "0.20.0" + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/markdown": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/markdown/-/markdown-0.20.0.tgz", - "integrity": "sha512-ZoGsECejp9z6MEvc8l81b1h1aWbB3sTq6xOFeUTbDL5vKpA67z5CmQQLi0uZWrygrbO9dSE3Q/JGcodUrczxbw==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/markdown/-/markdown-0.22.0.tgz", + "integrity": "sha512-FJNfegbgry4dFwyzjdK6sasYHsVgiYy2WrVmVKYR/EDBxa0MARnVO7lRRXA37WcqMKi5N8dE/dABmjlmzuYzHA==", "license": "MIT", "dependencies": { - "@lexical/code": "0.20.0", - "@lexical/link": "0.20.0", - "@lexical/list": "0.20.0", - "@lexical/rich-text": "0.20.0", - "@lexical/text": "0.20.0", - "@lexical/utils": "0.20.0", - "lexical": "0.20.0" + "@lexical/code": "0.22.0", + "@lexical/link": "0.22.0", + "@lexical/list": "0.22.0", + "@lexical/rich-text": "0.22.0", + "@lexical/text": "0.22.0", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/offset": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/offset/-/offset-0.20.0.tgz", - "integrity": "sha512-VMhxsxxDGnpVw0jgC8UlDf0Q2RHIHbS49uZgs3l9nP+O+G8s3b76Ta4Tb+iJOK2FY6874/TcQMbSuXGhfpQk8A==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/offset/-/offset-0.22.0.tgz", + "integrity": "sha512-DgfO0q1+PzLzmMgRxTC7+y4whL6btlNSfv7f47TBAMBoj5tKdkGyMrru0xjoeYHVsMiSNgqMY2HTXU5YokKUOg==", "license": "MIT", "dependencies": { - "lexical": "0.20.0" + "lexical": "0.22.0" } }, "node_modules/@lexical/overflow": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/overflow/-/overflow-0.20.0.tgz", - "integrity": "sha512-z4lElzLm1FVifc7bzBZN4VNKeTuwygpyHQvCJVWXzF2Kbvex43PEYMi8u4A83idVqbmzbyBLASwUJS0voLoPLw==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/overflow/-/overflow-0.22.0.tgz", + "integrity": "sha512-LPj27ChVsOUW7Gv28z9m7NfpPQs7e3OooYL1WzU3R8NYDj/U32YxQXpUDcxHKwBPo8j8NVEna2d3UAG1txz6BA==", "license": "MIT", "dependencies": { - "lexical": "0.20.0" + "lexical": "0.22.0" } }, "node_modules/@lexical/plain-text": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.20.0.tgz", - "integrity": "sha512-LvoC+9mm2Im1iO8GgtgaqSfW0T3mIE5GQl1xGxbVNdANmtHmBgRAJn2KfQm1XHZP6zydLRMhZkzC+jfInh2yfQ==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.22.0.tgz", + "integrity": "sha512-MBlX4PfLN6I/As8uuRnL/17B+lIjmtNSIH90NjykRwBC8dtWr4gzSjm9OGTee6HctxnbQNb1BGLM7W1hLtiKAw==", "license": "MIT", "dependencies": { - "@lexical/clipboard": "0.20.0", - "@lexical/selection": "0.20.0", - "@lexical/utils": "0.20.0", - "lexical": "0.20.0" + "@lexical/clipboard": "0.22.0", + "@lexical/selection": "0.22.0", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/react": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/react/-/react-0.20.0.tgz", - "integrity": "sha512-5QbN5AFtZ9efXxU/M01ADhUZgthR0e8WKi5K/w5EPpWtYFDPQnUte3rKUjYJ7uwG1iwcvaCpuMbxJjHQ+i6pDQ==", - "license": "MIT", - "dependencies": { - "@lexical/clipboard": "0.20.0", - "@lexical/code": "0.20.0", - "@lexical/devtools-core": "0.20.0", - "@lexical/dragon": "0.20.0", - "@lexical/hashtag": "0.20.0", - "@lexical/history": "0.20.0", - "@lexical/link": "0.20.0", - "@lexical/list": "0.20.0", - "@lexical/mark": "0.20.0", - "@lexical/markdown": "0.20.0", - "@lexical/overflow": "0.20.0", - "@lexical/plain-text": "0.20.0", - "@lexical/rich-text": "0.20.0", - "@lexical/selection": "0.20.0", - "@lexical/table": "0.20.0", - "@lexical/text": "0.20.0", - "@lexical/utils": "0.20.0", - "@lexical/yjs": "0.20.0", - "lexical": "0.20.0", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/react/-/react-0.22.0.tgz", + "integrity": "sha512-kHeAX6QFsDcdih2kBQVnIATOQsDzpMp2VLYlSxatF8JvCTaMQ3quH/CGHLnUAauZDxM2LC/eV+Z4nrUOP3Alyg==", + "license": "MIT", + "dependencies": { + "@lexical/clipboard": "0.22.0", + "@lexical/code": "0.22.0", + "@lexical/devtools-core": "0.22.0", + "@lexical/dragon": "0.22.0", + "@lexical/hashtag": "0.22.0", + "@lexical/history": "0.22.0", + "@lexical/link": "0.22.0", + "@lexical/list": "0.22.0", + "@lexical/mark": "0.22.0", + "@lexical/markdown": "0.22.0", + "@lexical/overflow": "0.22.0", + "@lexical/plain-text": "0.22.0", + "@lexical/rich-text": "0.22.0", + "@lexical/selection": "0.22.0", + "@lexical/table": "0.22.0", + "@lexical/text": "0.22.0", + "@lexical/utils": "0.22.0", + "@lexical/yjs": "0.22.0", + "lexical": "0.22.0", "react-error-boundary": "^3.1.4" }, "peerDependencies": { @@ -1182,67 +1536,67 @@ } }, "node_modules/@lexical/rich-text": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.20.0.tgz", - "integrity": "sha512-BR1pACdMA+Ymef0f5EN1y+9yP8w7S+9MgmBP1yjr3w4KdqRnfSaGWyxwcHU8eA+zu16QfivpB6501VJ90YeuXw==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.22.0.tgz", + "integrity": "sha512-ILN/tht6emxbVK12Hp86y50fk0MGHMHg6Ivt/5OncoDPXfLMicuJRgLgLxLl5dCf7UVQOfa7z8eKEWnE83M5Mg==", "license": "MIT", "dependencies": { - "@lexical/clipboard": "0.20.0", - "@lexical/selection": "0.20.0", - "@lexical/utils": "0.20.0", - "lexical": "0.20.0" + "@lexical/clipboard": "0.22.0", + "@lexical/selection": "0.22.0", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/selection": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.20.0.tgz", - "integrity": "sha512-YnkH5UCMNN/em95or/6uwAV31vcENh1Roj+JOg5KD+gJuA7VGdDCy0vZl/o0+1badXozeZ2VRxXNC6JSK7T4+A==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.22.0.tgz", + "integrity": "sha512-DdRh8bHijQGV1OxeaywulaLRxgYtn1B7miS0I4pP04KkRXVxrlWRP5dGzQoMDghTh+W1QD9GiUSAyz4L9R3zxQ==", "license": "MIT", "dependencies": { - "lexical": "0.20.0" + "lexical": "0.22.0" } }, "node_modules/@lexical/table": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.20.0.tgz", - "integrity": "sha512-qHuK2rvQUoQDx62YpvJE3Ev4yK9kjRFo79IDBapxrhoXg/wCGQOjMBzVD3G5PWkhyl/GDnww80GwYjLloQLQzg==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.22.0.tgz", + "integrity": "sha512-Kx4N4kgYKTpcYtYYbp3hfG6We6ss3vWlhJ/f/QuUo18+w8c0a7aaCo4wTjNNUnSuXSFc1E02JlaTTVoI1pVfDw==", "license": "MIT", "dependencies": { - "@lexical/clipboard": "0.20.0", - "@lexical/utils": "0.20.0", - "lexical": "0.20.0" + "@lexical/clipboard": "0.22.0", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/text": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/text/-/text-0.20.0.tgz", - "integrity": "sha512-Fu64i5CIlEOlgucSdp9XFqB2XqoRsw4at76n93+6RF4+LgGDnu4nLXQVCVxNmLcGyh2WgczuTpnk5P2mHNAIUA==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/text/-/text-0.22.0.tgz", + "integrity": "sha512-eLQTH11FmTW8VBOcb3hKc6H4S4A2cXFDOXHE3lCA+ErLXOnwlj7tKm52eWyddPTlkNmZ3C8mIvfVPcS4Jxw20Q==", "license": "MIT", "dependencies": { - "lexical": "0.20.0" + "lexical": "0.22.0" } }, "node_modules/@lexical/utils": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.20.0.tgz", - "integrity": "sha512-sXIa2nowrNxY8VcjjuxZbJ/HovIql8bmInNaxBR03JAYfqMiL5I5/dYgjOQJV49NJnuR1uTY2GwVxVTXCTFUCw==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.22.0.tgz", + "integrity": "sha512-mQoNS4e0+lqkj3lPKE2u5vdQmdtgsqcLhzNJMhpCmFvJ896l5zKXOFQoFmF8BFz/v7w92FT7dpT5gd0lcIryyg==", "license": "MIT", "dependencies": { - "@lexical/list": "0.20.0", - "@lexical/selection": "0.20.0", - "@lexical/table": "0.20.0", - "lexical": "0.20.0" + "@lexical/list": "0.22.0", + "@lexical/selection": "0.22.0", + "@lexical/table": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/yjs": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@lexical/yjs/-/yjs-0.20.0.tgz", - "integrity": "sha512-TiHNhu2VkhXN69V+fXVS3xjOQ6aLnheQUGwOAhuFkDPL3VLCb0yl2Mgydpayn+3Grwii4ZBHcF7oCC84GiU5bw==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/yjs/-/yjs-0.22.0.tgz", + "integrity": "sha512-JrQO03HIIfOURpCpSZgZoTH8WBFumhvl9ysP1ZAqh9f2bLZp7qxi/jFgwOorz0NdM11Qb1dJprNNPaqNnS4BKA==", "license": "MIT", "dependencies": { - "@lexical/offset": "0.20.0", - "@lexical/selection": "0.20.0", - "lexical": "0.20.0" + "@lexical/offset": "0.22.0", + "@lexical/selection": "0.22.0", + "lexical": "0.22.0" }, "peerDependencies": { "yjs": ">=13.5.22" @@ -1280,6 +1634,12 @@ "node": ">= 8" } }, + "node_modules/@oslojs/encoding": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", + "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", + "license": "MIT" + }, "node_modules/@playwright/test": { "version": "1.43.1", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.1.tgz", @@ -1295,190 +1655,343 @@ "node": ">=16" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.0.tgz", - "integrity": "sha512-jwXtxYbRt1V+CdQSy6Z+uZti7JF5irRKF8hlKfEnF/xJpcNGuuiZMBvuoYM+x9sr9iWGnzrlM0+9hvQ1kgkf1w==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ] + "node_modules/@rollup/pluginutils": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", + "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.0.tgz", - "integrity": "sha512-fI9nduZhCccjzlsA/OuAwtFGWocxA4gqXGTLvOyiF8d+8o0fZUeSztixkYjcGq1fGZY3Tkq4yRvHPFxU+jdZ9Q==", + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.1.tgz", + "integrity": "sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.29.1.tgz", + "integrity": "sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.0.tgz", - "integrity": "sha512-BcnSPRM76/cD2gQC+rQNGBN6GStBs2pl/FpweW8JYuz5J/IEa0Fr4AtrPv766DB/6b2MZ/AfSIOSGw3nEIP8SA==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.29.1.tgz", + "integrity": "sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.0.tgz", - "integrity": "sha512-LDyFB9GRolGN7XI6955aFeI3wCdCUszFWumWU0deHA8VpR3nWRrjG6GtGjBrQxQKFevnUTHKCfPR4IvrW3kCgQ==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.29.1.tgz", + "integrity": "sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" ] }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.29.1.tgz", + "integrity": "sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.29.1.tgz", + "integrity": "sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.0.tgz", - "integrity": "sha512-ygrGVhQP47mRh0AAD0zl6QqCbNsf0eTo+vgwkY6LunBcg0f2Jv365GXlDUECIyoXp1kKwL5WW6rsO429DBY/bA==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.29.1.tgz", + "integrity": "sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.29.1.tgz", + "integrity": "sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.0.tgz", - "integrity": "sha512-x+uJ6MAYRlHGe9wi4HQjxpaKHPM3d3JjqqCkeC5gpnnI6OWovLdXTpfa8trjxPLnWKyBsSi5kne+146GAxFt4A==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.29.1.tgz", + "integrity": "sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.0.tgz", - "integrity": "sha512-nrRw8ZTQKg6+Lttwqo6a2VxR9tOroa2m91XbdQ2sUUzHoedXlsyvY1fN4xWdqz8PKmf4orDwejxXHjh7YBGUCA==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.29.1.tgz", + "integrity": "sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA==", "cpu": [ "arm64" ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.29.1.tgz", + "integrity": "sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw==", + "cpu": [ + "loong64" + ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.0.tgz", - "integrity": "sha512-xV0d5jDb4aFu84XKr+lcUJ9y3qpIWhttO3Qev97z8DKLXR62LC3cXT/bMZXrjLF9X+P5oSmJTzAhqwUbY96PnA==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.29.1.tgz", + "integrity": "sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w==", "cpu": [ - "ppc64le" + "ppc64" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.0.tgz", - "integrity": "sha512-SDDhBQwZX6LPRoPYjAZWyL27LbcBo7WdBFWJi5PI9RPCzU8ijzkQn7tt8NXiXRiFMJCVpkuMkBf4OxSxVMizAw==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.29.1.tgz", + "integrity": "sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ==", "cpu": [ "riscv64" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.0.tgz", - "integrity": "sha512-RxB/qez8zIDshNJDufYlTT0ZTVut5eCpAZ3bdXDU9yTxBzui3KhbGjROK2OYTTor7alM7XBhssgoO3CZ0XD3qA==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.29.1.tgz", + "integrity": "sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g==", "cpu": [ "s390x" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.0.tgz", - "integrity": "sha512-C6y6z2eCNCfhZxT9u+jAM2Fup89ZjiG5pIzZIDycs1IwESviLxwkQcFRGLjnDrP+PT+v5i4YFvlcfAs+LnreXg==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.29.1.tgz", + "integrity": "sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.0.tgz", - "integrity": "sha512-i0QwbHYfnOMYsBEyjxcwGu5SMIi9sImDVjDg087hpzXqhBSosxkE7gyIYFHgfFl4mr7RrXksIBZ4DoLoP4FhJg==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.29.1.tgz", + "integrity": "sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.0.tgz", - "integrity": "sha512-Fq52EYb0riNHLBTAcL0cun+rRwyZ10S9vKzhGKKgeD+XbwunszSY0rVMco5KbOsTlwovP2rTOkiII/fQ4ih/zQ==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.29.1.tgz", + "integrity": "sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.0.tgz", - "integrity": "sha512-e/PBHxPdJ00O9p5Ui43+vixSgVf4NlLsmV6QneGERJ3lnjIua/kim6PRFe3iDueT1rQcgSkYP8ZBBXa/h4iPvw==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.29.1.tgz", + "integrity": "sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.0.tgz", - "integrity": "sha512-aGg7iToJjdklmxlUlJh/PaPNa4PmqHfyRMLunbL3eaMO0gp656+q1zOKkpJ/CVe9CryJv6tAN1HDoR8cNGzkag==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.29.1.tgz", + "integrity": "sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@shikijs/core": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.2.4.tgz", - "integrity": "sha512-ClaUWpt8oTzjcF0MM1P81AeWyzc1sNSJlAjMG80CbwqbFqXSNz+NpQVUC0icobt3sZn43Sn27M4pHD/Jmp3zHw==" + "version": "1.24.4", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.24.4.tgz", + "integrity": "sha512-jjLsld+xEEGYlxAXDyGwWsKJ1sw5Pc1pnp4ai2ORpjx2UX08YYTC0NNqQYO1PaghYaR+PvgMOGuvzw2he9sk0Q==", + "license": "MIT", + "dependencies": { + "@shikijs/engine-javascript": "1.24.4", + "@shikijs/engine-oniguruma": "1.24.4", + "@shikijs/types": "1.24.4", + "@shikijs/vscode-textmate": "^9.3.1", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.4" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "1.24.4", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.24.4.tgz", + "integrity": "sha512-TClaQOLvo9WEMJv6GoUsykQ6QdynuKszuORFWCke8qvi6PeLm7FcD9+7y45UenysxEWYpDL5KJaVXTngTE+2BA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "1.24.4", + "@shikijs/vscode-textmate": "^9.3.1", + "oniguruma-to-es": "0.8.1" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "1.24.4", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.24.4.tgz", + "integrity": "sha512-Do2ry6flp2HWdvpj2XOwwa0ljZBRy15HKZITzPcNIBOGSeprnA8gOooA/bLsSPuy8aJBa+Q/r34dMmC3KNL/zw==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "1.24.4", + "@shikijs/vscode-textmate": "^9.3.1" + } + }, + "node_modules/@shikijs/types": { + "version": "1.24.4", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.24.4.tgz", + "integrity": "sha512-0r0XU7Eaow0PuDxuWC1bVqmWCgm3XqizIaT7SM42K03vc69LGooT0U8ccSR44xP/hGlNx4FKhtYpV+BU6aaKAA==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^9.3.1", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-9.3.1.tgz", + "integrity": "sha512-79QfK1393x9Ho60QFyLti+QfdJzRQCVLFb97kOIV7Eo9vQU/roINgk7m24uv0a7AUvN//RDH36FLjjK48v0s9g==", + "license": "MIT" }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -1517,31 +2030,41 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "license": "MIT" + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", "dependencies": { "@types/ms": "*" } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "license": "MIT" }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", "dependencies": { "@types/unist": "*" } }, "node_modules/@types/mdast": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", - "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", "dependencies": { "@types/unist": "*" } @@ -1549,21 +2072,18 @@ "node_modules/@types/ms": { "version": "0.7.34", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", - "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", + "license": "MIT" }, "node_modules/@types/nlcst": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-1.0.4.tgz", - "integrity": "sha512-ABoYdNQ/kBSsLvZAekMhIPMQ3YUZvavStpKYs7BjLLuKVmIMA0LUgZ7b54zzuWJRbHF80v1cNf4r90Vd6eMQDg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", + "license": "MIT", "dependencies": { - "@types/unist": "^2" + "@types/unist": "*" } }, - "node_modules/@types/nlcst/node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" - }, "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", @@ -1587,14 +2107,16 @@ } }, "node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" }, "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", + "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", + "license": "ISC" }, "node_modules/@vitejs/plugin-react": { "version": "4.2.1", @@ -1702,9 +2224,10 @@ "integrity": "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==" }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -1731,6 +2254,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", "dependencies": { "string-width": "^4.1.0" } @@ -1739,6 +2263,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { "node": ">=8" } @@ -1746,12 +2271,14 @@ "node_modules/ansi-align/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" }, "node_modules/ansi-align/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -1765,6 +2292,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -1773,9 +2301,10 @@ } }, "node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -1784,14 +2313,15 @@ } }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/anymatch": { @@ -1812,210 +2342,129 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dependencies": { - "dequal": "^2.0.3" + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" } }, "node_modules/array-iterate": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/astro": { - "version": "4.5.15", - "resolved": "https://registry.npmjs.org/astro/-/astro-4.5.15.tgz", - "integrity": "sha512-d2+yMv4ZlWwWFzfbpXIULMniNmdPlbwGrQScacEni0WLeo4k7ETO51/bHN/i/fXwxL9IGfasdEFkk2baYXDRog==", - "dependencies": { - "@astrojs/compiler": "^2.7.1", - "@astrojs/internal-helpers": "0.4.0", - "@astrojs/markdown-remark": "5.0.0", - "@astrojs/telemetry": "3.0.4", - "@babel/core": "^7.24.3", - "@babel/generator": "^7.23.3", - "@babel/parser": "^7.23.3", - "@babel/plugin-transform-react-jsx": "^7.22.5", - "@babel/traverse": "^7.23.3", - "@babel/types": "^7.23.3", - "@types/babel__core": "^7.20.4", - "acorn": "^8.11.2", - "aria-query": "^5.3.0", - "axobject-query": "^4.0.0", - "boxen": "^7.1.1", - "chokidar": "^3.5.3", - "ci-info": "^4.0.0", - "clsx": "^2.0.0", + "version": "4.16.18", + "resolved": "https://registry.npmjs.org/astro/-/astro-4.16.18.tgz", + "integrity": "sha512-G7zfwJt9BDHEZwlaLNvjbInIw2hPryyD654314KV/XT34pJU6SfN1S+mWa8RAkALcZNJnJXCJmT3JXLQStD3Lw==", + "license": "MIT", + "dependencies": { + "@astrojs/compiler": "^2.10.3", + "@astrojs/internal-helpers": "0.4.1", + "@astrojs/markdown-remark": "5.3.0", + "@astrojs/telemetry": "3.1.0", + "@babel/core": "^7.26.0", + "@babel/plugin-transform-react-jsx": "^7.25.9", + "@babel/types": "^7.26.0", + "@oslojs/encoding": "^1.1.0", + "@rollup/pluginutils": "^5.1.3", + "@types/babel__core": "^7.20.5", + "@types/cookie": "^0.6.0", + "acorn": "^8.14.0", + "aria-query": "^5.3.2", + "axobject-query": "^4.1.0", + "boxen": "8.0.1", + "ci-info": "^4.1.0", + "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", - "cookie": "^0.6.0", + "cookie": "^0.7.2", "cssesc": "^3.0.0", - "debug": "^4.3.4", - "deterministic-object-hash": "^2.0.1", - "devalue": "^4.3.2", - "diff": "^5.1.0", + "debug": "^4.3.7", + "deterministic-object-hash": "^2.0.2", + "devalue": "^5.1.1", + "diff": "^5.2.0", "dlv": "^1.1.3", - "dset": "^3.1.3", - "es-module-lexer": "^1.4.1", - "esbuild": "^0.19.6", + "dset": "^3.1.4", + "es-module-lexer": "^1.5.4", + "esbuild": "^0.21.5", "estree-walker": "^3.0.3", - "execa": "^8.0.1", "fast-glob": "^3.3.2", - "flattie": "^1.1.0", + "flattie": "^1.1.1", "github-slugger": "^2.0.0", "gray-matter": "^4.0.3", "html-escaper": "^3.0.3", "http-cache-semantics": "^4.1.1", "js-yaml": "^4.1.0", - "kleur": "^4.1.4", - "magic-string": "^0.30.3", - "mime": "^3.0.0", - "ora": "^7.0.1", - "p-limit": "^5.0.0", + "kleur": "^4.1.5", + "magic-string": "^0.30.14", + "magicast": "^0.3.5", + "micromatch": "^4.0.8", + "mrmime": "^2.0.0", + "neotraverse": "^0.6.18", + "ora": "^8.1.1", + "p-limit": "^6.1.0", "p-queue": "^8.0.1", - "path-to-regexp": "^6.2.1", - "preferred-pm": "^3.1.2", + "preferred-pm": "^4.0.0", "prompts": "^2.4.2", - "rehype": "^13.0.1", - "resolve": "^1.22.4", - "semver": "^7.5.4", - "shiki": "^1.1.2", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0", - "tsconfck": "^3.0.0", + "rehype": "^13.0.2", + "semver": "^7.6.3", + "shiki": "^1.23.1", + "tinyexec": "^0.3.1", + "tsconfck": "^3.1.4", "unist-util-visit": "^5.0.0", - "vfile": "^6.0.1", - "vite": "^5.1.4", - "vitefu": "^0.2.5", - "which-pm": "^2.1.1", + "vfile": "^6.0.3", + "vite": "^5.4.11", + "vitefu": "^1.0.4", + "which-pm": "^3.0.0", + "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", - "zod": "^3.22.4", - "zod-to-json-schema": "^3.22.4" + "zod": "^3.23.8", + "zod-to-json-schema": "^3.23.5", + "zod-to-ts": "^1.2.0" }, "bin": { "astro": "astro.js" }, "engines": { - "node": ">=18.14.1", - "npm": ">=6.14.0" + "node": "^18.17.1 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0" }, "optionalDependencies": { - "sharp": "^0.32.6" - } - }, - "node_modules/astro/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/astro/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "sharp": "^0.33.3" } }, - "node_modules/astro/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/axobject-query": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", - "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", - "dependencies": { - "dequal": "^2.0.3" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" } }, - "node_modules/b4a": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", - "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", - "optional": true - }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/bare-events": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz", - "integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==", - "optional": true - }, - "node_modules/bare-fs": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.2.3.tgz", - "integrity": "sha512-amG72llr9pstfXOBOHve1WjiuKKAMnebcmMbPWDZ7BCevAoJLpugjuAPRsDINEyjT0a6tbaVx3DctkXIRbLuJw==", - "optional": true, - "dependencies": { - "bare-events": "^2.0.0", - "bare-path": "^2.0.0", - "streamx": "^2.13.0" - } - }, - "node_modules/bare-os": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.2.1.tgz", - "integrity": "sha512-OwPyHgBBMkhC29Hl3O4/YfxW9n7mdTr2+SsO29XBWKKJsbgj3mnorDB80r5TiCQgQstgE5ga1qNYrpes6NvX2w==", - "optional": true - }, - "node_modules/bare-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.0.tgz", - "integrity": "sha512-DIIg7ts8bdRKwJRJrUMy/PICEaQZaPGZ26lsSx9MJSwIhSrcdHn7/C8W+XmnG/rKi6BaRcz+JO00CjZteybDtw==", - "optional": true, - "dependencies": { - "bare-os": "^2.1.0" - } - }, "node_modules/base-64": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==" }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -2027,84 +2476,44 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bl": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", - "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", - "dependencies": { - "buffer": "^6.0.3", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, "node_modules/boxen": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", - "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-8.0.1.tgz", + "integrity": "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==", + "license": "MIT", "dependencies": { "ansi-align": "^3.0.1", - "camelcase": "^7.0.1", - "chalk": "^5.2.0", + "camelcase": "^8.0.0", + "chalk": "^5.3.0", "cli-boxes": "^3.0.0", - "string-width": "^5.1.2", - "type-fest": "^2.13.0", - "widest-line": "^4.0.1", - "wrap-ansi": "^8.1.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/boxen/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, - "node_modules/boxen/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "string-width": "^7.2.0", + "type-fest": "^4.21.0", + "widest-line": "^5.0.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz", + "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==", "funding": [ { "type": "opencollective", @@ -2119,11 +2528,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -2132,85 +2542,65 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "node_modules/camelcase": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", + "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001690", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", + "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/feross" + "type": "opencollective", + "url": "https://opencollective.com/browserslist" }, { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/camelcase": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", - "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001605", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz", - "integrity": "sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" }, { "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "license": "MIT", "engines": { - "node": ">=4" + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/character-entities": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -2220,6 +2610,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -2229,6 +2620,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -2257,22 +2649,17 @@ "fsevents": "~2.3.2" } }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "optional": true - }, "node_modules/ci-info": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.0.0.tgz", - "integrity": "sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.1.0.tgz", + "integrity": "sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/sibiraj-s" } ], + "license": "MIT", "engines": { "node": ">=8" } @@ -2281,6 +2668,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -2289,14 +2677,15 @@ } }, "node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "license": "MIT", "dependencies": { - "restore-cursor": "^4.0.0" + "restore-cursor": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2306,6 +2695,7 @@ "version": "2.9.2", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", "engines": { "node": ">=6" }, @@ -2348,22 +2738,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/cliui/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/cliui/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, "node_modules/cliui/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -2410,9 +2784,10 @@ } }, "node_modules/clsx": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", - "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -2421,6 +2796,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", "optional": true, "dependencies": { "color-convert": "^2.0.1", @@ -2431,50 +2807,39 @@ } }, "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" }, "node_modules/color-string": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", "optional": true, "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, - "node_modules/color/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "optional": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "optional": true - }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -2491,25 +2856,12 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, "engines": { - "node": ">= 8" + "node": ">= 0.6" } }, "node_modules/cssesc": { @@ -2529,11 +2881,12 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -2548,6 +2901,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "license": "MIT", "dependencies": { "character-entities": "^2.0.0" }, @@ -2556,34 +2910,11 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "optional": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "optional": true, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -2592,6 +2923,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "license": "Apache-2.0", "optional": true, "engines": { "node": ">=8" @@ -2609,14 +2941,16 @@ } }, "node_modules/devalue": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.2.tgz", - "integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==" + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", + "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", + "license": "MIT" }, "node_modules/devlop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", "dependencies": { "dequal": "^2.0.0" }, @@ -2636,25 +2970,23 @@ "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" }, "node_modules/dset": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz", - "integrity": "sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", + "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" - }, "node_modules/electron-to-chromium": { - "version": "1.4.725", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.725.tgz", - "integrity": "sha512-OGkMXLY7XH6ykHE5ZOVVIMHaGAvvxqw98cswTKB683dntBJre7ufm9wouJ0ExDm0VXhHenU8mREvxIbV5nNoVQ==" + "version": "1.5.76", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz", + "integrity": "sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==", + "license": "ISC" }, "node_modules/emmet": { "version": "2.4.8", @@ -2666,23 +2998,22 @@ } }, "node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==" - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "optional": true, - "dependencies": { - "once": "^1.4.0" - } + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "license": "MIT" + }, + "node_modules/emoji-regex-xs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz", + "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==", + "license": "MIT" }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -2691,15 +3022,17 @@ } }, "node_modules/es-module-lexer": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz", - "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==" + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", + "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", + "license": "MIT" }, "node_modules/esbuild": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", - "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -2707,45 +3040,50 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.19.12", - "@esbuild/android-arm": "0.19.12", - "@esbuild/android-arm64": "0.19.12", - "@esbuild/android-x64": "0.19.12", - "@esbuild/darwin-arm64": "0.19.12", - "@esbuild/darwin-x64": "0.19.12", - "@esbuild/freebsd-arm64": "0.19.12", - "@esbuild/freebsd-x64": "0.19.12", - "@esbuild/linux-arm": "0.19.12", - "@esbuild/linux-arm64": "0.19.12", - "@esbuild/linux-ia32": "0.19.12", - "@esbuild/linux-loong64": "0.19.12", - "@esbuild/linux-mips64el": "0.19.12", - "@esbuild/linux-ppc64": "0.19.12", - "@esbuild/linux-riscv64": "0.19.12", - "@esbuild/linux-s390x": "0.19.12", - "@esbuild/linux-x64": "0.19.12", - "@esbuild/netbsd-x64": "0.19.12", - "@esbuild/openbsd-x64": "0.19.12", - "@esbuild/sunos-x64": "0.19.12", - "@esbuild/win32-arm64": "0.19.12", - "@esbuild/win32-ia32": "0.19.12", - "@esbuild/win32-x64": "0.19.12" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", "engines": { - "node": ">=0.8.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/esprima": { @@ -2773,41 +3111,11 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" }, - "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "optional": true, - "engines": { - "node": ">=6" - } - }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" }, "node_modules/extend-shallow": { "version": "2.0.1", @@ -2825,12 +3133,6 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, - "node_modules/fast-fifo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "optional": true - }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -2860,9 +3162,10 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2871,15 +3174,25 @@ } }, "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", + "locate-path": "^5.0.0", "path-exists": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=8" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz", + "integrity": "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==", + "license": "MIT", + "engines": { + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2889,6 +3202,7 @@ "version": "1.2.16", "resolved": "https://registry.npmjs.org/find-yarn-workspace-root2/-/find-yarn-workspace-root2-1.2.16.tgz", "integrity": "sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==", + "license": "Apache-2.0", "dependencies": { "micromatch": "^4.0.2", "pkg-dir": "^4.2.0" @@ -2902,12 +3216,6 @@ "node": ">=8" } }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "optional": true - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2921,14 +3229,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -2946,9 +3246,10 @@ } }, "node_modules/get-east-asian-width": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", - "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "license": "MIT", "engines": { "node": ">=18" }, @@ -2956,27 +3257,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "optional": true - }, "node_modules/github-slugger": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", - "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==" + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", + "license": "ISC" }, "node_modules/glob-parent": { "version": "5.1.2", @@ -2993,6 +3278,7 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", "engines": { "node": ">=4" } @@ -3000,7 +3286,8 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" }, "node_modules/gray-matter": { "version": "4.0.3", @@ -3036,29 +3323,11 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/hast-util-from-html": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.1.tgz", - "integrity": "sha512-RXQBLMl9kjKVNkJTIO6bZyb2n+cUH8LFaSSzo82jiLT6Tfc+Pt7VQCS+/h3YwG4jaNE2TA2sdJisGWR+aJrp0g==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "devlop": "^1.1.0", @@ -3073,14 +3342,15 @@ } }, "node_modules/hast-util-from-parse5": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz", - "integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.2.tgz", + "integrity": "sha512-SfMzfdAi/zAoZ1KkFEyyeXBn7u/ShQrfd675ZEE9M3qj+PMFX05xubzRyF76CCSJu8au9jgVxDV1+okFvgZU4A==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", - "hastscript": "^8.0.0", + "hastscript": "^9.0.0", "property-information": "^6.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", @@ -3095,6 +3365,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -3107,6 +3378,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -3116,9 +3388,10 @@ } }, "node_modules/hast-util-raw": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.2.tgz", - "integrity": "sha512-PldBy71wO9Uq1kyaMch9AHIghtQvIwxBUkv823pKmkTM3oV1JxtsTNYdevMxvUHqcnOAuO65JKU2+0NOxc2ksA==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", @@ -3140,15 +3413,15 @@ } }, "node_modules/hast-util-to-html": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.1.tgz", - "integrity": "sha512-hZOofyZANbyWo+9RP75xIDV/gq+OUKx+T46IlwERnKmfpwp81XBFbT9mi26ws+SJchA4RVUQwIBJpqEOBhMzEQ==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.4.tgz", + "integrity": "sha512-wxQzXtdbhiwGAUKrnQJXlOPmHnEehzphwkK7aluUPQ+lEc1xefC8pblMgpp2w5ldBTEfveRIrADcrhGIWrlTDA==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", - "hast-util-raw": "^9.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", @@ -3166,6 +3439,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", @@ -3181,9 +3455,10 @@ } }, "node_modules/hast-util-to-text": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.0.tgz", - "integrity": "sha512-EWiE1FSArNBPUo1cKWtzqgnuRQwEeQbQtnFJRYV1hb1BWDgrAlBU0ExptvZMM/KSA82cDpm2sFGf3Dmc5Mza3w==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", @@ -3199,6 +3474,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -3208,9 +3484,10 @@ } }, "node_modules/hastscript": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", - "integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.0.tgz", + "integrity": "sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", @@ -3232,6 +3509,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -3242,57 +3520,21 @@ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" }, - "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "engines": { - "node": ">=16.17.0" + "node_modules/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/import-meta-resolve": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz", - "integrity": "sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "optional": true - }, "node_modules/is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT", "optional": true }, "node_modules/is-binary-path": { @@ -3306,43 +3548,11 @@ "node": ">=8" } }, - "node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=4" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-docker": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -3392,6 +3602,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", "dependencies": { "is-docker": "^3.0.0" }, @@ -3409,6 +3620,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -3420,6 +3632,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -3428,6 +3641,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -3435,23 +3649,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3461,6 +3665,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" }, @@ -3471,11 +3676,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, "node_modules/isomorphic.js": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz", @@ -3504,14 +3704,15 @@ } }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-schema-traverse": { @@ -3552,15 +3753,15 @@ } }, "node_modules/lexical": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.20.0.tgz", - "integrity": "sha512-lJEHLFACXqRf3u/VlIOu9T7MJ51O4la92uOBwiS9Sx+juDK3Nrru5Vgl1aUirV1qK8XEM3h6Org2HcrsrzZ3ZA==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.22.0.tgz", + "integrity": "sha512-EquENoJZdhwAzsZ+Dz8dGZprlpPY1zez6Gk9yhGkPzmIVPRIGY4aEAmfKQCep1dZgkUUQB8Flr0xK0+u5TrFhw==", "license": "MIT" }, "node_modules/lib0": { - "version": "0.2.98", - "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.98.tgz", - "integrity": "sha512-XteTiNO0qEXqqweWx+b21p/fBnNHUA1NwAtJNJek1oPrewEZs2uiT4gWivHKr9GqCjDPAhchz0UQO8NwU3bBNA==", + "version": "0.2.99", + "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.99.tgz", + "integrity": "sha512-vwztYuUf1uf/1zQxfzRfO5yzfNKhTtgOByCruuiQQxWQXnPb8Itaube5ylofcV0oM0aKal9Mv+S1s1Ky0UYP1w==", "license": "MIT", "peer": true, "dependencies": { @@ -3583,6 +3784,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz", "integrity": "sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==", + "license": "MIT", "dependencies": { "graceful-fs": "^4.1.5", "js-yaml": "^3.13.0", @@ -3597,6 +3799,7 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } @@ -3605,6 +3808,7 @@ "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -3614,17 +3818,15 @@ } }, "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" + "p-locate": "^4.1.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/lodash": { @@ -3633,35 +3835,38 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/log-symbols": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", - "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "license": "MIT", "dependencies": { - "chalk": "^5.0.0", - "is-unicode-supported": "^1.1.0" + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "license": "MIT", "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -3682,25 +3887,36 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", "dependencies": { "yallist": "^3.0.2" } }, "node_modules/magic-string": { - "version": "0.30.8", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", - "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" } }, "node_modules/markdown-table": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", - "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -3710,6 +3926,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", "integrity": "sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", @@ -3724,6 +3941,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", @@ -3735,21 +3953,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/mdast-util-from-markdown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz", - "integrity": "sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", @@ -3773,6 +3981,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "license": "MIT", "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-gfm-autolink-literal": "^2.0.0", @@ -3788,9 +3997,10 @@ } }, "node_modules/mdast-util-gfm-autolink-literal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz", - "integrity": "sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "ccount": "^2.0.0", @@ -3807,6 +4017,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.1.0", @@ -3823,6 +4034,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", @@ -3837,6 +4049,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", @@ -3853,6 +4066,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", @@ -3868,6 +4082,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" @@ -3878,9 +4093,10 @@ } }, "node_modules/mdast-util-to-hast": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.1.0.tgz", - "integrity": "sha512-/e2l/6+OdGp/FB+ctrJ9Avz71AN/GRH3oi/3KAx/kMnoUsD6q0woXlDT8lLEeViVKE7oZxE7RXzvO3T8kF2/sA==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -3898,15 +4114,17 @@ } }, "node_modules/mdast-util-to-markdown": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", - "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "longest-streak": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" @@ -3920,6 +4138,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0" }, @@ -3928,11 +4147,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -3942,9 +4156,9 @@ } }, "node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.1.tgz", + "integrity": "sha512-eBPdkcoCNvYcxQOAKAlceo5SNdzZWfF+FcSupREAzdAh9rRmE239CEQAiTwIgblwnoM8zzj35sZ5ZwvSEOF6Kw==", "funding": [ { "type": "GitHub Sponsors", @@ -3955,6 +4169,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", @@ -3976,9 +4191,9 @@ } }, "node_modules/micromark-core-commonmark": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz", - "integrity": "sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.2.tgz", + "integrity": "sha512-FKjQKbxd1cibWMM1P9N+H8TwlgGgSkWZMmfuVucLCHaYqeSvJ0hFeHsIa65pA2nYbes0f8LDHPMrd9X7Ujxg9w==", "funding": [ { "type": "GitHub Sponsors", @@ -3989,6 +4204,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", @@ -4012,6 +4228,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", "micromark-extension-gfm-footnote": "^2.0.0", @@ -4028,9 +4245,10 @@ } }, "node_modules/micromark-extension-gfm-autolink-literal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz", - "integrity": "sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", @@ -4043,9 +4261,10 @@ } }, "node_modules/micromark-extension-gfm-footnote": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz", - "integrity": "sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", @@ -4062,9 +4281,10 @@ } }, "node_modules/micromark-extension-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", @@ -4079,9 +4299,10 @@ } }, "node_modules/micromark-extension-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz", - "integrity": "sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.0.tgz", + "integrity": "sha512-Ub2ncQv+fwD70/l4ou27b4YzfNaCJOvyX4HxXU15m7mpYY+rjuWzsLIPZHJL253Z643RpbcP1oeIJlQ/SKW67g==", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", @@ -4098,6 +4319,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" }, @@ -4107,9 +4329,10 @@ } }, "node_modules/micromark-extension-gfm-task-list-item": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz", - "integrity": "sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", @@ -4123,9 +4346,9 @@ } }, "node_modules/micromark-factory-destination": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", - "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", "funding": [ { "type": "GitHub Sponsors", @@ -4136,6 +4359,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", @@ -4143,9 +4367,9 @@ } }, "node_modules/micromark-factory-label": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", - "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", "funding": [ { "type": "GitHub Sponsors", @@ -4156,6 +4380,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", @@ -4164,9 +4389,9 @@ } }, "node_modules/micromark-factory-space": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", - "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -4177,15 +4402,16 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "node_modules/micromark-factory-title": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", - "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", "funding": [ { "type": "GitHub Sponsors", @@ -4196,6 +4422,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", @@ -4204,9 +4431,9 @@ } }, "node_modules/micromark-factory-whitespace": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", - "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", "funding": [ { "type": "GitHub Sponsors", @@ -4217,6 +4444,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", @@ -4225,9 +4453,9 @@ } }, "node_modules/micromark-util-character": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", - "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -4238,15 +4466,16 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "node_modules/micromark-util-chunked": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", - "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", "funding": [ { "type": "GitHub Sponsors", @@ -4257,14 +4486,15 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "node_modules/micromark-util-classify-character": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", - "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", "funding": [ { "type": "GitHub Sponsors", @@ -4275,6 +4505,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", @@ -4282,9 +4513,9 @@ } }, "node_modules/micromark-util-combine-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", - "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", "funding": [ { "type": "GitHub Sponsors", @@ -4295,15 +4526,16 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", - "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", "funding": [ { "type": "GitHub Sponsors", @@ -4314,14 +4546,15 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "node_modules/micromark-util-decode-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", - "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", "funding": [ { "type": "GitHub Sponsors", @@ -4332,6 +4565,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", @@ -4340,9 +4574,9 @@ } }, "node_modules/micromark-util-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", - "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", "funding": [ { "type": "GitHub Sponsors", @@ -4352,12 +4586,13 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-html-tag-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", - "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", "funding": [ { "type": "GitHub Sponsors", @@ -4367,12 +4602,13 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", - "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", "funding": [ { "type": "GitHub Sponsors", @@ -4383,14 +4619,15 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "node_modules/micromark-util-resolve-all": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", - "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", "funding": [ { "type": "GitHub Sponsors", @@ -4401,14 +4638,15 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" } }, "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", - "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", "funding": [ { "type": "GitHub Sponsors", @@ -4419,6 +4657,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", @@ -4426,9 +4665,9 @@ } }, "node_modules/micromark-util-subtokenize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz", - "integrity": "sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.3.tgz", + "integrity": "sha512-VXJJuNxYWSoYL6AJ6OQECCFGhIU2GGHMw8tahogePBrjkG8aCCas3ibkp7RnVOSTClg2is05/R7maAhF1XyQMg==", "funding": [ { "type": "GitHub Sponsors", @@ -4439,6 +4678,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", @@ -4447,9 +4687,9 @@ } }, "node_modules/micromark-util-symbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", - "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -4459,12 +4699,13 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", - "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.1.tgz", + "integrity": "sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==", "funding": [ { "type": "GitHub Sponsors", @@ -4474,73 +4715,48 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, - "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "optional": true, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "license": "MIT", "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "optional": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "optional": true - }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/muggle-string": { "version": "0.4.1", @@ -4548,15 +4764,16 @@ "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==" }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -4564,79 +4781,33 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "optional": true + "node_modules/neotraverse": { + "version": "0.6.18", + "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz", + "integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==", + "license": "MIT", + "engines": { + "node": ">= 10" + } }, "node_modules/nlcst-to-string": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-3.1.1.tgz", - "integrity": "sha512-63mVyqaqt0cmn2VcI2aH6kxe1rLAmSROqHMA0i4qqg1tidkfExgpb0FGMikMCn86mw5dFtBtEANfmSSK7TjNHw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", + "license": "MIT", "dependencies": { - "@types/nlcst": "^1.0.0" + "@types/nlcst": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/node-abi": { - "version": "3.57.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.57.0.tgz", - "integrity": "sha512-Dp+A9JWxRaKuHP35H77I4kCKesDy5HUDEmScia2FyncMTOXASMyg251F5PhFoDA5uqBrDDffiLpbqnrZmNXW+g==", - "optional": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/node-addon-api": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", - "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", - "optional": true - }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -4646,109 +4817,62 @@ "node": ">=0.10.0" } }, - "node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "license": "MIT", "dependencies": { - "path-key": "^4.0.0" + "mimic-function": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "optional": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "node_modules/oniguruma-to-es": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-0.8.1.tgz", + "integrity": "sha512-dekySTEvCxCj0IgKcA2uUCO/e4ArsqpucDPcX26w9ajx+DvMWLc5eZeJaRQkd7oC/+rwif5gnT900tA34uN9Zw==", + "license": "MIT", "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "emoji-regex-xs": "^1.0.0", + "regex": "^5.0.2", + "regex-recursion": "^5.0.0" } }, "node_modules/ora": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-7.0.1.tgz", - "integrity": "sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.1.1.tgz", + "integrity": "sha512-YWielGi1XzG1UTvOaCFaNgEnuhZVMSHYkW/FQ7UX8O26PtlpdM84c0f7wLPlkvx2RfiQmnzd61d/MGxmpQeJPw==", + "license": "MIT", "dependencies": { "chalk": "^5.3.0", - "cli-cursor": "^4.0.0", - "cli-spinners": "^2.9.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", - "is-unicode-supported": "^1.3.0", - "log-symbols": "^5.1.0", - "stdin-discarder": "^0.1.0", - "string-width": "^6.1.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ora/node_modules/string-width": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-6.1.0.tgz", - "integrity": "sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^10.2.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=16" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-limit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", - "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", + "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", + "license": "MIT", "dependencies": { - "yocto-queue": "^1.0.0" + "yocto-queue": "^1.1.1" }, "engines": { "node": ">=18" @@ -4758,39 +4882,27 @@ } }, "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" + "p-limit": "^2.2.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/p-locate/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" + "p-try": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate/node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4826,18 +4938,23 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/parse-latin": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-5.0.1.tgz", - "integrity": "sha512-b/K8ExXaWC9t34kKeDV8kGXBkXZ1HCSAZRYE7HR14eA1GlXX5L8iWhs8USJNhQU9q5ci413jCKF0gOyovvyRBg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", + "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", + "license": "MIT", "dependencies": { - "nlcst-to-string": "^3.0.0", - "unist-util-modify-children": "^3.0.0", - "unist-util-visit-children": "^2.0.0" + "@types/nlcst": "^2.0.0", + "@types/unist": "^3.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-modify-children": "^4.0.0", + "unist-util-visit-children": "^3.0.0", + "vfile": "^6.0.0" }, "funding": { "type": "github", @@ -4845,11 +4962,12 @@ } }, "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "license": "MIT", "dependencies": { - "entities": "^4.4.0" + "entities": "^4.5.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -4864,32 +4982,16 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" - }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -4906,6 +5008,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "license": "MIT", "engines": { "node": ">=6" } @@ -4914,6 +5017,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -4921,54 +5025,6 @@ "node": ">=8" } }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/playwright": { "version": "1.43.1", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz", @@ -5014,9 +5070,9 @@ } }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "funding": [ { "type": "opencollective", @@ -5031,128 +5087,28 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" } }, - "node_modules/prebuild-install": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", - "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prebuild-install/node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "optional": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/prebuild-install/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/prebuild-install/node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "optional": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/prebuild-install/node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "optional": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/preferred-pm": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-3.1.3.tgz", - "integrity": "sha512-MkXsENfftWSRpzCzImcp4FRsCc3y1opwB73CfCNWyzMqArju2CrlMHlqB7VexKiPEOjGMbttv1r9fSCn5S610w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-4.0.0.tgz", + "integrity": "sha512-gYBeFTZLu055D8Vv3cSPox/0iTPtkzxpLroSYYA7WXgRi31WCJ51Uyl8ZiPeUUjyvs2MBzK+S8v9JVUgHU/Sqw==", + "license": "MIT", "dependencies": { - "find-up": "^5.0.0", + "find-up-simple": "^1.0.0", "find-yarn-workspace-root2": "1.2.16", - "path-exists": "^4.0.0", - "which-pm": "2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/preferred-pm/node_modules/which-pm": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.0.0.tgz", - "integrity": "sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==", - "dependencies": { - "load-yaml-file": "^0.2.0", - "path-exists": "^4.0.0" + "which-pm": "^3.0.0" }, "engines": { - "node": ">=8.15" + "node": ">=18.12" } }, "node_modules/prettier": { @@ -5176,6 +5132,7 @@ "version": "1.29.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "license": "MIT", "engines": { "node": ">=6" } @@ -5204,21 +5161,12 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "optional": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -5238,27 +5186,6 @@ } ] }, - "node_modules/queue-tick": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", - "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", - "optional": true - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "optional": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -5305,19 +5232,6 @@ "node": ">=0.10.0" } }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -5334,10 +5248,36 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, + "node_modules/regex": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/regex/-/regex-5.1.1.tgz", + "integrity": "sha512-dN5I359AVGPnwzJm2jN1k0W9LPZ+ePvoOeVMMfqIMFz53sSwXkxaJoxr50ptnsC771lK95BnTrVSZxq0b9yCGw==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-5.1.1.tgz", + "integrity": "sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w==", + "license": "MIT", + "dependencies": { + "regex": "^5.1.1", + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" + }, "node_modules/rehype": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.1.tgz", - "integrity": "sha512-AcSLS2mItY+0fYu9xKxOu1LhUZeBZZBx8//5HKzF+0XP+eP8+6a5MXn2+DW2kfXR6Dtp1FEXMVrjyKAcvcU8vg==", + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.2.tgz", + "integrity": "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "rehype-parse": "^9.0.0", @@ -5350,9 +5290,10 @@ } }, "node_modules/rehype-parse": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.0.tgz", - "integrity": "sha512-WG7nfvmWWkCR++KEkZevZb/uw41E8TsH4DsY9UxsTbIXCVGbAs4S+r8FrQ+OtH5EEQAs+5UxKC42VinkmpA1Yw==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", + "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "hast-util-from-html": "^2.0.0", @@ -5367,6 +5308,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "hast-util-raw": "^9.0.0", @@ -5378,9 +5320,10 @@ } }, "node_modules/rehype-stringify": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.0.tgz", - "integrity": "sha512-1TX1i048LooI9QoecrXy7nGFFbFSufxVRAfc6Y9YMRAi56l+oB0zP51mLSV312uRuvVLPV1opSlJmslozR1XHQ==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", + "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "hast-util-to-html": "^9.0.0", @@ -5395,6 +5338,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", @@ -5412,6 +5356,7 @@ "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", @@ -5424,9 +5369,10 @@ } }, "node_modules/remark-rehype": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.0.tgz", - "integrity": "sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz", + "integrity": "sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -5440,22 +5386,25 @@ } }, "node_modules/remark-smartypants": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-2.1.0.tgz", - "integrity": "sha512-qoF6Vz3BjU2tP6OfZqHOvCU0ACmu/6jhGaINSQRI9mM7wCxNQTKB3JUAN4SVoN2ybElEDTxBIABRep7e569iJw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.2.tgz", + "integrity": "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==", + "license": "MIT", "dependencies": { - "retext": "^8.1.0", - "retext-smartypants": "^5.2.0", + "retext": "^9.0.0", + "retext-smartypants": "^6.0.0", + "unified": "^11.0.4", "unist-util-visit": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=16.0.0" } }, "node_modules/remark-stringify": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", @@ -5487,73 +5436,32 @@ "node": ">=0.10.0" } }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": ">=6" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, "node_modules/retext": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/retext/-/retext-8.1.0.tgz", - "integrity": "sha512-N9/Kq7YTn6ZpzfiGW45WfEGJqFf1IM1q8OsRa1CGzIebCJBNCANDRmOrholiDRGKo/We7ofKR4SEvcGAWEMD3Q==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", + "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", + "license": "MIT", "dependencies": { - "@types/nlcst": "^1.0.0", - "retext-latin": "^3.0.0", - "retext-stringify": "^3.0.0", - "unified": "^10.0.0" + "@types/nlcst": "^2.0.0", + "retext-latin": "^4.0.0", + "retext-stringify": "^4.0.0", + "unified": "^11.0.0" }, "funding": { "type": "opencollective", @@ -5561,77 +5469,14 @@ } }, "node_modules/retext-latin": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-3.1.0.tgz", - "integrity": "sha512-5MrD1tuebzO8ppsja5eEu+ZbBeUNCjoEarn70tkXOS7Bdsdf6tNahsv2bY0Z8VooFF6cw7/6S+d3yI/TMlMVVQ==", - "dependencies": { - "@types/nlcst": "^1.0.0", - "parse-latin": "^5.0.0", - "unherit": "^3.0.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-latin/node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" - }, - "node_modules/retext-latin/node_modules/unified": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", - "dependencies": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-latin/node_modules/unist-util-stringify-position": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", - "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", - "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-latin/node_modules/vfile": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", - "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", - "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-latin/node_modules/vfile-message": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", - "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz", + "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^3.0.0" + "@types/nlcst": "^2.0.0", + "parse-latin": "^7.0.0", + "unified": "^11.0.0" }, "funding": { "type": "opencollective", @@ -5639,116 +5484,14 @@ } }, "node_modules/retext-smartypants": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-5.2.0.tgz", - "integrity": "sha512-Do8oM+SsjrbzT2UNIKgheP0hgUQTDDQYyZaIY3kfq0pdFzoPk+ZClYJ+OERNXveog4xf1pZL4PfRxNoVL7a/jw==", - "dependencies": { - "@types/nlcst": "^1.0.0", - "nlcst-to-string": "^3.0.0", - "unified": "^10.0.0", - "unist-util-visit": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-smartypants/node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" - }, - "node_modules/retext-smartypants/node_modules/unified": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", - "dependencies": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-smartypants/node_modules/unist-util-is": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", - "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", - "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-smartypants/node_modules/unist-util-stringify-position": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", - "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", - "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-smartypants/node_modules/unist-util-visit": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", - "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0", - "unist-util-visit-parents": "^5.1.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-smartypants/node_modules/unist-util-visit-parents": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", - "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-is": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-smartypants/node_modules/vfile": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", - "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", - "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-smartypants/node_modules/vfile-message": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", - "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", + "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^3.0.0" + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" }, "funding": { "type": "opencollective", @@ -5756,139 +5499,14 @@ } }, "node_modules/retext-stringify": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-3.1.0.tgz", - "integrity": "sha512-767TLOaoXFXyOnjx/EggXlb37ZD2u4P1n0GJqVdpipqACsQP+20W+BNpMYrlJkq7hxffnFk+jc6mAK9qrbuB8w==", - "dependencies": { - "@types/nlcst": "^1.0.0", - "nlcst-to-string": "^3.0.0", - "unified": "^10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-stringify/node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" - }, - "node_modules/retext-stringify/node_modules/unified": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", - "dependencies": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-stringify/node_modules/unist-util-stringify-position": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", - "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", - "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-stringify/node_modules/vfile": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", - "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", - "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext-stringify/node_modules/vfile-message": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", - "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", - "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext/node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" - }, - "node_modules/retext/node_modules/unified": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", - "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", - "dependencies": { - "@types/unist": "^2.0.0", - "bail": "^2.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^5.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext/node_modules/unist-util-stringify-position": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", - "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", - "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext/node_modules/vfile": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", - "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", - "dependencies": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^3.0.0", - "vfile-message": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/retext/node_modules/vfile-message": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", - "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz", + "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^3.0.0" + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unified": "^11.0.0" }, "funding": { "type": "opencollective", @@ -5905,11 +5523,12 @@ } }, "node_modules/rollup": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.0.tgz", - "integrity": "sha512-Qe7w62TyawbDzB4yt32R0+AbIo6m1/sqO7UPzFS8Z/ksL5mrfhA0v4CavfdmFav3D+ub4QeAgsGEe84DoWe/nQ==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.29.1.tgz", + "integrity": "sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==", + "license": "MIT", "dependencies": { - "@types/estree": "1.0.5" + "@types/estree": "1.0.6" }, "bin": { "rollup": "dist/bin/rollup" @@ -5919,21 +5538,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.14.0", - "@rollup/rollup-android-arm64": "4.14.0", - "@rollup/rollup-darwin-arm64": "4.14.0", - "@rollup/rollup-darwin-x64": "4.14.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.14.0", - "@rollup/rollup-linux-arm64-gnu": "4.14.0", - "@rollup/rollup-linux-arm64-musl": "4.14.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.14.0", - "@rollup/rollup-linux-riscv64-gnu": "4.14.0", - "@rollup/rollup-linux-s390x-gnu": "4.14.0", - "@rollup/rollup-linux-x64-gnu": "4.14.0", - "@rollup/rollup-linux-x64-musl": "4.14.0", - "@rollup/rollup-win32-arm64-msvc": "4.14.0", - "@rollup/rollup-win32-ia32-msvc": "4.14.0", - "@rollup/rollup-win32-x64-msvc": "4.14.0", + "@rollup/rollup-android-arm-eabi": "4.29.1", + "@rollup/rollup-android-arm64": "4.29.1", + "@rollup/rollup-darwin-arm64": "4.29.1", + "@rollup/rollup-darwin-x64": "4.29.1", + "@rollup/rollup-freebsd-arm64": "4.29.1", + "@rollup/rollup-freebsd-x64": "4.29.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.29.1", + "@rollup/rollup-linux-arm-musleabihf": "4.29.1", + "@rollup/rollup-linux-arm64-gnu": "4.29.1", + "@rollup/rollup-linux-arm64-musl": "4.29.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.29.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.29.1", + "@rollup/rollup-linux-riscv64-gnu": "4.29.1", + "@rollup/rollup-linux-s390x-gnu": "4.29.1", + "@rollup/rollup-linux-x64-gnu": "4.29.1", + "@rollup/rollup-linux-x64-musl": "4.29.1", + "@rollup/rollup-win32-arm64-msvc": "4.29.1", + "@rollup/rollup-win32-ia32-msvc": "4.29.1", + "@rollup/rollup-win32-x64-msvc": "4.29.1", "fsevents": "~2.3.2" } }, @@ -5959,25 +5582,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -5999,100 +5603,76 @@ } }, "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/sharp": { - "version": "0.32.6", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", - "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", "hasInstallScript": true, + "license": "Apache-2.0", "optional": true, "dependencies": { "color": "^4.2.3", - "detect-libc": "^2.0.2", - "node-addon-api": "^6.1.0", - "prebuild-install": "^7.1.1", - "semver": "^7.5.4", - "simple-get": "^4.0.1", - "tar-fs": "^3.0.4", - "tunnel-agent": "^0.6.0" + "detect-libc": "^2.0.3", + "semver": "^7.6.3" }, "engines": { - "node": ">=14.15.0" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" - } - }, - "node_modules/sharp/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sharp/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sharp/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dependencies": { - "shebang-regex": "^3.0.0" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "engines": { - "node": ">=8" + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" } }, "node_modules/shiki": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.2.4.tgz", - "integrity": "sha512-Q9n9jKiOjJCRPztA9POn3/uZXNySHDNKAsPNpmtHDcFyi6ZQhx5vQKZW3Nhrwn8TWW3RudSRk66zqY603EZDeg==", + "version": "1.24.4", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.24.4.tgz", + "integrity": "sha512-aVGSFAOAr1v26Hh/+GBIsRVDWJ583XYV7CuNURKRWh9gpGv4OdbisZGq96B9arMYTZhTQkmRF5BrShOSTvNqhw==", + "license": "MIT", "dependencies": { - "@shikijs/core": "1.2.4" + "@shikijs/core": "1.24.4", + "@shikijs/engine-javascript": "1.24.4", + "@shikijs/engine-oniguruma": "1.24.4", + "@shikijs/types": "1.24.4", + "@shikijs/vscode-textmate": "^9.3.1", + "@types/hast": "^3.0.4" } }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", "engines": { "node": ">=14" }, @@ -6100,55 +5680,11 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true, - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", "optional": true, "dependencies": { "is-arrayish": "^0.3.1" @@ -6160,9 +5696,10 @@ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -6171,6 +5708,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -6182,44 +5720,22 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "node_modules/stdin-discarder": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", - "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", - "dependencies": { - "bl": "^5.0.0" - }, + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/streamx": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz", - "integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==", - "optional": true, - "dependencies": { - "fast-fifo": "^1.1.0", - "queue-tick": "^1.0.1" - }, - "optionalDependencies": { - "bare-events": "^2.2.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string-width": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", - "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -6236,6 +5752,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" @@ -6249,6 +5766,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -6263,6 +5781,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "license": "MIT", "engines": { "node": ">=4" } @@ -6275,85 +5794,17 @@ "node": ">=0.10.0" } }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tar-fs": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz", - "integrity": "sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==", - "optional": true, - "dependencies": { - "pump": "^3.0.0", - "tar-stream": "^3.1.5" - }, - "optionalDependencies": { - "bare-fs": "^2.1.1", - "bare-path": "^2.1.0" - } - }, - "node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", - "optional": true, - "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "engines": { - "node": ">=4" - } + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "license": "MIT" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -6365,6 +5816,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -6374,15 +5826,17 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/tsconfck": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.0.3.tgz", - "integrity": "sha512-4t0noZX9t6GcPTfBAbIbbIU4pfpCwh0ueq3S4O/5qXI1VwK1outmxhe9dOiEWqMz3MW2LKgDTpqWV+37IWuVbA==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.4.tgz", + "integrity": "sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==", + "license": "MIT", "bin": { "tsconfck": "bin/tsconfck.js" }, @@ -6398,24 +5852,20 @@ } } }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "optional": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true }, "node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "version": "4.31.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.31.0.tgz", + "integrity": "sha512-yCxltHW07Nkhv/1F6wWBr8kz+5BGMfP+RbRSYFnegVb0qV/UMT0G0ElBloPVerqn4M2ZV80Ir1FtCcYv1cT6vQ==", + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=12.20" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6446,35 +5896,16 @@ "semver": "^7.3.8" } }, - "node_modules/typescript-auto-import-cache/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/ultrahtml": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.5.3.tgz", "integrity": "sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==" }, - "node_modules/unherit": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-3.0.1.tgz", - "integrity": "sha512-akOOQ/Yln8a2sgcLj4U0Jmx0R5jpIg2IUyRrWOzmEbjBtGzBdHtSeFKgoEcoH4KYIG/Pb8GQ/BwtYm0GCq1Sqg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/unified": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", - "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", @@ -6493,6 +5924,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" @@ -6506,6 +5938,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -6515,11 +5948,12 @@ } }, "node_modules/unist-util-modify-children": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-3.1.1.tgz", - "integrity": "sha512-yXi4Lm+TG5VG+qvokP6tpnk+r1EPwyYL04JWDxLvgvPV40jANh7nm3udk65OOWquvbMDe+PL9+LmkxDpTv/7BA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz", + "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==", + "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", + "@types/unist": "^3.0.0", "array-iterate": "^2.0.0" }, "funding": { @@ -6527,15 +5961,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-modify-children/node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" - }, "node_modules/unist-util-position": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -6548,6 +5978,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-visit": "^5.0.0" @@ -6561,6 +5992,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -6573,562 +6005,186 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-children": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-2.0.2.tgz", - "integrity": "sha512-+LWpMFqyUwLGpsQxpumsQ9o9DG2VGLFrpz+rpVXYIEdPy57GSy5HioC0g3bg/8WP9oCLlapQtklOzQ8uLS496Q==", - "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-children/node_modules/@types/unist": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", - "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" - }, - "node_modules/unist-util-visit-parents": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", - "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/vfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", - "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile-location": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.2.tgz", - "integrity": "sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==", - "dependencies": { - "@types/unist": "^3.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile-message": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vite": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz", - "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==", - "dependencies": { - "esbuild": "^0.20.1", - "postcss": "^8.4.38", - "rollup": "^4.13.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" + "node_modules/unist-util-visit-children": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz", + "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } ], - "engines": { - "node": ">=12" + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", - "hasInstallScript": true, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "5.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", + "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, "bin": { - "esbuild": "bin/esbuild" + "vite": "bin/vite.js" }, "engines": { - "node": ">=12" + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } } }, "node_modules/vitefu": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", - "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.4.tgz", + "integrity": "sha512-y6zEE3PQf6uu/Mt6DTJ9ih+kyJLr4XcSgHR2zUkM8SWDhuixEJxfJ6CZGMHh1Ec3vPLoEA0IHU5oWzVqw8ulow==", + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*" + ], "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "peerDependenciesMeta": { "vite": { @@ -7248,17 +6304,6 @@ } } }, - "node_modules/volar-service-typescript/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/volar-service-yaml": { "version": "0.0.61", "resolved": "https://registry.npmjs.org/volar-service-yaml/-/volar-service-yaml-0.0.61.tgz", @@ -7370,133 +6415,70 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/which-pm": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.1.1.tgz", - "integrity": "sha512-xzzxNw2wMaoCWXiGE8IJ9wuPMU+EYhFksjHxrRT8kMT5SnocBPRg69YAMtyV4D12fP582RA+k3P8H9J5EMdIxQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-3.0.0.tgz", + "integrity": "sha512-ysVYmw6+ZBhx3+ZkcPwRuJi38ZOTLJJ33PSHaitLxSKUMsh0LkKd0nC69zZCwt5D+AYUcMK2hhw4yWny20vSGg==", + "license": "MIT", "dependencies": { - "load-yaml-file": "^0.2.0", - "path-exists": "^4.0.0" + "load-yaml-file": "^0.2.0" }, "engines": { - "node": ">=8.15" + "node": ">=18.12" } }, "node_modules/which-pm-runs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/widest-line": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", - "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", - "dependencies": { - "string-width": "^5.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/widest-line/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, - "node_modules/widest-line/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz", + "integrity": "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==", + "license": "MIT", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "string-width": "^7.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "license": "MIT", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "optional": true + "node_modules/xxhash-wasm": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", + "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==", + "license": "MIT" }, "node_modules/y18n": { "version": "5.0.8", @@ -7509,7 +6491,8 @@ "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" }, "node_modules/yaml": { "version": "2.5.1", @@ -7670,9 +6653,9 @@ } }, "node_modules/yjs": { - "version": "13.6.20", - "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.20.tgz", - "integrity": "sha512-Z2YZI+SYqK7XdWlloI3lhMiKnCdFCVC4PchpdO+mCYwtiTwncjUbnRK9R1JmkNfdmHyDXuWN3ibJAt0wsqTbLQ==", + "version": "13.6.21", + "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.21.tgz", + "integrity": "sha512-/fzzyeCAfr3Qwx1D71zvumm64x+Q5MEFel6EhWlA1IBFxWPb7tei4J2a8CJyjpYHfVrRij5q3RJTK9W2Iqjouw==", "license": "MIT", "peer": true, "dependencies": { @@ -7688,9 +6671,10 @@ } }, "node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "license": "MIT", "engines": { "node": ">=12.20" }, @@ -7699,25 +6683,37 @@ } }, "node_modules/zod": { - "version": "3.22.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", - "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", + "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/zod-to-json-schema": { - "version": "3.22.5", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.22.5.tgz", - "integrity": "sha512-+akaPo6a0zpVCCseDed504KBJUQpEW5QZw7RMneNmKw+fGaML1Z9tUNLnHHAC8x6dzVRO1eB2oEMyZRnuBZg7Q==", + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.1.tgz", + "integrity": "sha512-3h08nf3Vw3Wl3PK+q3ow/lIil81IT2Oa7YpQyUUDsEWbXveMesdfK1xBd2RhCkynwZndAxixji/7SYJJowr62w==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.24.1" + } + }, + "node_modules/zod-to-ts": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/zod-to-ts/-/zod-to-ts-1.2.0.tgz", + "integrity": "sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==", "peerDependencies": { - "zod": "^3.22.4" + "typescript": "^4.9.4 || ^5.0.2", + "zod": "^3" } }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" diff --git a/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/package.json b/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/package.json index 6f2e97d445a..9864430be38 100644 --- a/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/package.json +++ b/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/package.json @@ -1,7 +1,7 @@ { "name": "lexical-esm-astro-react", "type": "module", - "version": "0.21.0", + "version": "0.23.1", "scripts": { "dev": "astro dev", "start": "astro dev", @@ -13,12 +13,12 @@ "dependencies": { "@astrojs/check": "^0.9.3", "@astrojs/react": "^3.1.0", - "@lexical/react": "0.21.0", - "@lexical/utils": "0.21.0", + "@lexical/react": "0.23.1", + "@lexical/utils": "0.23.1", "@types/react": "^18.2.66", "@types/react-dom": "^18.2.22", "astro": "^4.5.4", - "lexical": "0.21.0", + "lexical": "0.23.1", "react": "^18.2.0", "react-dom": "^18.2.0", "typescript": "^5.4.2" diff --git a/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/src/components/plugins/TreeViewPlugin.tsx b/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/src/components/plugins/TreeViewPlugin.tsx index 62eb7425c44..f72600c947e 100644 --- a/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/src/components/plugins/TreeViewPlugin.tsx +++ b/scripts/__tests__/integration/fixtures/lexical-esm-astro-react/src/components/plugins/TreeViewPlugin.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {TreeView} from '@lexical/react/LexicalTreeView'; // import * as React from 'react'; diff --git a/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/app/plugins/TreeViewPlugin.tsx b/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/app/plugins/TreeViewPlugin.tsx index 62eb7425c44..f72600c947e 100644 --- a/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/app/plugins/TreeViewPlugin.tsx +++ b/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/app/plugins/TreeViewPlugin.tsx @@ -6,6 +6,8 @@ * */ +import type {JSX} from 'react'; + import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import {TreeView} from '@lexical/react/LexicalTreeView'; // import * as React from 'react'; diff --git a/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/package-lock.json b/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/package-lock.json index 5b61357e9d2..b05fb5ebf71 100644 --- a/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/package-lock.json +++ b/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/package-lock.json @@ -1,16 +1,16 @@ { "name": "lexical-esm-nextjs", - "version": "0.1.0", + "version": "0.22.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lexical-esm-nextjs", - "version": "0.1.0", + "version": "0.22.0", "dependencies": { - "@lexical/plain-text": "^0.14.5", - "@lexical/react": "^0.14.5", - "lexical": "^0.14.5", + "@lexical/plain-text": "0.22.0", + "@lexical/react": "0.22.0", + "lexical": "0.22.0", "next": "^14.2.1", "react": "^18", "react-dom": "^18" @@ -142,38 +142,41 @@ } }, "node_modules/@lexical/clipboard": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.14.5.tgz", - "integrity": "sha512-22xbagoQ8jiwImRtMcRl3+pojsiqF0cSfMXbjsHc5fPAq3ULf8OvAMkiSWEOxGQA6I6VIHX30+HtwZ7TgdPJ7A==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.22.0.tgz", + "integrity": "sha512-nG3MX7MYmaf4f4Ia0YaYaJIS1QriuUxNaLHYeAqOPqYZLH1CUnXslCiak6OyQ4dt/QozKKvGM5vpZN2QWvs0Xw==", + "license": "MIT", "dependencies": { - "@lexical/html": "0.14.5", - "@lexical/list": "0.14.5", - "@lexical/selection": "0.14.5", - "@lexical/utils": "0.14.5", - "lexical": "0.14.5" + "@lexical/html": "0.22.0", + "@lexical/list": "0.22.0", + "@lexical/selection": "0.22.0", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/code": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/code/-/code-0.14.5.tgz", - "integrity": "sha512-eBZ5GMx2VDg7tC085qCD2+hzwGm5b6M/b4LXiPW0In6/SmJIDnEOppSz7jmHezWkLIGL2xK43gw1oqTY9igwug==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/code/-/code-0.22.0.tgz", + "integrity": "sha512-5HQGcv+R7+uOxFGGqGxE5Mj2LcYwxniHejri7s3OJTSeFrGxAXwP2Kxb+5FSvWsyg265snuxZlNNfKVozgJPhA==", + "license": "MIT", "dependencies": { - "@lexical/utils": "0.14.5", - "lexical": "0.14.5", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0", "prismjs": "^1.27.0" } }, "node_modules/@lexical/devtools-core": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/devtools-core/-/devtools-core-0.14.5.tgz", - "integrity": "sha512-4yTZ8Q9sDkvA5n96wEstru2NonAJ6T/zuSTcYizddwDJr56tzanSdJUFbEIG6G3ankqbKMRYNetupD/Ks3sXEg==", - "dependencies": { - "@lexical/html": "0.14.5", - "@lexical/link": "0.14.5", - "@lexical/mark": "0.14.5", - "@lexical/table": "0.14.5", - "@lexical/utils": "0.14.5", - "lexical": "0.14.5" + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/devtools-core/-/devtools-core-0.22.0.tgz", + "integrity": "sha512-PFdaN2c+O/eLqNcWzuLBz0AaiLPHs9+iMHUZDQMgAWcKS6uiEBA61VS+ZNZn8zj8RZZvUtxgmZ9wQFFURklfww==", + "license": "MIT", + "dependencies": { + "@lexical/html": "0.22.0", + "@lexical/link": "0.22.0", + "@lexical/mark": "0.22.0", + "@lexical/table": "0.22.0", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" }, "peerDependencies": { "react": ">=17.x", @@ -181,133 +184,145 @@ } }, "node_modules/@lexical/dragon": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/dragon/-/dragon-0.14.5.tgz", - "integrity": "sha512-p+rybaKGcxC8SCerQaMxRf+GcD+0YEXiv8WHx4DaxrTnHdn+8gapFpwe9Sxjmga/6BqeLa3rF/fis3zN3oyMlg==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/dragon/-/dragon-0.22.0.tgz", + "integrity": "sha512-68b1EiFbYRqPEhbrFPhfTNe/hSTCFtwBmcIP5cGgEef+lL5XqCxc6NK2g2DK4Dx26DSGwXxTuRG8NuuxFN+CiA==", + "license": "MIT", "dependencies": { - "lexical": "0.14.5" + "lexical": "0.22.0" } }, "node_modules/@lexical/hashtag": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/hashtag/-/hashtag-0.14.5.tgz", - "integrity": "sha512-jfIFZRm99EIAOsztgFBodyR8Rn/6TI7ee5HonBH6xFY439DheQxTaWDP0Y1SeL7iiu8d3ak2+AXvne1kBziR2A==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/hashtag/-/hashtag-0.22.0.tgz", + "integrity": "sha512-W6Wrz0+ClezZQavjCjYso+LzRP/rWNUIM6cLwnf7oFXsmIXeaLHXecIbRwZ+SChnj4eUlSlnlknMVi3bJKaOjw==", + "license": "MIT", "dependencies": { - "@lexical/utils": "0.14.5", - "lexical": "0.14.5" + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/history": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/history/-/history-0.14.5.tgz", - "integrity": "sha512-Img2hPZ5QA0Sm2Y3HcHqK4qqluabhJrOm93vtOnk7eQU0JLTjFnprPIzRiKnNLpjbasJI6Be5z/3pI4LNIpIvw==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/history/-/history-0.22.0.tgz", + "integrity": "sha512-4e/xL7CtYvsv8X4iGH1tPL8J6jthDpzh0a1WWZfL9ipeOYN9Btctq6o1Obdth5DfbMR7ELq7PSN2FK6+jZ4EQQ==", + "license": "MIT", "dependencies": { - "@lexical/utils": "0.14.5", - "lexical": "0.14.5" + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/html": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.14.5.tgz", - "integrity": "sha512-HITDaKld+039OGsEbNpZ16ykmuspptRuaN8UFGfy4Y/isVzF3V3DmgXtIuUe47S4jaXVSbCZG18o//om1ytkTw==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.22.0.tgz", + "integrity": "sha512-ED2Xik95a4kPg9vbU5pT/sA5hvEyGnuVxg0XvMx/6Gaa7OIhYDiZvSD4DCE+eVfn0xZMnIbX94Ygf4//71kCYw==", + "license": "MIT", "dependencies": { - "@lexical/selection": "0.14.5", - "@lexical/utils": "0.14.5", - "lexical": "0.14.5" + "@lexical/selection": "0.22.0", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/link": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/link/-/link-0.14.5.tgz", - "integrity": "sha512-NnMWRnMtigSBzM1zDSCzvwPPEOyelYy4Jlk9Iqq0KpRnzo248HAotMUTaYdMfWRgGIdPzflYZH5UhZJOAhH+qg==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/link/-/link-0.22.0.tgz", + "integrity": "sha512-mtlsOYW6sgbgvv1ecPt6/9CdlgP0MhVyrF8iu16JpngphVXu/Lz2BSh7TCfY0xho/H2OIu++9lUGn87cK1Zplw==", + "license": "MIT", "dependencies": { - "@lexical/utils": "0.14.5", - "lexical": "0.14.5" + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/list": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.14.5.tgz", - "integrity": "sha512-kVD7FCbtbT5noydQQ6+AcBjkQS2cLb071uoDiKX+EHzDko08b8xdD63r1rqnj2kOvYlsNLVtf5yy6Cv4xNxWDw==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.22.0.tgz", + "integrity": "sha512-DZLzMg1/H+nclV8BNqZe2qk/bz1ogCr7Huzwab5o8jTjpsDJaqyUZasj8wRgBzyLu9jxMQngkarL47nnk+zrbA==", + "license": "MIT", "dependencies": { - "@lexical/utils": "0.14.5", - "lexical": "0.14.5" + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/mark": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/mark/-/mark-0.14.5.tgz", - "integrity": "sha512-Z8YTHLrKpNHkCPATd3bzJhkbOnK0/gpZtjxphn+JvhgLOvmHIWCPS+HixQn10RJbcCAnja6QuhfsbgmP+c2eKA==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/mark/-/mark-0.22.0.tgz", + "integrity": "sha512-d8Jb9xqhHwUrN2uBs0aIjvA/NgeAZCI5Zorynqq5ihBVSytrol09JyRt4t7SXRH4sCpDMDLMWfTjm820RQFq8g==", + "license": "MIT", "dependencies": { - "@lexical/utils": "0.14.5", - "lexical": "0.14.5" + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/markdown": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/markdown/-/markdown-0.14.5.tgz", - "integrity": "sha512-lLVU2Vaj0cvh8lv8NBuxIhMLGuSroXf6Ls2CH81nN+eafL5X8yKGb2ae9EUdKxxppBKzZJxfe+phUlLgAqgVeg==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/markdown/-/markdown-0.22.0.tgz", + "integrity": "sha512-FJNfegbgry4dFwyzjdK6sasYHsVgiYy2WrVmVKYR/EDBxa0MARnVO7lRRXA37WcqMKi5N8dE/dABmjlmzuYzHA==", + "license": "MIT", "dependencies": { - "@lexical/code": "0.14.5", - "@lexical/link": "0.14.5", - "@lexical/list": "0.14.5", - "@lexical/rich-text": "0.14.5", - "@lexical/text": "0.14.5", - "@lexical/utils": "0.14.5", - "lexical": "0.14.5" + "@lexical/code": "0.22.0", + "@lexical/link": "0.22.0", + "@lexical/list": "0.22.0", + "@lexical/rich-text": "0.22.0", + "@lexical/text": "0.22.0", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/offset": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/offset/-/offset-0.14.5.tgz", - "integrity": "sha512-oUBr7SQhLHc0/SImyizgBXnfvmmh41i1nnaWJ1kflgXRXPpW1OxnFsuVB8EGKrc5nToxfrcwl6iryuDyJVrQ7g==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/offset/-/offset-0.22.0.tgz", + "integrity": "sha512-DgfO0q1+PzLzmMgRxTC7+y4whL6btlNSfv7f47TBAMBoj5tKdkGyMrru0xjoeYHVsMiSNgqMY2HTXU5YokKUOg==", + "license": "MIT", "dependencies": { - "lexical": "0.14.5" + "lexical": "0.22.0" } }, "node_modules/@lexical/overflow": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/overflow/-/overflow-0.14.5.tgz", - "integrity": "sha512-mZSQID6GTxSrnx+SeUqmyB8OZUTHolXqm0Ck2L27fRIIUQGZTXR9+CrV4+t2jNFK3brTo2POB95xwBq+O463hA==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/overflow/-/overflow-0.22.0.tgz", + "integrity": "sha512-LPj27ChVsOUW7Gv28z9m7NfpPQs7e3OooYL1WzU3R8NYDj/U32YxQXpUDcxHKwBPo8j8NVEna2d3UAG1txz6BA==", + "license": "MIT", "dependencies": { - "lexical": "0.14.5" + "lexical": "0.22.0" } }, "node_modules/@lexical/plain-text": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.14.5.tgz", - "integrity": "sha512-i0NiJ1RZ/990nArZcKcQOG+0SxO8ErUDT+QDCGOoGGqG02pQf+UuiLVWW9GdD+5unA7eRQDUza10MMyzsV+MJA==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.22.0.tgz", + "integrity": "sha512-MBlX4PfLN6I/As8uuRnL/17B+lIjmtNSIH90NjykRwBC8dtWr4gzSjm9OGTee6HctxnbQNb1BGLM7W1hLtiKAw==", + "license": "MIT", "dependencies": { - "@lexical/clipboard": "0.14.5", - "@lexical/selection": "0.14.5", - "@lexical/utils": "0.14.5", - "lexical": "0.14.5" + "@lexical/clipboard": "0.22.0", + "@lexical/selection": "0.22.0", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/react": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/react/-/react-0.14.5.tgz", - "integrity": "sha512-dn7J07nxG6CZqm5jhLjhkQlJWMQrdm4BGTEF6/MYog5uUUwqDwBdVnZ3hwadibupAmNT7+Xia+4vrp0oJWM1lQ==", - "dependencies": { - "@lexical/clipboard": "0.14.5", - "@lexical/code": "0.14.5", - "@lexical/devtools-core": "0.14.5", - "@lexical/dragon": "0.14.5", - "@lexical/hashtag": "0.14.5", - "@lexical/history": "0.14.5", - "@lexical/link": "0.14.5", - "@lexical/list": "0.14.5", - "@lexical/mark": "0.14.5", - "@lexical/markdown": "0.14.5", - "@lexical/overflow": "0.14.5", - "@lexical/plain-text": "0.14.5", - "@lexical/rich-text": "0.14.5", - "@lexical/selection": "0.14.5", - "@lexical/table": "0.14.5", - "@lexical/text": "0.14.5", - "@lexical/utils": "0.14.5", - "@lexical/yjs": "0.14.5", - "lexical": "0.14.5", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/react/-/react-0.22.0.tgz", + "integrity": "sha512-kHeAX6QFsDcdih2kBQVnIATOQsDzpMp2VLYlSxatF8JvCTaMQ3quH/CGHLnUAauZDxM2LC/eV+Z4nrUOP3Alyg==", + "license": "MIT", + "dependencies": { + "@lexical/clipboard": "0.22.0", + "@lexical/code": "0.22.0", + "@lexical/devtools-core": "0.22.0", + "@lexical/dragon": "0.22.0", + "@lexical/hashtag": "0.22.0", + "@lexical/history": "0.22.0", + "@lexical/link": "0.22.0", + "@lexical/list": "0.22.0", + "@lexical/mark": "0.22.0", + "@lexical/markdown": "0.22.0", + "@lexical/overflow": "0.22.0", + "@lexical/plain-text": "0.22.0", + "@lexical/rich-text": "0.22.0", + "@lexical/selection": "0.22.0", + "@lexical/table": "0.22.0", + "@lexical/text": "0.22.0", + "@lexical/utils": "0.22.0", + "@lexical/yjs": "0.22.0", + "lexical": "0.22.0", "react-error-boundary": "^3.1.4" }, "peerDependencies": { @@ -316,76 +331,86 @@ } }, "node_modules/@lexical/rich-text": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.14.5.tgz", - "integrity": "sha512-hLZ8oBrc4ZuYK3KbviV0pUW1R9CvsN8dLTOdYpW5hxvCMDI6UFrtRmaURQY96M7JSYQsDMrtyKyFuID3RwOR1w==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.22.0.tgz", + "integrity": "sha512-ILN/tht6emxbVK12Hp86y50fk0MGHMHg6Ivt/5OncoDPXfLMicuJRgLgLxLl5dCf7UVQOfa7z8eKEWnE83M5Mg==", + "license": "MIT", "dependencies": { - "@lexical/clipboard": "0.14.5", - "@lexical/selection": "0.14.5", - "@lexical/utils": "0.14.5", - "lexical": "0.14.5" + "@lexical/clipboard": "0.22.0", + "@lexical/selection": "0.22.0", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/selection": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.14.5.tgz", - "integrity": "sha512-uK4X1wOSnlq2xvIIludnPb6i+grtV4IR7Y1Dg7ZGFJfk1q5FWuS9iA3iVjZbSiehgbZef5nDCPRez9WN/F5krA==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.22.0.tgz", + "integrity": "sha512-DdRh8bHijQGV1OxeaywulaLRxgYtn1B7miS0I4pP04KkRXVxrlWRP5dGzQoMDghTh+W1QD9GiUSAyz4L9R3zxQ==", + "license": "MIT", "dependencies": { - "lexical": "0.14.5" + "lexical": "0.22.0" } }, "node_modules/@lexical/table": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.14.5.tgz", - "integrity": "sha512-K+R1w6KL9jIf9gKcXP1x3gPQxaVf+u9rjidKAZptgZYH/O4aLnE7MR+nrLFUYYw0NPOOgYTFxJOk9OW500TtKA==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.22.0.tgz", + "integrity": "sha512-Kx4N4kgYKTpcYtYYbp3hfG6We6ss3vWlhJ/f/QuUo18+w8c0a7aaCo4wTjNNUnSuXSFc1E02JlaTTVoI1pVfDw==", + "license": "MIT", "dependencies": { - "@lexical/utils": "0.14.5", - "lexical": "0.14.5" + "@lexical/clipboard": "0.22.0", + "@lexical/utils": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/text": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/text/-/text-0.14.5.tgz", - "integrity": "sha512-qcoORBgy3MD1xmmm5hE248HmL3BJLU/+qGvJz7Ei/9Fh5p2+PIYoL90KRcOP6Pp3pDs3ocydb+YcCxLg9L+OOQ==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/text/-/text-0.22.0.tgz", + "integrity": "sha512-eLQTH11FmTW8VBOcb3hKc6H4S4A2cXFDOXHE3lCA+ErLXOnwlj7tKm52eWyddPTlkNmZ3C8mIvfVPcS4Jxw20Q==", + "license": "MIT", "dependencies": { - "lexical": "0.14.5" + "lexical": "0.22.0" } }, "node_modules/@lexical/utils": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.14.5.tgz", - "integrity": "sha512-KoO63Y5lsgMxcLLIUC/Gwiof4BoKODY5i0NGUhUez/zGq4vCdXp+1DVJF7gmmvg9/vx0J16IrTcr/SAoAnhSFg==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.22.0.tgz", + "integrity": "sha512-mQoNS4e0+lqkj3lPKE2u5vdQmdtgsqcLhzNJMhpCmFvJ896l5zKXOFQoFmF8BFz/v7w92FT7dpT5gd0lcIryyg==", + "license": "MIT", "dependencies": { - "@lexical/list": "0.14.5", - "@lexical/selection": "0.14.5", - "@lexical/table": "0.14.5", - "lexical": "0.14.5" + "@lexical/list": "0.22.0", + "@lexical/selection": "0.22.0", + "@lexical/table": "0.22.0", + "lexical": "0.22.0" } }, "node_modules/@lexical/yjs": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/@lexical/yjs/-/yjs-0.14.5.tgz", - "integrity": "sha512-Y9dMA/B0tlkQLRUmwnfkPKOOaFQSFSp257pDoQr5Gnpx1OjZWGbbesPn4h2dFhGeLme41nznGZNwxR5nH6lGaw==", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@lexical/yjs/-/yjs-0.22.0.tgz", + "integrity": "sha512-JrQO03HIIfOURpCpSZgZoTH8WBFumhvl9ysP1ZAqh9f2bLZp7qxi/jFgwOorz0NdM11Qb1dJprNNPaqNnS4BKA==", + "license": "MIT", "dependencies": { - "@lexical/offset": "0.14.5", - "lexical": "0.14.5" + "@lexical/offset": "0.22.0", + "@lexical/selection": "0.22.0", + "lexical": "0.22.0" }, "peerDependencies": { "yjs": ">=13.5.22" } }, "node_modules/@next/env": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.1.tgz", - "integrity": "sha512-qsHJle3GU3CmVx7pUoXcghX4sRN+vINkbLdH611T8ZlsP//grzqVW87BSUgOZeSAD4q7ZdZicdwNe/20U2janA==" + "version": "14.2.21", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.21.tgz", + "integrity": "sha512-lXcwcJd5oR01tggjWJ6SrNNYFGuOOMB9c251wUNkjCpkoXOPkDeF/15c3mnVlBqrW4JJXb2kVxDFhC4GduJt2A==", + "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.1.tgz", - "integrity": "sha512-kGjnjcIJehEcd3rT/3NAATJQndAEELk0J9GmGMXHSC75TMnvpOhONcjNHbjtcWE5HUQnIHy5JVkatrnYm1QhVw==", + "version": "14.2.21", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.21.tgz", + "integrity": "sha512-HwEjcKsXtvszXz5q5Z7wCtrHeTTDSTgAbocz45PHMUjU3fBYInfvhR+ZhavDRUYLonm53aHZbB09QtJVJj8T7g==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -395,12 +420,13 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.1.tgz", - "integrity": "sha512-dAdWndgdQi7BK2WSXrx4lae7mYcOYjbHJUhvOUnJjMNYrmYhxbbvJ2xElZpxNxdfA6zkqagIB9He2tQk+l16ew==", + "version": "14.2.21", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.21.tgz", + "integrity": "sha512-TSAA2ROgNzm4FhKbTbyJOBrsREOMVdDIltZ6aZiKvCi/v0UwFmwigBGeqXDA97TFMpR3LNNpw52CbVelkoQBxA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -410,12 +436,13 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.1.tgz", - "integrity": "sha512-2ZctfnyFOGvTkoD6L+DtQtO3BfFz4CapoHnyLTXkOxbZkVRgg3TQBUjTD/xKrO1QWeydeo8AWfZRg8539qNKrg==", + "version": "14.2.21", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.21.tgz", + "integrity": "sha512-0Dqjn0pEUz3JG+AImpnMMW/m8hRtl1GQCNbO66V1yp6RswSTiKmnHf3pTX6xMdJYSemf3O4Q9ykiL0jymu0TuA==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -425,12 +452,13 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.1.tgz", - "integrity": "sha512-jazZXctiaanemy4r+TPIpFP36t1mMwWCKMsmrTRVChRqE6putyAxZA4PDujx0SnfvZHosjdkx9xIq9BzBB5tWg==", + "version": "14.2.21", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.21.tgz", + "integrity": "sha512-Ggfw5qnMXldscVntwnjfaQs5GbBbjioV4B4loP+bjqNEb42fzZlAaK+ldL0jm2CTJga9LynBMhekNfV8W4+HBw==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -440,12 +468,13 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.1.tgz", - "integrity": "sha512-VjCHWCjsAzQAAo8lkBOLEIkBZFdfW+Z18qcQ056kL4KpUYc8o59JhLDCBlhg+hINQRgzQ2UPGma2AURGOH0+Qg==", + "version": "14.2.21", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.21.tgz", + "integrity": "sha512-uokj0lubN1WoSa5KKdThVPRffGyiWlm/vCc/cMkWOQHw69Qt0X1o3b2PyLLx8ANqlefILZh1EdfLRz9gVpG6tg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -455,12 +484,13 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.1.tgz", - "integrity": "sha512-7HZKYKvAp4nAHiHIbY04finRqjeYvkITOGOurP1aLMexIFG/1+oCnqhGogBdc4lao/lkMW1c+AkwWSzSlLasqw==", + "version": "14.2.21", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.21.tgz", + "integrity": "sha512-iAEBPzWNbciah4+0yI4s7Pce6BIoxTQ0AGCkxn/UBuzJFkYyJt71MadYQkjPqCQCJAFQ26sYh7MOKdU+VQFgPg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -470,12 +500,13 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.1.tgz", - "integrity": "sha512-YGHklaJ/Cj/F0Xd8jxgj2p8po4JTCi6H7Z3Yics3xJhm9CPIqtl8erlpK1CLv+HInDqEWfXilqatF8YsLxxA2Q==", + "version": "14.2.21", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.21.tgz", + "integrity": "sha512-plykgB3vL2hB4Z32W3ktsfqyuyGAPxqwiyrAi2Mr8LlEUhNn9VgkiAl5hODSBpzIfWweX3er1f5uNpGDygfQVQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -485,12 +516,13 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.1.tgz", - "integrity": "sha512-o+ISKOlvU/L43ZhtAAfCjwIfcwuZstiHVXq/BDsZwGqQE0h/81td95MPHliWCnFoikzWcYqh+hz54ZB2FIT8RA==", + "version": "14.2.21", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.21.tgz", + "integrity": "sha512-w5bacz4Vxqrh06BjWgua3Yf7EMDb8iMcVhNrNx8KnJXt8t+Uu0Zg4JHLDL/T7DkTCEEfKXO/Er1fcfWxn2xfPA==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -500,12 +532,13 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.1.tgz", - "integrity": "sha512-GmRoTiLcvCLifujlisknv4zu9/C4i9r0ktsA8E51EMqJL4bD4CpO7lDYr7SrUxCR0tS4RVcrqKmCak24T0ohaw==", + "version": "14.2.21", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.21.tgz", + "integrity": "sha512-sT6+llIkzpsexGYZq8cjjthRyRGe5cJVhqh12FmlbxHqna6zsDDK8UNaV7g41T6atFHCJUPeLb3uyAwrBwy0NA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -1197,6 +1230,7 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz", "integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==", + "license": "MIT", "peer": true, "funding": { "type": "GitHub Sponsors ❤", @@ -1236,14 +1270,16 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/lexical": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.14.5.tgz", - "integrity": "sha512-ouV7Gyr9+3WT3WTrCgRAD3iZnlJWfs2/kBl2x3J2Q3X9uCWJn/zn21fQ8G1EUHlu0dvXPBmdk9hXb/FjTClt6Q==" + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.22.0.tgz", + "integrity": "sha512-EquENoJZdhwAzsZ+Dz8dGZprlpPY1zez6Gk9yhGkPzmIVPRIGY4aEAmfKQCep1dZgkUUQB8Flr0xK0+u5TrFhw==", + "license": "MIT" }, "node_modules/lib0": { - "version": "0.2.93", - "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.93.tgz", - "integrity": "sha512-M5IKsiFJYulS+8Eal8f+zAqf5ckm1vffW0fFDxfgxJ+uiVopvDdd3PxJmz0GsVi3YNO7QCFSq0nAsiDmNhLj9Q==", + "version": "0.2.99", + "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.99.tgz", + "integrity": "sha512-vwztYuUf1uf/1zQxfzRfO5yzfNKhTtgOByCruuiQQxWQXnPb8Itaube5ylofcV0oM0aKal9Mv+S1s1Ky0UYP1w==", + "license": "MIT", "peer": true, "dependencies": { "isomorphic.js": "^0.2.4" @@ -1356,11 +1392,12 @@ } }, "node_modules/next": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.1.tgz", - "integrity": "sha512-SF3TJnKdH43PMkCcErLPv+x/DY1YCklslk3ZmwaVoyUfDgHKexuKlf9sEfBQ69w+ue8jQ3msLb+hSj1T19hGag==", + "version": "14.2.21", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.21.tgz", + "integrity": "sha512-rZmLwucLHr3/zfDMYbJXbw0ZeoBpirxkXuvsJbk7UPorvPYZhP7vq7aHbKnU7dQNCYIimRrbB2pp3xmf+wsYUg==", + "license": "MIT", "dependencies": { - "@next/env": "14.2.1", + "@next/env": "14.2.21", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", @@ -1375,15 +1412,15 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.2.1", - "@next/swc-darwin-x64": "14.2.1", - "@next/swc-linux-arm64-gnu": "14.2.1", - "@next/swc-linux-arm64-musl": "14.2.1", - "@next/swc-linux-x64-gnu": "14.2.1", - "@next/swc-linux-x64-musl": "14.2.1", - "@next/swc-win32-arm64-msvc": "14.2.1", - "@next/swc-win32-ia32-msvc": "14.2.1", - "@next/swc-win32-x64-msvc": "14.2.1" + "@next/swc-darwin-arm64": "14.2.21", + "@next/swc-darwin-x64": "14.2.21", + "@next/swc-linux-arm64-gnu": "14.2.21", + "@next/swc-linux-arm64-musl": "14.2.21", + "@next/swc-linux-x64-gnu": "14.2.21", + "@next/swc-linux-x64-musl": "14.2.21", + "@next/swc-win32-arm64-msvc": "14.2.21", + "@next/swc-win32-ia32-msvc": "14.2.21", + "@next/swc-win32-x64-msvc": "14.2.21" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -1736,6 +1773,7 @@ "version": "1.29.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "license": "MIT", "engines": { "node": ">=6" } @@ -2335,12 +2373,13 @@ } }, "node_modules/yjs": { - "version": "13.6.14", - "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.14.tgz", - "integrity": "sha512-D+7KcUr0j+vBCUSKXXEWfA+bG4UQBviAwP3gYBhkstkgwy5+8diOPMx0iqLIOxNo/HxaREUimZRxqHGAHCL2BQ==", + "version": "13.6.21", + "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.21.tgz", + "integrity": "sha512-/fzzyeCAfr3Qwx1D71zvumm64x+Q5MEFel6EhWlA1IBFxWPb7tei4J2a8CJyjpYHfVrRij5q3RJTK9W2Iqjouw==", + "license": "MIT", "peer": true, "dependencies": { - "lib0": "^0.2.86" + "lib0": "^0.2.98" }, "engines": { "node": ">=16.0.0", diff --git a/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/package.json b/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/package.json index 2a7b23e34da..a4e84c7097c 100644 --- a/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/package.json +++ b/scripts/__tests__/integration/fixtures/lexical-esm-nextjs/package.json @@ -1,6 +1,6 @@ { "name": "lexical-esm-nextjs", - "version": "0.21.0", + "version": "0.23.1", "private": true, "scripts": { "dev": "next dev", @@ -9,9 +9,9 @@ "test": "playwright test" }, "dependencies": { - "@lexical/plain-text": "0.21.0", - "@lexical/react": "0.21.0", - "lexical": "0.21.0", + "@lexical/plain-text": "0.23.1", + "@lexical/react": "0.23.1", + "lexical": "0.23.1", "next": "^14.2.1", "react": "^18", "react-dom": "^18" diff --git a/scripts/__tests__/integration/fixtures/lexical-esm-sveltekit-vanilla-js/package.json b/scripts/__tests__/integration/fixtures/lexical-esm-sveltekit-vanilla-js/package.json index acb21924aa5..84df85c5073 100644 --- a/scripts/__tests__/integration/fixtures/lexical-esm-sveltekit-vanilla-js/package.json +++ b/scripts/__tests__/integration/fixtures/lexical-esm-sveltekit-vanilla-js/package.json @@ -1,6 +1,6 @@ { "name": "lexical-sveltekit-vanilla-js", - "version": "0.21.0", + "version": "0.23.1", "private": true, "scripts": { "dev": "vite dev", @@ -9,17 +9,17 @@ "test": "playwright test" }, "devDependencies": { - "@lexical/dragon": "0.21.0", - "@lexical/history": "0.21.0", - "@lexical/rich-text": "0.21.0", - "@lexical/utils": "0.21.0", + "@lexical/dragon": "0.23.1", + "@lexical/history": "0.23.1", + "@lexical/rich-text": "0.23.1", + "@lexical/utils": "0.23.1", "@playwright/test": "^1.28.1", "@sveltejs/adapter-auto": "^3.0.0", "@sveltejs/adapter-node": "^5.0.1", "@sveltejs/adapter-static": "^3.0.1", "@sveltejs/kit": "^2.10.1", "@sveltejs/vite-plugin-svelte": "^3.0.0", - "lexical": "0.21.0", + "lexical": "0.23.1", "prettier": "^3.1.1", "prettier-plugin-svelte": "^3.1.2", "svelte": "^4.2.19", diff --git a/scripts/build.js b/scripts/build.js index ec1b6c470f7..e92f9376e99 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -18,7 +18,6 @@ const commonjs = require('@rollup/plugin-commonjs'); const replace = require('@rollup/plugin-replace'); const json = require('@rollup/plugin-json'); const alias = require('@rollup/plugin-alias'); -const compiler = require('@ampproject/rollup-plugin-closure-compiler'); const terser = require('@rollup/plugin-terser'); const {exec} = require('child-process-promise'); const {packagesManager} = require('./shared/packagesManager'); @@ -34,19 +33,6 @@ const isRelease = argv.release; const isWWW = argv.www; const extractCodes = argv.codes; -const closureOptions = { - apply_input_source_maps: false, - assume_function_wrapper: true, - compilation_level: 'SIMPLE', - inject_libraries: false, - language_in: 'ECMASCRIPT_2019', - language_out: 'ECMASCRIPT_2019', - process_common_js_modules: false, - rewrite_polyfills: false, - use_types_for_optimization: false, - warning_level: 'QUIET', -}; - const modulePackageMappings = Object.fromEntries( packagesManager.getPublicPackages().flatMap((pkg) => { const pkgName = pkg.getNpmName(); @@ -254,13 +240,10 @@ async function build( isWWW && strictWWWMappings, ), ), - // terser is used for esm builds because - // @ampproject/rollup-plugin-closure-compiler doesn't compile - // `export default function X()` correctly - isProd && - (format === 'esm' - ? terser({ecma: 2019, module: true}) - : compiler(closureOptions)), + // terser is used because @ampproject/rollup-plugin-closure-compiler + // doesn't compile `export default function X()` correctly and hasn't + // been updated since Aug 2021 + isProd && terser({ecma: 2019, module: format === 'esm'}), { renderChunk(source) { // Assets pipeline might use "export" word in the beginning of the line @@ -370,7 +353,7 @@ function forkModuleContent( if (target === 'cjs') { lines.push( `'use strict'`, - `const ${outputFileName} = process.env.NODE_ENV === 'development' ? require('${devFileName}') : require('${prodFileName}');`, + `const ${outputFileName} = process.env.NODE_ENV !== 'production' ? require('${devFileName}') : require('${prodFileName}');`, `module.exports = ${outputFileName};`, ); } else { @@ -378,11 +361,11 @@ function forkModuleContent( lines.push( `import * as modDev from '${devFileName}';`, `import * as modProd from '${prodFileName}';`, - `const mod = process.env.NODE_ENV === 'development' ? modDev : modProd;`, + `const mod = process.env.NODE_ENV !== 'production' ? modDev : modProd;`, ); } else if (target === 'node') { lines.push( - `const mod = await (process.env.NODE_ENV === 'development' ? import('${devFileName}') : import('${prodFileName}'));`, + `const mod = await (process.env.NODE_ENV !== 'production' ? import('${devFileName}') : import('${prodFileName}'));`, ); } for (const name of exports) { diff --git a/scripts/error-codes/codes.json b/scripts/error-codes/codes.json index 384e63523bd..a0c547363c0 100644 --- a/scripts/error-codes/codes.json +++ b/scripts/error-codes/codes.json @@ -250,5 +250,13 @@ "248": "selectAdjacentCell: Row not in table", "249": "getCornerOrThrow: cell %s is not at a corner of rect", "250": "cellAtCornerOrThrow: %s = %s missing in tableMap", - "251": "$handleArrowKey: TableSelection.getNodes()[0] expected to be TableNode" + "251": "$handleArrowKey: TableSelection.getNodes()[0] expected to be TableNode", + "252": "$getPointNode: element point is not an ElementNode", + "253": "Expected TableSelection", + "254": "TablePlugin: Expecting all children of TableNode to be TableRowNode, found %s (type %s)", + "255": "TablePlugin: TableNode is not registered on editor", + "256": "insertAfterEndRow is not a TableRowNode", + "257": "insertBeforeStartRow is not a TableRowNode", + "258": "$childIterator: Cycle detected, node with key %s has already been traversed", + "259": "Point.getNode() must return ElementNode when type is element" } From 448e2af7796cebea6d0a710f48351cf44791fe77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 30 Jan 2025 12:27:05 -0300 Subject: [PATCH 03/25] first version with default value --- .eslintrc.js | 7 ++- packages/lexical/src/LexicalNode.ts | 61 +++++++++++++++---- .../src/__tests__/unit/LexicalNode.test.ts | 44 ++++++++++++- 3 files changed, 95 insertions(+), 17 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index c0cd4c5817e..d5d51c34779 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -88,7 +88,10 @@ module.exports = { ], '@typescript-eslint/ban-ts-comment': OFF, '@typescript-eslint/no-this-alias': OFF, - '@typescript-eslint/no-unused-vars': [ERROR, {args: 'none'}], + '@typescript-eslint/no-unused-vars': [ + ERROR, + {args: 'none', argsIgnorePattern: '^_', varsIgnorePattern: '^_'}, + ], 'header/header': [2, 'scripts/www/headerTemplate.js'], }, }, @@ -226,8 +229,6 @@ module.exports = { 'no-unused-expressions': ERROR, - 'no-unused-vars': [ERROR, {args: 'none'}], - 'no-use-before-define': OFF, // Flow fails with with non-string literal keys diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index 0a8ab879205..bebaa782780 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -187,6 +187,30 @@ export type NodeKey = string; export type State = {[Key in string]?: string | number | boolean | State}; +export interface StateKey { + key: K; + // Here we are storing a default for convenience + value: V; + parse: (value: unknown) => V; +} + +export interface StateKeyConfig { + /* possibly constrain V to ensure JSON serializability */ + parse: (value: unknown) => V; +} +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type StateKeyConfigValue> = ReturnType< + T['parse'] +>; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function createStateKey>( + key: K, + config: T, +): StateKey> { + return {key, parse: config.parse, value: config.parse(undefined)}; +} + export class LexicalNode { // Allow us to look up the type including static props ['constructor']!: KlassConstructor; @@ -204,21 +228,32 @@ export class LexicalNode { /** @internal */ __state: State = {}; - getState(key: keyof T): T[keyof T] | undefined { - const self = this.getLatest(); - return (self.__state as T)[key]; + // getState(key: keyof T): T[keyof T] | undefined { + // const self = this.getLatest(); + // return (self.__state as T)[key]; + // } + + getState(k: T): T['value'] | undefined { + return k.parse(/* implement state here */ undefined); } - setState( - key: keyof T, - value: T[keyof T] | undefined, - ) { - const self = this.getWritable(); - if (value === undefined) { - delete (self.__state as T)[key]; - return; - } - (self.__state as T)[key] = value; + // setState( + // key: keyof T, + // value: T[keyof T] | undefined, + // ) { + // const self = this.getWritable(); + // if (value === undefined) { + // delete (self.__state as T)[key]; + // return; + // } + // (self.__state as T)[key] = value; + // } + + setState(k: T, v: T['value']) { + const _self = this.getWritable(); + // self.__state[k.key] = v; + // (self.__state as T)[k.key] = v; + return this; } // Flow doesn't support abstract classes unfortunately, so we can't _force_ diff --git a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts index 3210f2ad5d1..fb51c0cef15 100644 --- a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts @@ -21,12 +21,13 @@ import { NodeKey, ParagraphNode, RangeSelection, + RootNode, SerializedLexicalNode, SerializedTextNode, TextNode, } from 'lexical'; -import {LexicalNode} from '../../LexicalNode'; +import {createStateKey, LexicalNode} from '../../LexicalNode'; import {$createParagraphNode} from '../../nodes/LexicalParagraphNode'; import {$createTextNode} from '../../nodes/LexicalTextNode'; import { @@ -36,6 +37,14 @@ import { TestInlineElementNode, } from '../utils'; +// https://www.totaltypescript.com/how-to-test-your-types +type Expect = T; +type Equal = (() => T extends X ? 1 : 2) extends () => T extends Y + ? 1 + : 2 + ? true + : false; + class TestNode extends LexicalNode { static getType(): string { return 'test'; @@ -1497,3 +1506,36 @@ describe('LexicalNode tests', () => { }, ); }); + +describe('LexicalNode state', () => { + initializeUnitTest( + (testEnv) => { + let root: RootNode; + + beforeEach(async () => { + const {editor} = testEnv; + await editor.update(() => { + root = $getRoot(); + }); + }); + + test(`createStateKey and getState don't need to be inside an update, setState does`, async () => { + const keyForString = createStateKey('keyForString', { + parse: (value) => value as string, + }); + const stringValue = root.getState(keyForString); + type _Test = Expect>; + expect(stringValue).toBeUndefined(); + const fn = () => { + root.setState(keyForString, 'hello'); + }; + expect(fn).toThrow(); + }); + }, + { + namespace: '', + nodes: [LexicalNode, TestNode], + theme: {}, + }, + ); +}); From bf701100a781c29b290f5d4c9cc43c61f2b86ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 30 Jan 2025 17:11:30 -0300 Subject: [PATCH 04/25] make state json serializable --- packages/lexical/src/LexicalNode.ts | 44 +++++-------------- .../src/__tests__/unit/LexicalNode.test.ts | 25 ++++++++--- 2 files changed, 30 insertions(+), 39 deletions(-) diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index bebaa782780..606416abe3d 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -185,23 +185,21 @@ export type DOMExportOutput = { export type NodeKey = string; -export type State = {[Key in string]?: string | number | boolean | State}; - -export interface StateKey { +type State = {[Key in string]?: string | number | boolean | State}; +type StateValue = string | number | boolean | State; +interface StateKey< + K extends string = string, + V extends StateValue = StateValue, +> { key: K; // Here we are storing a default for convenience value: V; parse: (value: unknown) => V; } - -export interface StateKeyConfig { - /* possibly constrain V to ensure JSON serializability */ +interface StateKeyConfig { parse: (value: unknown) => V; } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type StateKeyConfigValue> = ReturnType< - T['parse'] ->; +type StateKeyConfigValue = ReturnType; // eslint-disable-next-line @typescript-eslint/no-explicit-any export function createStateKey>( @@ -228,32 +226,14 @@ export class LexicalNode { /** @internal */ __state: State = {}; - // getState(key: keyof T): T[keyof T] | undefined { - // const self = this.getLatest(); - // return (self.__state as T)[key]; - // } - getState(k: T): T['value'] | undefined { - return k.parse(/* implement state here */ undefined); + const self = this.getLatest(); + return self.__state[k.key]; } - // setState( - // key: keyof T, - // value: T[keyof T] | undefined, - // ) { - // const self = this.getWritable(); - // if (value === undefined) { - // delete (self.__state as T)[key]; - // return; - // } - // (self.__state as T)[key] = value; - // } - setState(k: T, v: T['value']) { - const _self = this.getWritable(); - // self.__state[k.key] = v; - // (self.__state as T)[k.key] = v; - return this; + const self = this.getWritable(); + self.__state[k.key] = v; } // Flow doesn't support abstract classes unfortunately, so we can't _force_ diff --git a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts index fb51c0cef15..f49807fa3c9 100644 --- a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts @@ -1519,18 +1519,29 @@ describe('LexicalNode state', () => { }); }); - test(`createStateKey and getState don't need to be inside an update, setState does`, async () => { - const keyForString = createStateKey('keyForString', { - parse: (value) => value as string, - }); - const stringValue = root.getState(keyForString); - type _Test = Expect>; - expect(stringValue).toBeUndefined(); + test(`setState() need to be inside an update`, async () => { const fn = () => { + const keyForString = createStateKey('keyForString', { + parse: (value) => value as string, + }); root.setState(keyForString, 'hello'); }; expect(fn).toThrow(); }); + + test(`getState and setState`, async () => { + const keyForString = createStateKey('keyForString', { + parse: (value) => value as string, + }); + const {editor} = testEnv; + editor.update(() => { + const stringValue = root.getState(keyForString); + type _Test = Expect>; + expect(stringValue).toBeUndefined(); + root.setState(keyForString, 'hello'); + expect(root.getState(keyForString)).toBe('hello'); + }); + }); }, { namespace: '', From 6ebd4e5b569373628112d9a0bb6ec698503e74e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Thu, 30 Jan 2025 17:33:13 -0300 Subject: [PATCH 05/25] add import and export json tests --- packages/lexical/src/LexicalNode.ts | 1 + .../src/__tests__/unit/LexicalNode.test.ts | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index 606416abe3d..65b767d771b 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -972,6 +972,7 @@ export class LexicalNode { updateFromJSON( serializedNode: LexicalUpdateJSON, ): this { + this.__state = serializedNode.state || {}; return this; } diff --git a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts index f49807fa3c9..b1831588c47 100644 --- a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts @@ -1542,6 +1542,40 @@ describe('LexicalNode state', () => { expect(root.getState(keyForString)).toBe('hello'); }); }); + + test(`import and export state`, async () => { + const {editor} = testEnv; + editor.update(() => { + const paragraph = new ParagraphNode(); + const json = paragraph.exportJSON(); + // We don't export state as an empty object + expect(json).toStrictEqual({ + children: [], + direction: null, + format: '', + indent: 0, + textFormat: 0, + textStyle: '', + type: 'paragraph', + version: 1, + }); + const keyForNumber = createStateKey('keyForNumber', { + parse: (value) => value as number, + }); + paragraph.setState(keyForNumber, 1); + const json2 = paragraph.exportJSON(); + expect(json2).toStrictEqual({ + ...json, + state: { + keyForNumber: 1, + }, + }); + const paragraph2 = ParagraphNode.importJSON(json2); + expect(paragraph2.__state).toStrictEqual({ + keyForNumber: 1, + }); + }); + }); }, { namespace: '', From e46d7356d598a76eab7ae10cb7fdc71a57dffab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 31 Jan 2025 09:30:41 -0300 Subject: [PATCH 06/25] getState returns immutable types --- packages/lexical/src/LexicalNode.ts | 19 ++++- .../src/__tests__/unit/LexicalNode.test.ts | 74 +++++++++++++++---- 2 files changed, 74 insertions(+), 19 deletions(-) diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index 65b767d771b..bf657d981cc 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -185,6 +185,15 @@ export type DOMExportOutput = { export type NodeKey = string; +type DeepImmutable = T extends Map + ? ReadonlyMap, DeepImmutable> + : T extends Set + ? ReadonlySet> + : T extends object + ? { + readonly [K in keyof T]: DeepImmutable; + } + : T; type State = {[Key in string]?: string | number | boolean | State}; type StateValue = string | number | boolean | State; interface StateKey< @@ -193,7 +202,7 @@ interface StateKey< > { key: K; // Here we are storing a default for convenience - value: V; + value: DeepImmutable; parse: (value: unknown) => V; } interface StateKeyConfig { @@ -224,16 +233,17 @@ export class LexicalNode { /** @internal */ __next: null | NodeKey; /** @internal */ - __state: State = {}; + readonly __state: DeepImmutable = {}; getState(k: T): T['value'] | undefined { const self = this.getLatest(); - return self.__state[k.key]; + // If the state is not set, return the default value + return self.__state[k.key] ?? k.parse(undefined); } setState(k: T, v: T['value']) { const self = this.getWritable(); - self.__state[k.key] = v; + (self.__state as State)[k.key] = v; } // Flow doesn't support abstract classes unfortunately, so we can't _force_ @@ -972,6 +982,7 @@ export class LexicalNode { updateFromJSON( serializedNode: LexicalUpdateJSON, ): this { + // @ts-expect-error - only exception. this.__state = serializedNode.state || {}; return this; } diff --git a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts index b1831588c47..af16d17500b 100644 --- a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts @@ -1549,26 +1549,14 @@ describe('LexicalNode state', () => { const paragraph = new ParagraphNode(); const json = paragraph.exportJSON(); // We don't export state as an empty object - expect(json).toStrictEqual({ - children: [], - direction: null, - format: '', - indent: 0, - textFormat: 0, - textStyle: '', - type: 'paragraph', - version: 1, - }); + expect(json).not.toHaveProperty('state'); const keyForNumber = createStateKey('keyForNumber', { parse: (value) => value as number, }); paragraph.setState(keyForNumber, 1); const json2 = paragraph.exportJSON(); - expect(json2).toStrictEqual({ - ...json, - state: { - keyForNumber: 1, - }, + expect(json2.state).toStrictEqual({ + keyForNumber: 1, }); const paragraph2 = ParagraphNode.importJSON(json2); expect(paragraph2.__state).toStrictEqual({ @@ -1576,6 +1564,62 @@ describe('LexicalNode state', () => { }); }); }); + + test('default value should not be exported', async () => { + const {editor} = testEnv; + editor.update(() => { + const indentKey = createStateKey('indent', { + parse: (value) => (typeof value === 'number' ? value : 0), + }); + const paragraph = new ParagraphNode(); + expect(paragraph.getState(indentKey)).toBe(0); + const json = paragraph.exportJSON(); + expect(json).not.toHaveProperty('state'); + paragraph.setState(indentKey, 1); + const json2 = paragraph.exportJSON(); + expect(json2.state).toStrictEqual({ + indent: 1, + }); + // set the default value explicitly + paragraph.setState(indentKey, 0); + const json3 = paragraph.exportJSON(); + expect(json3.state).not.toHaveProperty('indent'); + }); + }); + + test('getState returns immutable values, setState require an Object literal', async () => { + type TestObject = { + foo: string; + bar: number; + }; + const {editor} = testEnv; + editor.update(() => { + const paragraph = new ParagraphNode(); + const objectKey = createStateKey('testObject', { + parse: (value) => value as TestObject, + }); + const paragraphObject = paragraph.getState(objectKey); + type _Test = Expect< + Equal< + typeof paragraphObject, + | { + readonly bar: number; + readonly foo: string; + } + | undefined + > + >; + expect(paragraphObject).toBeDefined(); + + // @ts-expect-error - foo is required + paragraph.setState(objectKey, {bar: 1}); + // @ts-expect-error - baz is not a valid property + paragraph.setState(objectKey, {bar: 1, baz: 'baz', foo: 'foo'}); + + paragraph.setState(objectKey, paragraphObject!); + paragraph.setState(objectKey, {...paragraphObject!, foo: 'foo'}); + }); + }); }, { namespace: '', From e404d320c58bfd5021b30863e5d88a5297b3ebce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 31 Jan 2025 10:15:25 -0300 Subject: [PATCH 07/25] fix tests --- .../src/__tests__/unit/LexicalTableSelection.test.tsx | 3 +++ .../lexical/src/__tests__/unit/LexicalEditor.test.tsx | 9 +++++++++ .../src/__tests__/unit/LexicalEditorState.test.ts | 4 ++++ packages/lexical/src/__tests__/unit/LexicalNode.test.ts | 8 ++++---- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx b/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx index dace11e3e0a..70dcdba725f 100644 --- a/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx +++ b/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx @@ -134,6 +134,7 @@ describe('table selection', () => { __parent: null, __prev: null, __size: 1, + __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -150,6 +151,7 @@ describe('table selection', () => { __parent: 'root', __prev: null, __size: 1, + __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -163,6 +165,7 @@ describe('table selection', () => { __next: null, __parent: paragraphKey, __prev: null, + __state: {}, __style: '', __text: 'Hello world', __type: 'text', diff --git a/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx b/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx index 5bfed2efef9..cfaa41012f3 100644 --- a/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx +++ b/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx @@ -1206,6 +1206,7 @@ describe('LexicalEditor tests', () => { __parent: null, __prev: null, __size: 1, + __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -1222,6 +1223,7 @@ describe('LexicalEditor tests', () => { __parent: 'root', __prev: null, __size: 0, + __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -1295,6 +1297,7 @@ describe('LexicalEditor tests', () => { __parent: null, __prev: null, __size: 1, + __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -1311,6 +1314,7 @@ describe('LexicalEditor tests', () => { __parent: 'root', __prev: null, __size: 1, + __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -1324,6 +1328,7 @@ describe('LexicalEditor tests', () => { __next: null, __parent: paragraphKey, __prev: null, + __state: {}, __style: '', __text: 'Hello world', __type: 'text', @@ -1379,6 +1384,7 @@ describe('LexicalEditor tests', () => { __parent: null, __prev: null, __size: 1, + __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -1395,6 +1401,7 @@ describe('LexicalEditor tests', () => { __parent: 'root', __prev: null, __size: 1, + __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -1408,6 +1415,7 @@ describe('LexicalEditor tests', () => { __next: null, __parent: paragraphKey, __prev: null, + __state: {}, __style: '', __text: 'Hello world', __type: 'text', @@ -2900,6 +2908,7 @@ describe('LexicalEditor tests', () => { __next: null, __parent: null, __prev: null, + __state: {}, __style: '', __text: 'yolo', __type: 'text', diff --git a/packages/lexical/src/__tests__/unit/LexicalEditorState.test.ts b/packages/lexical/src/__tests__/unit/LexicalEditorState.test.ts index 8e6e3a6eb00..bfe302d04f7 100644 --- a/packages/lexical/src/__tests__/unit/LexicalEditorState.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalEditorState.test.ts @@ -62,6 +62,7 @@ describe('LexicalEditorState tests', () => { __parent: null, __prev: null, __size: 1, + __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -78,6 +79,7 @@ describe('LexicalEditorState tests', () => { __parent: 'root', __prev: null, __size: 1, + __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -91,6 +93,7 @@ describe('LexicalEditorState tests', () => { __next: null, __parent: '1', __prev: null, + __state: {}, __style: '', __text: 'foo', __type: 'text', @@ -150,6 +153,7 @@ describe('LexicalEditorState tests', () => { __parent: null, __prev: null, __size: 0, + __state: {}, __style: '', __textFormat: 0, __textStyle: '', diff --git a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts index af16d17500b..17bf5bc7950 100644 --- a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts @@ -1580,10 +1580,11 @@ describe('LexicalNode state', () => { expect(json2.state).toStrictEqual({ indent: 1, }); + // TODO: How could exportJson know which stateKey maps to each key? // set the default value explicitly - paragraph.setState(indentKey, 0); - const json3 = paragraph.exportJSON(); - expect(json3.state).not.toHaveProperty('indent'); + // paragraph.setState(indentKey, 0); + // const json3 = paragraph.exportJSON(); + // expect(json3.state).not.toHaveProperty('indent'); }); }); @@ -1609,7 +1610,6 @@ describe('LexicalNode state', () => { | undefined > >; - expect(paragraphObject).toBeDefined(); // @ts-expect-error - foo is required paragraph.setState(objectKey, {bar: 1}); From 6d00c64c74a79a840e6b1c417edf78eb885d417b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 31 Jan 2025 11:33:28 -0300 Subject: [PATCH 08/25] add docs --- .../docs/concepts/node-replacement.md | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/lexical-website/docs/concepts/node-replacement.md b/packages/lexical-website/docs/concepts/node-replacement.md index 1aafbc50595..af163844a46 100644 --- a/packages/lexical-website/docs/concepts/node-replacement.md +++ b/packages/lexical-website/docs/concepts/node-replacement.md @@ -1,4 +1,41 @@ +# Node Customization +Originally the only way to customize nodes was using the node replacement API. Recently we have introduced a second way with the `state` property which has some advantages described below. + +## State (New) + +The advantages of using state over the replacement API are: +1. Easier (less boilerplate) +2. Composable (multiple plugins extending the same node causes failures) +3. Allows metadata: useful for adding things to the RootNode. + +All you need to do is define keys with `createStateKey`, and then use it with the `setState` and `getState` methods. + +```ts +// IMPLEMENTATION +const color = createStateKey('color', { parse: (value) => value as string }); + +// USAGE +const textNode = new TextNode(); +textNode.setState(color, "blue"); +const textColor = textNode.getState(color) // -> "blue" +``` + +Important: we recommend that you use prefixes with low collision probability when defining state keys. For example, if you are making a plugin called `awesome-lexical`, you could do: + +```ts +const color = createStateKey('awesome-lexical-color', /** your parse fn */) +const bgColor = createStateKey('awesome-lexical-bg-color', /** your parse fn */) + +// Or you can add all your state inside an object: +type AwesomeLexical = { + color?: string; + bgColor?: string; + padding?: number +} +const awesomeLexical = createStateKey('awesome-lexical', /** your parse fn which returns AwesomeLexical type */) + +``` # Node Overrides / Node Replacements @@ -6,7 +43,7 @@ Some of the most commonly used Lexical Nodes are owned and maintained by the cor Node Overrides allow you to replace all instances of a given node in your editor with instances of a different node class. This can be done through the nodes array in the Editor config: -``` +```ts const editorConfig = { ... nodes=[ From e0c59457213dd8e0c88ebfa62267fa3e68020ef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 31 Jan 2025 12:01:09 -0300 Subject: [PATCH 09/25] remove readonly property --- packages/lexical/src/LexicalNode.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index bf657d981cc..feecb343276 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -233,7 +233,7 @@ export class LexicalNode { /** @internal */ __next: null | NodeKey; /** @internal */ - readonly __state: DeepImmutable = {}; + __state: DeepImmutable = {}; getState(k: T): T['value'] | undefined { const self = this.getLatest(); @@ -982,7 +982,6 @@ export class LexicalNode { updateFromJSON( serializedNode: LexicalUpdateJSON, ): this { - // @ts-expect-error - only exception. this.__state = serializedNode.state || {}; return this; } From 7728780f092645dd2c334c73141639609967cd80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 31 Jan 2025 12:07:50 -0300 Subject: [PATCH 10/25] add paragraph in docs about json serializable values --- packages/lexical-website/docs/concepts/node-replacement.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/lexical-website/docs/concepts/node-replacement.md b/packages/lexical-website/docs/concepts/node-replacement.md index af163844a46..bd162ee7750 100644 --- a/packages/lexical-website/docs/concepts/node-replacement.md +++ b/packages/lexical-website/docs/concepts/node-replacement.md @@ -21,7 +21,11 @@ textNode.setState(color, "blue"); const textColor = textNode.getState(color) // -> "blue" ``` -Important: we recommend that you use prefixes with low collision probability when defining state keys. For example, if you are making a plugin called `awesome-lexical`, you could do: +Inside state, you can put any serializable json value except null. Our recommendation is to always use TypeScript in strict mode, so you don't have to worry about these things! + +### Important + +we recommend that you use prefixes with low collision probability when defining state keys. For example, if you are making a plugin called `awesome-lexical`, you could do: ```ts const color = createStateKey('awesome-lexical-color', /** your parse fn */) From d807d4fb5a112111c0af0e6d27c9fdf8403c65f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 31 Jan 2025 13:30:40 -0300 Subject: [PATCH 11/25] better example in docs. getState does not necessarily return undefined. --- .../docs/concepts/node-replacement.md | 4 +++- packages/lexical/src/LexicalNode.ts | 4 ++-- .../src/__tests__/unit/LexicalNode.test.ts | 17 ++++++++++++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/lexical-website/docs/concepts/node-replacement.md b/packages/lexical-website/docs/concepts/node-replacement.md index bd162ee7750..621fbadcf38 100644 --- a/packages/lexical-website/docs/concepts/node-replacement.md +++ b/packages/lexical-website/docs/concepts/node-replacement.md @@ -13,7 +13,9 @@ All you need to do is define keys with `createStateKey`, and then use it with th ```ts // IMPLEMENTATION -const color = createStateKey('color', { parse: (value) => value as string }); +const color = createStateKey('color', { + parse: (value: unknown) => (typeof value === 'string' ? value : undefined), +}); // USAGE const textNode = new TextNode(); diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index feecb343276..ed259c9440c 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -195,7 +195,7 @@ type DeepImmutable = T extends Map } : T; type State = {[Key in string]?: string | number | boolean | State}; -type StateValue = string | number | boolean | State; +type StateValue = string | number | boolean | undefined | State; interface StateKey< K extends string = string, V extends StateValue = StateValue, @@ -235,7 +235,7 @@ export class LexicalNode { /** @internal */ __state: DeepImmutable = {}; - getState(k: T): T['value'] | undefined { + getState(k: T): T['value'] { const self = this.getLatest(); // If the state is not set, return the default value return self.__state[k.key] ?? k.parse(undefined); diff --git a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts index 17bf5bc7950..466538c9712 100644 --- a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts @@ -1536,10 +1536,25 @@ describe('LexicalNode state', () => { const {editor} = testEnv; editor.update(() => { const stringValue = root.getState(keyForString); - type _Test = Expect>; + type _Test = Expect>; expect(stringValue).toBeUndefined(); root.setState(keyForString, 'hello'); expect(root.getState(keyForString)).toBe('hello'); + + const keyForMaybeString = createStateKey('keyForMaybeString', { + parse: (value) => value as string | undefined, + }); + const maybeStringValue = root.getState(keyForMaybeString); + type _Test2 = Expect< + Equal + >; + expect(maybeStringValue).toBeUndefined(); + + const keyForMaybeNull = createStateKey('keyForMaybeNull', { + parse: (value) => value as string | null, + }); + // @ts-expect-error - null is not a valid value + const _maybeNullValue = root.getState(keyForMaybeNull); }); }); From 90a032bf71f0b9b5fa8286be0409edb5837efd54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 31 Jan 2025 13:31:59 -0300 Subject: [PATCH 12/25] use $createTextNode() --- packages/lexical-website/docs/concepts/node-replacement.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lexical-website/docs/concepts/node-replacement.md b/packages/lexical-website/docs/concepts/node-replacement.md index 621fbadcf38..1eefe748e0a 100644 --- a/packages/lexical-website/docs/concepts/node-replacement.md +++ b/packages/lexical-website/docs/concepts/node-replacement.md @@ -18,7 +18,7 @@ const color = createStateKey('color', { }); // USAGE -const textNode = new TextNode(); +const textNode = $createTextNode(); textNode.setState(color, "blue"); const textColor = textNode.getState(color) // -> "blue" ``` From c663540f39eaa0173a6466954cd436ca2aed9d7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 31 Jan 2025 13:33:59 -0300 Subject: [PATCH 13/25] fix type --- packages/lexical/src/LexicalNode.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index ed259c9440c..f3239c5b74b 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -932,7 +932,7 @@ export class LexicalNode { return { type: this.__type, version: 1, - ...(objetcIsEmpty(this.__state) ? {} : {state: this.__state}), + ...(objectIsEmpty(this.__state) ? {} : {state: this.__state}), }; } @@ -1343,7 +1343,7 @@ export function insertRangeAfter( * The best way to check if an object is empty in O(1) * @see https://stackoverflow.com/a/59787784/10476393 */ -function objetcIsEmpty(obj: object) { +function objectIsEmpty(obj: object) { for (const key in obj) { return false; } From 113a4f1728b8fa04f521e45043fde350b4dbbe0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 31 Jan 2025 14:29:36 -0300 Subject: [PATCH 14/25] create a new object in setState --- packages/lexical/src/LexicalNode.ts | 3 ++- packages/lexical/src/__tests__/unit/LexicalNode.test.ts | 9 ++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index f3239c5b74b..30b9be1e441 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -243,7 +243,7 @@ export class LexicalNode { setState(k: T, v: T['value']) { const self = this.getWritable(); - (self.__state as State)[k.key] = v; + self.__state = {...self.__state, [k.key]: v}; } // Flow doesn't support abstract classes unfortunately, so we can't _force_ @@ -333,6 +333,7 @@ export class LexicalNode { this.__parent = prevNode.__parent; this.__next = prevNode.__next; this.__prev = prevNode.__prev; + this.__state = prevNode.__state || {}; } // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts index 466538c9712..43ad84a40cf 100644 --- a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts @@ -1618,11 +1618,10 @@ describe('LexicalNode state', () => { type _Test = Expect< Equal< typeof paragraphObject, - | { - readonly bar: number; - readonly foo: string; - } - | undefined + { + readonly bar: number; + readonly foo: string; + } > >; From 91148f3bd8adcb376fe2491c9766f1ef09c4cece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 31 Jan 2025 14:41:34 -0300 Subject: [PATCH 15/25] fix unit test --- .../lexical/src/__tests__/unit/LexicalNode.test.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts index 43ad84a40cf..89d2a73b583 100644 --- a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts @@ -1550,11 +1550,15 @@ describe('LexicalNode state', () => { >; expect(maybeStringValue).toBeUndefined(); - const keyForMaybeNull = createStateKey('keyForMaybeNull', { + // TO-DO: + // It would be a bit nicer if createStateKey also gave a compilation error if parse tried to return null. + // It's not a big deal, because getState does give an error. The problem is that I can't activate it. + // The @expect-error does not work because strict mode is disabled in `tsconfig.test.json`. + const _keyForMaybeNull = createStateKey('keyForMaybeNull', { parse: (value) => value as string | null, }); - // @ts-expect-error - null is not a valid value - const _maybeNullValue = root.getState(keyForMaybeNull); + // // @ts-expect-error - null is not a valid value + // const _maybeNullValue = root.getState(keyForMaybeNull); }); }); From 47435b0fe8527983c0f42d52d60f7fe741e16bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 31 Jan 2025 15:45:03 -0300 Subject: [PATCH 16/25] Update packages/lexical/src/LexicalNode.ts Co-authored-by: Bob Ippolito --- packages/lexical/src/LexicalNode.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index 30b9be1e441..c51fe4f55b4 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -241,9 +241,10 @@ export class LexicalNode { return self.__state[k.key] ?? k.parse(undefined); } - setState(k: T, v: T['value']) { + setState(k: T, v: T['value']): this { const self = this.getWritable(); self.__state = {...self.__state, [k.key]: v}; + return self; } // Flow doesn't support abstract classes unfortunately, so we can't _force_ From fb7e1649e41da82fb5f4b9bdc10d0f3ea38fa684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 31 Jan 2025 15:45:20 -0300 Subject: [PATCH 17/25] Update packages/lexical/src/LexicalNode.ts Co-authored-by: Bob Ippolito --- packages/lexical/src/LexicalNode.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index c51fe4f55b4..3d2bb00ecc5 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -238,7 +238,7 @@ export class LexicalNode { getState(k: T): T['value'] { const self = this.getLatest(); // If the state is not set, return the default value - return self.__state[k.key] ?? k.parse(undefined); + return k.parse(self.__state[k.key]); } setState(k: T, v: T['value']): this { From eab152e7c6836960050d3dff8d085254558374af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 31 Jan 2025 15:53:48 -0300 Subject: [PATCH 18/25] Update packages/lexical/src/LexicalNode.ts Co-authored-by: Bob Ippolito --- packages/lexical/src/LexicalNode.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index 3d2bb00ecc5..a0975dbaa4c 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -200,10 +200,10 @@ interface StateKey< K extends string = string, V extends StateValue = StateValue, > { - key: K; + readonly key: K; // Here we are storing a default for convenience - value: DeepImmutable; - parse: (value: unknown) => V; + readonly value: DeepImmutable; + readonly parse: (value: unknown) => V; } interface StateKeyConfig { parse: (value: unknown) => V; From d2b4f21d3ead1bb4a7e1ea299731db7f21c5b28e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 31 Jan 2025 15:54:01 -0300 Subject: [PATCH 19/25] Update packages/lexical/src/LexicalNode.ts Co-authored-by: Bob Ippolito --- packages/lexical/src/LexicalNode.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index a0975dbaa4c..1940b161781 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -206,7 +206,7 @@ interface StateKey< readonly parse: (value: unknown) => V; } interface StateKeyConfig { - parse: (value: unknown) => V; + readonly parse: (value: unknown) => V; } type StateKeyConfigValue = ReturnType; From 2bc4a0eebfc6f8cdc1a66d3d1322e82b9bd987d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Mon, 3 Feb 2025 10:36:43 -0300 Subject: [PATCH 20/25] add null to State type, fix parse function in test --- packages/lexical/src/LexicalNode.ts | 4 ++-- .../src/__tests__/unit/LexicalNode.test.ts | 17 ++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index 1940b161781..e2b8ac58e1c 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -194,8 +194,8 @@ type DeepImmutable = T extends Map readonly [K in keyof T]: DeepImmutable; } : T; -type State = {[Key in string]?: string | number | boolean | State}; -type StateValue = string | number | boolean | undefined | State; +type State = {[Key in string]?: string | number | null | boolean | State}; +type StateValue = string | number | boolean | null | undefined | State; interface StateKey< K extends string = string, V extends StateValue = StateValue, diff --git a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts index 89d2a73b583..6986795b272 100644 --- a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts @@ -1531,13 +1531,13 @@ describe('LexicalNode state', () => { test(`getState and setState`, async () => { const keyForString = createStateKey('keyForString', { - parse: (value) => value as string, + parse: (value) => (value as string) || '', }); const {editor} = testEnv; editor.update(() => { const stringValue = root.getState(keyForString); type _Test = Expect>; - expect(stringValue).toBeUndefined(); + expect(stringValue).toBe(''); root.setState(keyForString, 'hello'); expect(root.getState(keyForString)).toBe('hello'); @@ -1551,14 +1551,13 @@ describe('LexicalNode state', () => { expect(maybeStringValue).toBeUndefined(); // TO-DO: - // It would be a bit nicer if createStateKey also gave a compilation error if parse tried to return null. - // It's not a big deal, because getState does give an error. The problem is that I can't activate it. - // The @expect-error does not work because strict mode is disabled in `tsconfig.test.json`. - const _keyForMaybeNull = createStateKey('keyForMaybeNull', { - parse: (value) => value as string | null, + // It would be a bit nicer if createStateKey also gave a compilation error. + // It's not a big deal, because getState will indeed throw the error at compile time. + const keyForNoSerializable = createStateKey('keyForNoSerializable', { + parse: () => new Date(), }); - // // @ts-expect-error - null is not a valid value - // const _maybeNullValue = root.getState(keyForMaybeNull); + // @ts-expect-error - null is not a valid value + const _noSerializableValue = root.getState(keyForNoSerializable); }); }); From fca2071997080c59a9912d1e7db7a7133d90d4b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Mon, 3 Feb 2025 11:00:20 -0300 Subject: [PATCH 21/25] add Bob's test about previous reconciled versions of the node --- .../src/__tests__/unit/LexicalNode.test.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts index 6986795b272..964f25802bf 100644 --- a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts @@ -1637,6 +1637,42 @@ describe('LexicalNode state', () => { paragraph.setState(objectKey, {...paragraphObject!, foo: 'foo'}); }); }); + + test('setting state shouldn’t affect previous reconciled versions of the node', () => { + const {editor} = testEnv; + let v0: RootNode; + let v1: RootNode; + const vk = createStateKey('vk', { + parse: (v) => (typeof v === 'number' ? v : null), + }); + editor.update( + () => { + v0 = $getRoot(); + v0.setState(vk, 0); + expect(v0.getState(vk)).toBe(0); + }, + {discrete: true}, + ); + const state0 = editor.getEditorState(); + editor.update( + () => { + v0.setState(vk, 1); + v1 = v0.getLatest(); + // This is testing getLatest() + expect(v0.getState(vk)).toBe(1); + expect(v1.getState(vk)).toBe(1); + expect(v1.is(v0)).toBe(true); + }, + {discrete: true}, + ); + const state1 = editor.getEditorState(); + // Test that the correct version is returned and that they are independent + expect(state0.read(() => v0.getState(vk))).toBe(0); + expect(state1.read(() => v1.getState(vk))).toBe(1); + // Test that getLatest is used and not the __state property directly + expect(state0.read(() => v1.getState(vk))).toBe(0); + expect(state1.read(() => v0.getState(vk))).toBe(1); + }); }, { namespace: '', From 8cf6855bae606f46fe612ed66b57fef57f35207c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Mon, 3 Feb 2025 11:38:48 -0300 Subject: [PATCH 22/25] improve parse functions in tests again --- .../lexical/src/__tests__/unit/LexicalNode.test.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts index 964f25802bf..94b84975a31 100644 --- a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts @@ -1522,7 +1522,7 @@ describe('LexicalNode state', () => { test(`setState() need to be inside an update`, async () => { const fn = () => { const keyForString = createStateKey('keyForString', { - parse: (value) => value as string, + parse: (value) => (typeof value === 'string' ? value : ''), }); root.setState(keyForString, 'hello'); }; @@ -1531,7 +1531,7 @@ describe('LexicalNode state', () => { test(`getState and setState`, async () => { const keyForString = createStateKey('keyForString', { - parse: (value) => (value as string) || '', + parse: (value) => (typeof value === 'string' ? value : ''), }); const {editor} = testEnv; editor.update(() => { @@ -1542,7 +1542,7 @@ describe('LexicalNode state', () => { expect(root.getState(keyForString)).toBe('hello'); const keyForMaybeString = createStateKey('keyForMaybeString', { - parse: (value) => value as string | undefined, + parse: (value) => (typeof value === 'string' ? value : undefined), }); const maybeStringValue = root.getState(keyForMaybeString); type _Test2 = Expect< @@ -1569,7 +1569,7 @@ describe('LexicalNode state', () => { // We don't export state as an empty object expect(json).not.toHaveProperty('state'); const keyForNumber = createStateKey('keyForNumber', { - parse: (value) => value as number, + parse: (value) => (typeof value === 'number' ? value : 0), }); paragraph.setState(keyForNumber, 1); const json2 = paragraph.exportJSON(); @@ -1615,7 +1615,11 @@ describe('LexicalNode state', () => { editor.update(() => { const paragraph = new ParagraphNode(); const objectKey = createStateKey('testObject', { - parse: (value) => value as TestObject, + parse: (value) => + (value as TestObject) || { + bar: 0, + foo: '', + }, }); const paragraphObject = paragraph.getState(objectKey); type _Test = Expect< From abd3d3e826172b55783c96d235ae2c67aa64ffd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:41:00 -0300 Subject: [PATCH 23/25] add stateStore to register state keys --- packages/lexical/src/LexicalNode.ts | 23 +++++++++++++++- .../src/__tests__/unit/LexicalNode.test.ts | 26 ++++++++++++++++--- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index e2b8ac58e1c..9ab22bc9eee 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -210,11 +210,19 @@ interface StateKeyConfig { } type StateKeyConfigValue = ReturnType; +const stateStore = new Map(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any export function createStateKey>( key: K, config: T, ): StateKey> { + if (stateStore.has(key)) { + throw new Error( + `There has been an attempt to register a state with the key "${key}", but it is already registered.`, + ); + } + stateStore.set(key, config); return {key, parse: config.parse, value: config.parse(undefined)}; } @@ -931,10 +939,23 @@ export class LexicalNode { * * */ exportJSON(): SerializedLexicalNode { + const state: State = {}; + Object.entries(this.__state).forEach(([key, value]) => { + const config = stateStore.get(key); + if (!config) { + throw new Error( + `There has been an attempt to export a state with the key "${key}", but it is not registered.`, + ); + } + // We don't export state if it's the default value + if (value !== config.parse(undefined)) { + state[key] = value; + } + }); return { type: this.__type, version: 1, - ...(objectIsEmpty(this.__state) ? {} : {state: this.__state}), + ...(objectIsEmpty(state) ? {} : {state}), }; } diff --git a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts index 94b84975a31..878ac85e7ca 100644 --- a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts @@ -1583,6 +1583,15 @@ describe('LexicalNode state', () => { }); }); + test('states cannot be registered with the same key string', () => { + expect(() => { + createStateKey('foo', {parse: (value) => undefined}); + createStateKey('foo', {parse: (value) => 0}); + }).toThrow( + `There has been an attempt to register a state with the key "foo", but it is already registered.`, + ); + }); + test('default value should not be exported', async () => { const {editor} = testEnv; editor.update(() => { @@ -1598,11 +1607,20 @@ describe('LexicalNode state', () => { expect(json2.state).toStrictEqual({ indent: 1, }); - // TODO: How could exportJson know which stateKey maps to each key? // set the default value explicitly - // paragraph.setState(indentKey, 0); - // const json3 = paragraph.exportJSON(); - // expect(json3.state).not.toHaveProperty('indent'); + paragraph.setState(indentKey, 0); + const json3 = paragraph.exportJSON(); + expect(json3).not.toHaveProperty('state'); + + // TO-DISCUSS: There has been an attempt to register a state with the key "foo", but it is already registered. + // const foo = createStateKey('foo', { + // parse: (value) => (typeof value === 'string' ? value : ''), + // }); + // paragraph.setState(foo, 'foo'); + // const json4 = paragraph.exportJSON(); + // expect(json4.state).toStrictEqual({ + // foo: 'foo', + // }); }); }); From 3f8bba0e80a7665aec9a648f7db033f57cbc6c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 7 Feb 2025 17:51:43 -0300 Subject: [PATCH 24/25] BIG CHANGE - state as class --- .../unit/LexicalTableSelection.test.tsx | 3 - packages/lexical/src/LexicalNode.ts | 98 +++----- packages/lexical/src/LexicalNodeState.ts | 131 ++++++++++ .../src/__tests__/unit/LexicalEditor.test.tsx | 9 - .../__tests__/unit/LexicalEditorState.test.ts | 4 - .../src/__tests__/unit/LexicalNode.test.ts | 210 +--------------- .../__tests__/unit/LexicalNodeState.test.ts | 225 ++++++++++++++++++ 7 files changed, 390 insertions(+), 290 deletions(-) create mode 100644 packages/lexical/src/LexicalNodeState.ts create mode 100644 packages/lexical/src/__tests__/unit/LexicalNodeState.test.ts diff --git a/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx b/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx index 70dcdba725f..dace11e3e0a 100644 --- a/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx +++ b/packages/lexical-table/src/__tests__/unit/LexicalTableSelection.test.tsx @@ -134,7 +134,6 @@ describe('table selection', () => { __parent: null, __prev: null, __size: 1, - __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -151,7 +150,6 @@ describe('table selection', () => { __parent: 'root', __prev: null, __size: 1, - __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -165,7 +163,6 @@ describe('table selection', () => { __next: null, __parent: paragraphKey, __prev: null, - __state: {}, __style: '', __text: 'Hello world', __type: 'text', diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index 9ab22bc9eee..5c6ae55a4d8 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -22,6 +22,7 @@ import { type DecoratorNode, ElementNode, } from '.'; +import {NodeState, State} from './LexicalNodeState'; import { $getSelection, $isNodeSelection, @@ -185,47 +186,6 @@ export type DOMExportOutput = { export type NodeKey = string; -type DeepImmutable = T extends Map - ? ReadonlyMap, DeepImmutable> - : T extends Set - ? ReadonlySet> - : T extends object - ? { - readonly [K in keyof T]: DeepImmutable; - } - : T; -type State = {[Key in string]?: string | number | null | boolean | State}; -type StateValue = string | number | boolean | null | undefined | State; -interface StateKey< - K extends string = string, - V extends StateValue = StateValue, -> { - readonly key: K; - // Here we are storing a default for convenience - readonly value: DeepImmutable; - readonly parse: (value: unknown) => V; -} -interface StateKeyConfig { - readonly parse: (value: unknown) => V; -} -type StateKeyConfigValue = ReturnType; - -const stateStore = new Map(); - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function createStateKey>( - key: K, - config: T, -): StateKey> { - if (stateStore.has(key)) { - throw new Error( - `There has been an attempt to register a state with the key "${key}", but it is already registered.`, - ); - } - stateStore.set(key, config); - return {key, parse: config.parse, value: config.parse(undefined)}; -} - export class LexicalNode { // Allow us to look up the type including static props ['constructor']!: KlassConstructor; @@ -240,21 +200,31 @@ export class LexicalNode { __prev: null | NodeKey; /** @internal */ __next: null | NodeKey; - /** @internal */ - __state: DeepImmutable = {}; - getState(k: T): T['value'] { - const self = this.getLatest(); - // If the state is not set, return the default value - return k.parse(self.__state[k.key]); + /** @internal */ + get __state() { + // @ts-expect-error + return this._state; } - setState(k: T, v: T['value']): this { - const self = this.getWritable(); - self.__state = {...self.__state, [k.key]: v}; - return self; + /** @internal */ + set __state(value: NodeState) { + // @ts-expect-error + this._state = value; } + // getState(k: T): T['value'] { + // const self = this.getLatest(); + // // If the state is not set, return the default value + // return k.parse(self.__state[k.key]); + // } + + // setState(k: T, v: T['value']): this { + // const self = this.getWritable(); + // self.__state = {...self.__state, [k.key]: v}; + // return self; + // } + // Flow doesn't support abstract classes unfortunately, so we can't _force_ // subclasses of Node to implement statics. All subclasses of Node should have // a static getType and clone method though. We define getType and clone here so we can call it @@ -342,7 +312,7 @@ export class LexicalNode { this.__parent = prevNode.__parent; this.__next = prevNode.__next; this.__prev = prevNode.__prev; - this.__state = prevNode.__state || {}; + this.__state = prevNode.__state || new NodeState(); } // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -354,6 +324,12 @@ export class LexicalNode { this.__prev = null; this.__next = null; $setNodeKey(this, key); + Object.defineProperty(this, '_state', { + configurable: true, + enumerable: false, + value: new NodeState(), + writable: true, + }); if (__DEV__) { if (this.__type !== 'root') { @@ -939,19 +915,8 @@ export class LexicalNode { * * */ exportJSON(): SerializedLexicalNode { - const state: State = {}; - Object.entries(this.__state).forEach(([key, value]) => { - const config = stateStore.get(key); - if (!config) { - throw new Error( - `There has been an attempt to export a state with the key "${key}", but it is not registered.`, - ); - } - // We don't export state if it's the default value - if (value !== config.parse(undefined)) { - state[key] = value; - } - }); + // eslint-disable-next-line dot-notation + const state = this.__state['toJSON'](); return { type: this.__type, version: 1, @@ -1005,7 +970,8 @@ export class LexicalNode { updateFromJSON( serializedNode: LexicalUpdateJSON, ): this { - this.__state = serializedNode.state || {}; + // eslint-disable-next-line dot-notation + this.__state['unknownState'] = serializedNode.state || {}; return this; } diff --git a/packages/lexical/src/LexicalNodeState.ts b/packages/lexical/src/LexicalNodeState.ts new file mode 100644 index 00000000000..967f2ef6661 --- /dev/null +++ b/packages/lexical/src/LexicalNodeState.ts @@ -0,0 +1,131 @@ +/** + * 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. + * + */ +/* eslint-disable dot-notation */ + +import {LexicalNode} from './LexicalNode'; + +/** + * NOTE: we parse in getState and setState, but not in importJSON or exportJSON. Ideally, + * the normal thing would be the other way around. The reason we do it this way is because + * we don't have a composable way to declare states (or plugins), prior to creating the + * editor. Maybe later with something like https://lexical-builder.pages.dev/. + */ + +export type DeepImmutable = T extends Map + ? ReadonlyMap, DeepImmutable> + : T extends Set + ? ReadonlySet> + : T extends object + ? { + readonly [K in keyof T]: DeepImmutable; + } + : T; + +export type State = { + [Key in string]?: string | number | boolean | null | undefined | State; +}; + +type StateValue = string | number | boolean | null | undefined | State; + +export function createState( + key: K, + config: {parse: (value: unknown) => T}, +) { + // We create a stateConfig with a default value to save some work later + const stateConfig = { + defaultValue: config.parse(undefined), + key, + parse: config.parse, + }; + + const $get = (node: LexicalNode): DeepImmutable => { + // 1. We first try to get the value from the knownState + const state = node.getLatest().__state; + const value = state['knownState'].get(stateConfig) as DeepImmutable; + if (value !== undefined) { + return value; + } + + // 2. If the value is not in the knownState, we try to get it from the unknownState + // and set it in the knownState Map (even if it's a default, so we don't parse again). + const unknownValue = state['unknownState'][key]; + delete state['unknownState'][key]; + const parsedValue = config.parse(unknownValue) as DeepImmutable; + state['knownState'].set(stateConfig, parsedValue); + + // We check collisions (the same string key used on the same node instance in 2 different `createState`) + // We could use a reverse map to avoid a lookup (Map), but it seems overkill. + state['knownState'].forEach((_, currentStateConfig) => { + if ( + currentStateConfig.key === key && + currentStateConfig !== stateConfig + ) { + throw new Error(`State key collision detected: ${key}`); + } + }); + + return parsedValue; + }; + + const $set = (node: LexicalNode, value: T) => { + const self = node.getWritable(); + self.__state = self.__state['clone'](); + const parsedValue = config.parse(value); + delete self.__state['unknownState'][key]; + self.__state['knownState'].set(stateConfig, parsedValue); + }; + + return {$get, $set}; +} + +interface StateConfig< + K extends string = string, + V extends StateValue = StateValue, +> { + readonly key: K; + readonly defaultValue: DeepImmutable; + readonly parse: (value: unknown) => V; +} + +export class NodeState { + /** + * State that has already been parsed in a get state, so it is safe. (can be returned with + * just a cast since the proof was given before). + * + * Note that it uses StateConfig, so in addition to (1) the CURRENT VALUE, it has access to + * (2) the State key (3) the DEFAULT VALUE and (4) the PARSE FUNCTION + */ + private knownState: Map = new Map(); + + /** + * It is a copy of serializedNode.state that is made when JSON is imported but has not been parsed yet. + * It stays here until a get state requires us to parse it, and since we then know the value is safe we move it to knownState + * + * note that it uses string as keys instead of StateConfig so it has no way to parse at export time. + * In exportJSON, we only parse knownState to save the default value which is not exported. + * For safety, we parse unknownState in get state. + */ + private unknownState: Record = {}; + + private toJSON(): State { + const state = {...this.unknownState}; + this.knownState.forEach((stateValue, stateConfig) => { + if (stateValue !== stateConfig.defaultValue) { + state[stateConfig.key] = stateConfig.parse(stateValue); + } + }); + return state as State; + } + + private clone() { + const newState = new NodeState(); + newState.unknownState = {...this.unknownState}; + newState.knownState = new Map(this.knownState); + return newState; + } +} diff --git a/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx b/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx index cfaa41012f3..5bfed2efef9 100644 --- a/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx +++ b/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx @@ -1206,7 +1206,6 @@ describe('LexicalEditor tests', () => { __parent: null, __prev: null, __size: 1, - __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -1223,7 +1222,6 @@ describe('LexicalEditor tests', () => { __parent: 'root', __prev: null, __size: 0, - __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -1297,7 +1295,6 @@ describe('LexicalEditor tests', () => { __parent: null, __prev: null, __size: 1, - __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -1314,7 +1311,6 @@ describe('LexicalEditor tests', () => { __parent: 'root', __prev: null, __size: 1, - __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -1328,7 +1324,6 @@ describe('LexicalEditor tests', () => { __next: null, __parent: paragraphKey, __prev: null, - __state: {}, __style: '', __text: 'Hello world', __type: 'text', @@ -1384,7 +1379,6 @@ describe('LexicalEditor tests', () => { __parent: null, __prev: null, __size: 1, - __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -1401,7 +1395,6 @@ describe('LexicalEditor tests', () => { __parent: 'root', __prev: null, __size: 1, - __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -1415,7 +1408,6 @@ describe('LexicalEditor tests', () => { __next: null, __parent: paragraphKey, __prev: null, - __state: {}, __style: '', __text: 'Hello world', __type: 'text', @@ -2908,7 +2900,6 @@ describe('LexicalEditor tests', () => { __next: null, __parent: null, __prev: null, - __state: {}, __style: '', __text: 'yolo', __type: 'text', diff --git a/packages/lexical/src/__tests__/unit/LexicalEditorState.test.ts b/packages/lexical/src/__tests__/unit/LexicalEditorState.test.ts index bfe302d04f7..8e6e3a6eb00 100644 --- a/packages/lexical/src/__tests__/unit/LexicalEditorState.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalEditorState.test.ts @@ -62,7 +62,6 @@ describe('LexicalEditorState tests', () => { __parent: null, __prev: null, __size: 1, - __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -79,7 +78,6 @@ describe('LexicalEditorState tests', () => { __parent: 'root', __prev: null, __size: 1, - __state: {}, __style: '', __textFormat: 0, __textStyle: '', @@ -93,7 +91,6 @@ describe('LexicalEditorState tests', () => { __next: null, __parent: '1', __prev: null, - __state: {}, __style: '', __text: 'foo', __type: 'text', @@ -153,7 +150,6 @@ describe('LexicalEditorState tests', () => { __parent: null, __prev: null, __size: 0, - __state: {}, __style: '', __textFormat: 0, __textStyle: '', diff --git a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts index 878ac85e7ca..9b60b0872bc 100644 --- a/packages/lexical/src/__tests__/unit/LexicalNode.test.ts +++ b/packages/lexical/src/__tests__/unit/LexicalNode.test.ts @@ -21,13 +21,12 @@ import { NodeKey, ParagraphNode, RangeSelection, - RootNode, SerializedLexicalNode, SerializedTextNode, TextNode, } from 'lexical'; -import {createStateKey, LexicalNode} from '../../LexicalNode'; +import {LexicalNode} from '../../LexicalNode'; import {$createParagraphNode} from '../../nodes/LexicalParagraphNode'; import {$createTextNode} from '../../nodes/LexicalTextNode'; import { @@ -37,15 +36,7 @@ import { TestInlineElementNode, } from '../utils'; -// https://www.totaltypescript.com/how-to-test-your-types -type Expect = T; -type Equal = (() => T extends X ? 1 : 2) extends () => T extends Y - ? 1 - : 2 - ? true - : false; - -class TestNode extends LexicalNode { +export class TestNode extends LexicalNode { static getType(): string { return 'test'; } @@ -1506,200 +1497,3 @@ describe('LexicalNode tests', () => { }, ); }); - -describe('LexicalNode state', () => { - initializeUnitTest( - (testEnv) => { - let root: RootNode; - - beforeEach(async () => { - const {editor} = testEnv; - await editor.update(() => { - root = $getRoot(); - }); - }); - - test(`setState() need to be inside an update`, async () => { - const fn = () => { - const keyForString = createStateKey('keyForString', { - parse: (value) => (typeof value === 'string' ? value : ''), - }); - root.setState(keyForString, 'hello'); - }; - expect(fn).toThrow(); - }); - - test(`getState and setState`, async () => { - const keyForString = createStateKey('keyForString', { - parse: (value) => (typeof value === 'string' ? value : ''), - }); - const {editor} = testEnv; - editor.update(() => { - const stringValue = root.getState(keyForString); - type _Test = Expect>; - expect(stringValue).toBe(''); - root.setState(keyForString, 'hello'); - expect(root.getState(keyForString)).toBe('hello'); - - const keyForMaybeString = createStateKey('keyForMaybeString', { - parse: (value) => (typeof value === 'string' ? value : undefined), - }); - const maybeStringValue = root.getState(keyForMaybeString); - type _Test2 = Expect< - Equal - >; - expect(maybeStringValue).toBeUndefined(); - - // TO-DO: - // It would be a bit nicer if createStateKey also gave a compilation error. - // It's not a big deal, because getState will indeed throw the error at compile time. - const keyForNoSerializable = createStateKey('keyForNoSerializable', { - parse: () => new Date(), - }); - // @ts-expect-error - null is not a valid value - const _noSerializableValue = root.getState(keyForNoSerializable); - }); - }); - - test(`import and export state`, async () => { - const {editor} = testEnv; - editor.update(() => { - const paragraph = new ParagraphNode(); - const json = paragraph.exportJSON(); - // We don't export state as an empty object - expect(json).not.toHaveProperty('state'); - const keyForNumber = createStateKey('keyForNumber', { - parse: (value) => (typeof value === 'number' ? value : 0), - }); - paragraph.setState(keyForNumber, 1); - const json2 = paragraph.exportJSON(); - expect(json2.state).toStrictEqual({ - keyForNumber: 1, - }); - const paragraph2 = ParagraphNode.importJSON(json2); - expect(paragraph2.__state).toStrictEqual({ - keyForNumber: 1, - }); - }); - }); - - test('states cannot be registered with the same key string', () => { - expect(() => { - createStateKey('foo', {parse: (value) => undefined}); - createStateKey('foo', {parse: (value) => 0}); - }).toThrow( - `There has been an attempt to register a state with the key "foo", but it is already registered.`, - ); - }); - - test('default value should not be exported', async () => { - const {editor} = testEnv; - editor.update(() => { - const indentKey = createStateKey('indent', { - parse: (value) => (typeof value === 'number' ? value : 0), - }); - const paragraph = new ParagraphNode(); - expect(paragraph.getState(indentKey)).toBe(0); - const json = paragraph.exportJSON(); - expect(json).not.toHaveProperty('state'); - paragraph.setState(indentKey, 1); - const json2 = paragraph.exportJSON(); - expect(json2.state).toStrictEqual({ - indent: 1, - }); - // set the default value explicitly - paragraph.setState(indentKey, 0); - const json3 = paragraph.exportJSON(); - expect(json3).not.toHaveProperty('state'); - - // TO-DISCUSS: There has been an attempt to register a state with the key "foo", but it is already registered. - // const foo = createStateKey('foo', { - // parse: (value) => (typeof value === 'string' ? value : ''), - // }); - // paragraph.setState(foo, 'foo'); - // const json4 = paragraph.exportJSON(); - // expect(json4.state).toStrictEqual({ - // foo: 'foo', - // }); - }); - }); - - test('getState returns immutable values, setState require an Object literal', async () => { - type TestObject = { - foo: string; - bar: number; - }; - const {editor} = testEnv; - editor.update(() => { - const paragraph = new ParagraphNode(); - const objectKey = createStateKey('testObject', { - parse: (value) => - (value as TestObject) || { - bar: 0, - foo: '', - }, - }); - const paragraphObject = paragraph.getState(objectKey); - type _Test = Expect< - Equal< - typeof paragraphObject, - { - readonly bar: number; - readonly foo: string; - } - > - >; - - // @ts-expect-error - foo is required - paragraph.setState(objectKey, {bar: 1}); - // @ts-expect-error - baz is not a valid property - paragraph.setState(objectKey, {bar: 1, baz: 'baz', foo: 'foo'}); - - paragraph.setState(objectKey, paragraphObject!); - paragraph.setState(objectKey, {...paragraphObject!, foo: 'foo'}); - }); - }); - - test('setting state shouldn’t affect previous reconciled versions of the node', () => { - const {editor} = testEnv; - let v0: RootNode; - let v1: RootNode; - const vk = createStateKey('vk', { - parse: (v) => (typeof v === 'number' ? v : null), - }); - editor.update( - () => { - v0 = $getRoot(); - v0.setState(vk, 0); - expect(v0.getState(vk)).toBe(0); - }, - {discrete: true}, - ); - const state0 = editor.getEditorState(); - editor.update( - () => { - v0.setState(vk, 1); - v1 = v0.getLatest(); - // This is testing getLatest() - expect(v0.getState(vk)).toBe(1); - expect(v1.getState(vk)).toBe(1); - expect(v1.is(v0)).toBe(true); - }, - {discrete: true}, - ); - const state1 = editor.getEditorState(); - // Test that the correct version is returned and that they are independent - expect(state0.read(() => v0.getState(vk))).toBe(0); - expect(state1.read(() => v1.getState(vk))).toBe(1); - // Test that getLatest is used and not the __state property directly - expect(state0.read(() => v1.getState(vk))).toBe(0); - expect(state1.read(() => v0.getState(vk))).toBe(1); - }); - }, - { - namespace: '', - nodes: [LexicalNode, TestNode], - theme: {}, - }, - ); -}); diff --git a/packages/lexical/src/__tests__/unit/LexicalNodeState.test.ts b/packages/lexical/src/__tests__/unit/LexicalNodeState.test.ts new file mode 100644 index 00000000000..e5f3faca525 --- /dev/null +++ b/packages/lexical/src/__tests__/unit/LexicalNodeState.test.ts @@ -0,0 +1,225 @@ +/** + * 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 {$getRoot, ParagraphNode} from 'lexical'; + +import {LexicalNode} from '../../LexicalNode'; +import {createState} from '../../LexicalNodeState'; +import {RootNode} from '../../nodes/LexicalRootNode'; +import {initializeUnitTest} from '../utils'; +import {TestNode} from './LexicalNode.test'; + +// https://www.totaltypescript.com/how-to-test-your-types +type Expect = T; +type Equal = (() => T extends X ? 1 : 2) extends () => T extends Y + ? 1 + : 2 + ? true + : false; + +describe('LexicalNode state', () => { + initializeUnitTest( + (testEnv) => { + let root: RootNode; + + beforeEach(async () => { + const {editor} = testEnv; + await editor.update(() => { + root = $getRoot(); + }); + }); + + test(`state.$set() and state.$get() need to be inside an update`, async () => { + const stringState = createState('stringState', { + parse: (value) => (typeof value === 'string' ? value : ''), + }); + const $fn = () => { + stringState.$set(root, 'hello'); + }; + const $fn2 = () => { + stringState.$set(root, 'hello'); + }; + expect($fn).toThrow(); + expect($fn2).toThrow(); + const {editor} = testEnv; + editor.update(() => { + expect($fn).not.toThrow(); + expect($fn2).not.toThrow(); + }); + }); + + test(`getState and setState`, async () => { + const stringState = createState('stringState', { + parse: (value) => (typeof value === 'string' ? value : ''), + }); + const {editor} = testEnv; + editor.update(() => { + const stringValue = stringState.$get(root); + type _Test = Expect>; + expect(stringValue).toBe(''); + stringState.$set(root, 'hello'); + expect(stringState.$get(root)).toBe('hello'); + + const maybeStringState = createState('maybeStringState', { + parse: (value) => (typeof value === 'string' ? value : undefined), + }); + const maybeStringValue = maybeStringState.$get(root); + type _Test2 = Expect< + Equal + >; + expect(maybeStringValue).toBeUndefined(); + + const _noSerializableState = createState('noSerializableState', { + // @ts-expect-error - Date is not serializable + parse: () => new Date(), + }); + }); + }); + + test(`import and export state`, async () => { + const {editor} = testEnv; + editor.update(() => { + const paragraph = new ParagraphNode(); + const json = paragraph.exportJSON(); + // We don't export state as an empty object + expect(json).not.toHaveProperty('state'); + const numberState = createState('numberState', { + parse: (value) => (typeof value === 'number' ? value : 0), + }); + numberState.$set(paragraph, 1); + const json2 = paragraph.exportJSON(); + expect(json2.state).toStrictEqual({ + numberState: 1, + }); + const paragraph2 = ParagraphNode.importJSON(json2); + const json3 = paragraph2.exportJSON(); + expect(json3.state).toStrictEqual({ + numberState: 1, + }); + }); + }); + + // TODO + // test('states cannot be registered with the same key string', () => { + // expect(() => { + // createState('foo', {parse: (value) => undefined}); + // createState('foo', {parse: (value) => 0}); + // }).toThrow( + // `There has been an attempt to register a state with the key "foo", but it is already registered.`, + // ); + // }); + + test('default value should not be exported', async () => { + const {editor} = testEnv; + editor.update(() => { + const indentState = createState('indent', { + parse: (value) => (typeof value === 'number' ? value : 0), + }); + const paragraph = new ParagraphNode(); + expect(indentState.$get(paragraph)).toBe(0); + const json = paragraph.exportJSON(); + expect(json).not.toHaveProperty('state'); + indentState.$set(paragraph, 1); + const json2 = paragraph.exportJSON(); + expect(json2.state).toStrictEqual({ + indent: 1, + }); + // set the default value explicitly + indentState.$set(paragraph, 0); + const json3 = paragraph.exportJSON(); + expect(json3).not.toHaveProperty('state'); + + const foo = createState('foo', { + parse: (value) => (typeof value === 'string' ? value : ''), + }); + foo.$set(paragraph, 'fooValue'); + const json4 = paragraph.exportJSON(); + expect(json4.state).toStrictEqual({ + foo: 'fooValue', + }); + }); + }); + + test('getState returns immutable values, setState require an Object literal', async () => { + type TestObject = { + foo: string; + bar: number; + }; + const {editor} = testEnv; + editor.update(() => { + const paragraph = new ParagraphNode(); + const objectState = createState('object', { + parse: (value) => + (value as TestObject) || { + bar: 0, + foo: '', + }, + }); + const paragraphObject = objectState.$get(paragraph); + type _Test = Expect< + Equal< + typeof paragraphObject, + { + readonly bar: number; + readonly foo: string; + } + > + >; + + // @ts-expect-error - foo is required + objectState.$set(paragraph, {bar: 1}); + // @ts-expect-error - baz is not a valid property + objectState.$set(paragraph, {bar: 1, baz: 'baz', foo: 'foo'}); + + objectState.$set(paragraph, paragraphObject!); + objectState.$set(paragraph, {...paragraphObject!, foo: 'foo'}); + }); + }); + + test('setting state shouldn’t affect previous reconciled versions of the node', () => { + const {editor} = testEnv; + let v0: RootNode; + let v1: RootNode; + const vk = createState('vk', { + parse: (v) => (typeof v === 'number' ? v : null), + }); + editor.update( + () => { + v0 = $getRoot(); + vk.$set(v0, 0); + expect(vk.$get(v0)).toBe(0); + }, + {discrete: true}, + ); + const state0 = editor.getEditorState(); + editor.update( + () => { + vk.$set(v0, 1); + v1 = v0.getLatest(); + // This is testing getLatest() + expect(vk.$get(v0)).toBe(1); + expect(vk.$get(v1)).toBe(1); + expect(v1.is(v0)).toBe(true); + }, + {discrete: true}, + ); + const state1 = editor.getEditorState(); + // Test that the correct version is returned and that they are independent + expect(state0.read(() => vk.$get(v0))).toBe(0); + expect(state1.read(() => vk.$get(v1))).toBe(1); + // Test that getLatest is used and not the __state property directly + expect(state0.read(() => vk.$get(v1))).toBe(0); + expect(state1.read(() => vk.$get(v0))).toBe(1); + }); + }, + { + namespace: '', + nodes: [LexicalNode, TestNode], + theme: {}, + }, + ); +}); From 4624e2fcbe22464e14420da9dd3b969e4e068e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Jablo=C3=B1ski?= <43938777+GermanJablo@users.noreply.github.com> Date: Mon, 10 Feb 2025 18:25:26 -0300 Subject: [PATCH 25/25] improvements --- .../docs/concepts/node-replacement.md | 20 +++++++++---------- packages/lexical/src/LexicalNode.ts | 12 ----------- packages/lexical/src/LexicalNodeState.ts | 2 +- 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/packages/lexical-website/docs/concepts/node-replacement.md b/packages/lexical-website/docs/concepts/node-replacement.md index 1eefe748e0a..dda506baf18 100644 --- a/packages/lexical-website/docs/concepts/node-replacement.md +++ b/packages/lexical-website/docs/concepts/node-replacement.md @@ -2,36 +2,34 @@ Originally the only way to customize nodes was using the node replacement API. Recently we have introduced a second way with the `state` property which has some advantages described below. -## State (New) +## State (Experimental) The advantages of using state over the replacement API are: 1. Easier (less boilerplate) 2. Composable (multiple plugins extending the same node causes failures) 3. Allows metadata: useful for adding things to the RootNode. -All you need to do is define keys with `createStateKey`, and then use it with the `setState` and `getState` methods. - ```ts // IMPLEMENTATION -const color = createStateKey('color', { +const colorState = createState('color', { parse: (value: unknown) => (typeof value === 'string' ? value : undefined), }); // USAGE const textNode = $createTextNode(); -textNode.setState(color, "blue"); -const textColor = textNode.getState(color) // -> "blue" +colorState.$set(textNode, "blue"); +const textColor = colorState.$get(textNode) // -> "blue" ``` -Inside state, you can put any serializable json value except null. Our recommendation is to always use TypeScript in strict mode, so you don't have to worry about these things! +Inside state, you can put any serializable json value. Our recommendation is to always use TypeScript in strict mode, so you don't have to worry about these things! ### Important -we recommend that you use prefixes with low collision probability when defining state keys. For example, if you are making a plugin called `awesome-lexical`, you could do: +we recommend that you use prefixes with low collision probability when defining state. For example, if you are making a plugin called `awesome-lexical`, you could do: ```ts -const color = createStateKey('awesome-lexical-color', /** your parse fn */) -const bgColor = createStateKey('awesome-lexical-bg-color', /** your parse fn */) +const color = createState('awesome-lexical-color', /** your parse fn */) +const bgColor = createState('awesome-lexical-bg-color', /** your parse fn */) // Or you can add all your state inside an object: type AwesomeLexical = { @@ -39,7 +37,7 @@ type AwesomeLexical = { bgColor?: string; padding?: number } -const awesomeLexical = createStateKey('awesome-lexical', /** your parse fn which returns AwesomeLexical type */) +const awesomeLexical = createState('awesome-lexical', /** your parse fn which returns AwesomeLexical type */) ``` diff --git a/packages/lexical/src/LexicalNode.ts b/packages/lexical/src/LexicalNode.ts index 5c6ae55a4d8..f071458228d 100644 --- a/packages/lexical/src/LexicalNode.ts +++ b/packages/lexical/src/LexicalNode.ts @@ -213,18 +213,6 @@ export class LexicalNode { this._state = value; } - // getState(k: T): T['value'] { - // const self = this.getLatest(); - // // If the state is not set, return the default value - // return k.parse(self.__state[k.key]); - // } - - // setState(k: T, v: T['value']): this { - // const self = this.getWritable(); - // self.__state = {...self.__state, [k.key]: v}; - // return self; - // } - // Flow doesn't support abstract classes unfortunately, so we can't _force_ // subclasses of Node to implement statics. All subclasses of Node should have // a static getType and clone method though. We define getType and clone here so we can call it diff --git a/packages/lexical/src/LexicalNodeState.ts b/packages/lexical/src/LexicalNodeState.ts index 967f2ef6661..2543e6d2f30 100644 --- a/packages/lexical/src/LexicalNodeState.ts +++ b/packages/lexical/src/LexicalNodeState.ts @@ -30,7 +30,7 @@ export type State = { [Key in string]?: string | number | boolean | null | undefined | State; }; -type StateValue = string | number | boolean | null | undefined | State; +type StateValue = State[keyof State]; export function createState( key: K,