diff --git a/package-lock.json b/package-lock.json
index 90380e21120..6553ad7b38f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -26436,7 +26436,7 @@
"dev": true,
"requires": {
"@types/node": "*",
- "playwright-core": "1.23.0-next-alpha-trueadm-fork"
+ "playwright-core": "1.23.1"
}
},
"@polka/url": {
diff --git a/packages/lexical-playground/src/plugins/AutoEmbedPlugin/index.tsx b/packages/lexical-playground/src/plugins/AutoEmbedPlugin/index.tsx
index 177fcc2e295..0110fc6f878 100644
--- a/packages/lexical-playground/src/plugins/AutoEmbedPlugin/index.tsx
+++ b/packages/lexical-playground/src/plugins/AutoEmbedPlugin/index.tsx
@@ -22,6 +22,7 @@ import * as ReactDOM from 'react-dom';
import useModal from '../../hooks/useModal';
import Button from '../../ui/Button';
+import {DialogActions} from '../../ui/Dialog';
import {INSERT_FIGMA_COMMAND} from '../FigmaPlugin';
import {INSERT_TWEET_COMMAND} from '../TwitterPlugin';
import {INSERT_YOUTUBE_COMMAND} from '../YouTubePlugin';
@@ -248,14 +249,14 @@ export function AutoEmbedDialog({
}}
/>
-
+
-
+
);
}
diff --git a/packages/lexical-playground/src/plugins/ComponentPickerPlugin/index.tsx b/packages/lexical-playground/src/plugins/ComponentPickerPlugin/index.tsx
index 5df0bf4fe08..6a95eac6a16 100644
--- a/packages/lexical-playground/src/plugins/ComponentPickerPlugin/index.tsx
+++ b/packages/lexical-playground/src/plugins/ComponentPickerPlugin/index.tsx
@@ -38,14 +38,11 @@ import useModal from '../../hooks/useModal';
import catTypingGif from '../../images/cat-typing.gif';
import {EmbedConfigs} from '../AutoEmbedPlugin';
import {INSERT_COLLAPSIBLE_COMMAND} from '../CollapsiblePlugin';
+import {InsertEquationDialog} from '../EquationsPlugin';
import {INSERT_EXCALIDRAW_COMMAND} from '../ExcalidrawPlugin';
-import {INSERT_IMAGE_COMMAND} from '../ImagesPlugin';
-import {
- InsertEquationDialog,
- InsertImageDialog,
- InsertPollDialog,
- InsertTableDialog,
-} from '../ToolbarPlugin';
+import {INSERT_IMAGE_COMMAND, InsertImageDialog} from '../ImagesPlugin';
+import {InsertPollDialog} from '../PollPlugin';
+import {InsertTableDialog} from '../TablePlugin';
class ComponentPickerOption extends TypeaheadOption {
// What shows up in the editor
diff --git a/packages/lexical-playground/src/plugins/EquationsPlugin/index.ts b/packages/lexical-playground/src/plugins/EquationsPlugin/index.tsx
similarity index 72%
rename from packages/lexical-playground/src/plugins/EquationsPlugin/index.ts
rename to packages/lexical-playground/src/plugins/EquationsPlugin/index.tsx
index 13881b553fb..11c84c16061 100644
--- a/packages/lexical-playground/src/plugins/EquationsPlugin/index.ts
+++ b/packages/lexical-playground/src/plugins/EquationsPlugin/index.tsx
@@ -17,10 +17,13 @@ import {
COMMAND_PRIORITY_EDITOR,
createCommand,
LexicalCommand,
+ LexicalEditor,
} from 'lexical';
-import {useEffect} from 'react';
+import {useCallback, useEffect} from 'react';
+import * as React from 'react';
import {$createEquationNode, EquationNode} from '../../nodes/EquationNode';
+import KatexEquationAlterer from '../../ui/KatexEquationAlterer';
type CommandPayload = {
equation: string;
@@ -30,6 +33,24 @@ type CommandPayload = {
export const INSERT_EQUATION_COMMAND: LexicalCommand =
createCommand();
+export function InsertEquationDialog({
+ activeEditor,
+ onClose,
+}: {
+ activeEditor: LexicalEditor;
+ onClose: () => void;
+}): JSX.Element {
+ const onEquationConfirm = useCallback(
+ (equation: string, inline: boolean) => {
+ activeEditor.dispatchCommand(INSERT_EQUATION_COMMAND, {equation, inline});
+ onClose();
+ },
+ [activeEditor, onClose],
+ );
+
+ return ;
+}
+
export default function EquationsPlugin(): JSX.Element | null {
const [editor] = useLexicalComposerContext();
diff --git a/packages/lexical-playground/src/plugins/ImagesPlugin/index.ts b/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx
similarity index 56%
rename from packages/lexical-playground/src/plugins/ImagesPlugin/index.ts
rename to packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx
index 9de793e7af3..f632b0da9ed 100644
--- a/packages/lexical-playground/src/plugins/ImagesPlugin/index.ts
+++ b/packages/lexical-playground/src/plugins/ImagesPlugin/index.tsx
@@ -25,20 +25,182 @@ import {
LexicalCommand,
LexicalEditor,
} from 'lexical';
-import {useEffect} from 'react';
+import {useEffect, useRef, useState} from 'react';
+import * as React from 'react';
import getSelection from 'shared/getDOMSelection';
+import landscapeImage from '../../images/landscape.jpg';
+import yellowFlowerImage from '../../images/yellow-flower.jpg';
import {
$createImageNode,
$isImageNode,
ImageNode,
ImagePayload,
} from '../../nodes/ImageNode';
+import Button from '../../ui/Button';
+import {DialogActions, DialogButtonsList} from '../../ui/Dialog';
+import FileInput from '../../ui/FileInput';
+import TextInput from '../../ui/TextInput';
export type InsertImagePayload = Readonly;
export const INSERT_IMAGE_COMMAND: LexicalCommand =
createCommand();
+
+export function InsertImageUriDialogBody({
+ onClick,
+}: {
+ onClick: (payload: InsertImagePayload) => void;
+}) {
+ const [src, setSrc] = useState('');
+ const [altText, setAltText] = useState('');
+
+ const isDisabled = src === '';
+
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+}
+
+export function InsertImageUploadedDialogBody({
+ onClick,
+}: {
+ onClick: (payload: InsertImagePayload) => void;
+}) {
+ const [src, setSrc] = useState('');
+ const [altText, setAltText] = useState('');
+
+ const isDisabled = src === '';
+
+ const loadImage = (files: FileList | null) => {
+ const reader = new FileReader();
+ reader.onload = function () {
+ if (typeof reader.result === 'string') {
+ setSrc(reader.result);
+ }
+ return '';
+ };
+ if (files !== null) {
+ reader.readAsDataURL(files[0]);
+ }
+ };
+
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+}
+
+export function InsertImageDialog({
+ activeEditor,
+ onClose,
+}: {
+ activeEditor: LexicalEditor;
+ onClose: () => void;
+}): JSX.Element {
+ const [mode, setMode] = useState(null);
+ const hasModifier = useRef(false);
+
+ useEffect(() => {
+ hasModifier.current = false;
+ const handler = (e: KeyboardEvent) => {
+ hasModifier.current = e.altKey;
+ };
+ document.addEventListener('keydown', handler);
+ return () => {
+ document.removeEventListener('keydown', handler);
+ };
+ }, [activeEditor]);
+
+ const onClick = (payload: InsertImagePayload) => {
+ activeEditor.dispatchCommand(INSERT_IMAGE_COMMAND, payload);
+ onClose();
+ };
+
+ return (
+ <>
+ {!mode && (
+
+
+
+
+
+ )}
+ {mode === 'url' && }
+ {mode === 'file' && }
+ >
+ );
+}
+
export default function ImagesPlugin({
captionsEnabled,
}: {
diff --git a/packages/lexical-playground/src/plugins/PollPlugin/index.ts b/packages/lexical-playground/src/plugins/PollPlugin/index.tsx
similarity index 62%
rename from packages/lexical-playground/src/plugins/PollPlugin/index.ts
rename to packages/lexical-playground/src/plugins/PollPlugin/index.tsx
index 7067f6b0580..c5a60c08f43 100644
--- a/packages/lexical-playground/src/plugins/PollPlugin/index.ts
+++ b/packages/lexical-playground/src/plugins/PollPlugin/index.tsx
@@ -15,13 +15,44 @@ import {
COMMAND_PRIORITY_EDITOR,
createCommand,
LexicalCommand,
+ LexicalEditor,
} from 'lexical';
-import {useEffect} from 'react';
+import {useEffect, useState} from 'react';
+import * as React from 'react';
import {$createPollNode, PollNode} from '../../nodes/PollNode';
+import Button from '../../ui/Button';
+import {DialogActions} from '../../ui/Dialog';
+import TextInput from '../../ui/TextInput';
export const INSERT_POLL_COMMAND: LexicalCommand = createCommand();
+export function InsertPollDialog({
+ activeEditor,
+ onClose,
+}: {
+ activeEditor: LexicalEditor;
+ onClose: () => void;
+}): JSX.Element {
+ const [question, setQuestion] = useState('');
+
+ const onClick = () => {
+ activeEditor.dispatchCommand(INSERT_POLL_COMMAND, question);
+ onClose();
+ };
+
+ return (
+ <>
+
+
+
+
+ >
+ );
+}
+
export default function PollPlugin(): JSX.Element | null {
const [editor] = useLexicalComposerContext();
useEffect(() => {
diff --git a/packages/lexical-playground/src/plugins/TablePlugin.tsx b/packages/lexical-playground/src/plugins/TablePlugin.tsx
index fc23657770f..185629f6b1b 100644
--- a/packages/lexical-playground/src/plugins/TablePlugin.tsx
+++ b/packages/lexical-playground/src/plugins/TablePlugin.tsx
@@ -7,6 +7,7 @@
*/
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
+import {INSERT_TABLE_COMMAND} from '@lexical/table';
import {
$createNodeSelection,
$createParagraphNode,
@@ -27,6 +28,9 @@ import * as React from 'react';
import invariant from 'shared/invariant';
import {$createTableNodeWithDimensions, TableNode} from '../nodes/TableNode';
+import Button from '../ui/Button';
+import {DialogActions} from '../ui/Dialog';
+import TextInput from '../ui/TextInput';
export type InsertTableCommandPayload = Readonly<{
columns: string;
@@ -51,7 +55,7 @@ export type CellEditorConfig = Readonly<{
theme?: EditorThemeClasses;
}>;
-export const INSERT_TABLE_COMMAND: LexicalCommand =
+export const INSERT_NEW_TABLE_COMMAND: LexicalCommand =
createCommand();
// @ts-ignore: not sure why TS doesn't like using null as the value?
@@ -88,6 +92,58 @@ export function TableContext({children}: {children: JSX.Element}) {
);
}
+export function InsertTableDialog({
+ activeEditor,
+ onClose,
+}: {
+ activeEditor: LexicalEditor;
+ onClose: () => void;
+}): JSX.Element {
+ const [rows, setRows] = useState('5');
+ const [columns, setColumns] = useState('5');
+
+ const onClick = () => {
+ activeEditor.dispatchCommand(INSERT_TABLE_COMMAND, {columns, rows});
+ onClose();
+ };
+
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+}
+
+export function InsertNewTableDialog({
+ activeEditor,
+ onClose,
+}: {
+ activeEditor: LexicalEditor;
+ onClose: () => void;
+}): JSX.Element {
+ const [rows, setRows] = useState('5');
+ const [columns, setColumns] = useState('5');
+
+ const onClick = () => {
+ activeEditor.dispatchCommand(INSERT_NEW_TABLE_COMMAND, {columns, rows});
+ onClose();
+ };
+
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+}
+
export function TablePlugin({
cellEditorConfig,
children,
diff --git a/packages/lexical-playground/src/plugins/ToolbarPlugin/index.css b/packages/lexical-playground/src/plugins/ToolbarPlugin/index.css
deleted file mode 100644
index 1d3eb153aab..00000000000
--- a/packages/lexical-playground/src/plugins/ToolbarPlugin/index.css
+++ /dev/null
@@ -1,25 +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.
- *
- *
- */
-.ToolbarPlugin__dialogActions {
- display: flex;
- flex-direction: row;
- justify-content: right;
- margin-top: 20px;
-}
-
-.ToolbarPlugin__dialogButtonsList {
- display: flex;
- flex-direction: column;
- justify-content: right;
- margin-top: 20px;
-}
-
-.ToolbarPlugin__dialogButtonsList button {
- margin-bottom: 20px;
-}
diff --git a/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx b/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx
index 61035ba94bd..f19120f0b62 100644
--- a/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx
+++ b/packages/lexical-playground/src/plugins/ToolbarPlugin/index.tsx
@@ -6,11 +6,8 @@
*
*/
-import type {InsertImagePayload} from '../ImagesPlugin';
import type {LexicalEditor, NodeKey} from 'lexical';
-import './index.css';
-
import {
$createCodeNode,
$isCodeNode,
@@ -44,7 +41,6 @@ import {
$selectAll,
$wrapNodes,
} from '@lexical/selection';
-import {INSERT_TABLE_COMMAND} from '@lexical/table';
import {
$findMatchingParent,
$getNearestBlockElementAncestorOrThrow,
@@ -70,30 +66,28 @@ import {
SELECTION_CHANGE_COMMAND,
UNDO_COMMAND,
} from 'lexical';
+import {useCallback, useEffect, useState} from 'react';
import * as React from 'react';
-import {useCallback, useEffect, useRef, useState} from 'react';
import {IS_APPLE} from 'shared/environment';
import useModal from '../../hooks/useModal';
import catTypingGif from '../../images/cat-typing.gif';
-import landscapeImage from '../../images/landscape.jpg';
-import yellowFlowerImage from '../../images/yellow-flower.jpg';
import {$createStickyNode} from '../../nodes/StickyNode';
-import Button from '../../ui/Button';
import ColorPicker from '../../ui/ColorPicker';
import DropDown, {DropDownItem} from '../../ui/DropDown';
-import FileInput from '../../ui/FileInput';
-import KatexEquationAlterer from '../../ui/KatexEquationAlterer';
-import TextInput from '../../ui/TextInput';
import {getSelectedNode} from '../../utils/getSelectedNode';
import {sanitizeUrl} from '../../utils/sanitizeUrl';
import {EmbedConfigs} from '../AutoEmbedPlugin';
import {INSERT_COLLAPSIBLE_COMMAND} from '../CollapsiblePlugin';
-import {INSERT_EQUATION_COMMAND} from '../EquationsPlugin';
+import {InsertEquationDialog} from '../EquationsPlugin';
import {INSERT_EXCALIDRAW_COMMAND} from '../ExcalidrawPlugin';
-import {INSERT_IMAGE_COMMAND} from '../ImagesPlugin';
-import {INSERT_POLL_COMMAND} from '../PollPlugin';
-import {INSERT_TABLE_COMMAND as INSERT_NEW_TABLE_COMMAND} from '../TablePlugin';
+import {
+ INSERT_IMAGE_COMMAND,
+ InsertImageDialog,
+ InsertImagePayload,
+} from '../ImagesPlugin';
+import {InsertPollDialog} from '../PollPlugin';
+import {InsertNewTableDialog, InsertTableDialog} from '../TablePlugin';
const blockTypeToBlockName = {
bullet: 'Bulleted List',
@@ -147,260 +141,6 @@ const FONT_SIZE_OPTIONS: [string, string][] = [
['20px', '20px'],
];
-export function InsertImageUriDialogBody({
- onClick,
-}: {
- onClick: (payload: InsertImagePayload) => void;
-}) {
- const [src, setSrc] = useState('');
- const [altText, setAltText] = useState('');
-
- const isDisabled = src === '';
-
- return (
- <>
-
-
-
-
-
- >
- );
-}
-
-export function InsertImageUploadedDialogBody({
- onClick,
-}: {
- onClick: (payload: InsertImagePayload) => void;
-}) {
- const [src, setSrc] = useState('');
- const [altText, setAltText] = useState('');
-
- const isDisabled = src === '';
-
- const loadImage = (files: FileList | null) => {
- const reader = new FileReader();
- reader.onload = function () {
- if (typeof reader.result === 'string') {
- setSrc(reader.result);
- }
- return '';
- };
- if (files !== null) {
- reader.readAsDataURL(files[0]);
- }
- };
-
- return (
- <>
-
-
-
-
-
- >
- );
-}
-
-export function InsertImageDialog({
- activeEditor,
- onClose,
-}: {
- activeEditor: LexicalEditor;
- onClose: () => void;
-}): JSX.Element {
- const [mode, setMode] = useState(null);
- const hasModifier = useRef(false);
-
- useEffect(() => {
- hasModifier.current = false;
- const handler = (e: KeyboardEvent) => {
- hasModifier.current = e.altKey;
- };
- document.addEventListener('keydown', handler);
- return () => {
- document.removeEventListener('keydown', handler);
- };
- }, [activeEditor]);
-
- const onClick = (payload: InsertImagePayload) => {
- activeEditor.dispatchCommand(INSERT_IMAGE_COMMAND, payload);
- onClose();
- };
-
- return (
- <>
- {!mode && (
-
-
-
-
-
- )}
- {mode === 'url' && }
- {mode === 'file' && }
- >
- );
-}
-
-export function InsertTableDialog({
- activeEditor,
- onClose,
-}: {
- activeEditor: LexicalEditor;
- onClose: () => void;
-}): JSX.Element {
- const [rows, setRows] = useState('5');
- const [columns, setColumns] = useState('5');
-
- const onClick = () => {
- activeEditor.dispatchCommand(INSERT_TABLE_COMMAND, {columns, rows});
- onClose();
- };
-
- return (
- <>
-
-
-
-
-
- >
- );
-}
-
-export function InsertNewTableDialog({
- activeEditor,
- onClose,
-}: {
- activeEditor: LexicalEditor;
- onClose: () => void;
-}): JSX.Element {
- const [rows, setRows] = useState('5');
- const [columns, setColumns] = useState('5');
-
- const onClick = () => {
- activeEditor.dispatchCommand(INSERT_NEW_TABLE_COMMAND, {columns, rows});
- onClose();
- };
-
- return (
- <>
-
-
-
-
-
- >
- );
-}
-
-export function InsertPollDialog({
- activeEditor,
- onClose,
-}: {
- activeEditor: LexicalEditor;
- onClose: () => void;
-}): JSX.Element {
- const [question, setQuestion] = useState('');
-
- const onClick = () => {
- activeEditor.dispatchCommand(INSERT_POLL_COMMAND, question);
- onClose();
- };
-
- return (
- <>
-
-
-
-
- >
- );
-}
-
-export function InsertEquationDialog({
- activeEditor,
- onClose,
-}: {
- activeEditor: LexicalEditor;
- onClose: () => void;
-}): JSX.Element {
- const onEquationConfirm = useCallback(
- (equation: string, inline: boolean) => {
- activeEditor.dispatchCommand(INSERT_EQUATION_COMMAND, {equation, inline});
- onClose();
- },
- [activeEditor, onClose],
- );
-
- return ;
-}
-
function dropDownActiveClass(active: boolean) {
if (active) return 'active dropdown-item-active';
else return '';
diff --git a/packages/lexical-playground/src/ui/Dialog.css b/packages/lexical-playground/src/ui/Dialog.css
new file mode 100644
index 00000000000..9474211e5aa
--- /dev/null
+++ b/packages/lexical-playground/src/ui/Dialog.css
@@ -0,0 +1,17 @@
+.DialogActions {
+ display: flex;
+ flex-direction: row;
+ justify-content: right;
+ margin-top: 20px;
+}
+
+.DialogButtonsList {
+ display: flex;
+ flex-direction: column;
+ justify-content: right;
+ margin-top: 20px;
+}
+
+.DialogButtonsList button {
+ margin-bottom: 20px;
+}
diff --git a/packages/lexical-playground/src/ui/Dialog.tsx b/packages/lexical-playground/src/ui/Dialog.tsx
new file mode 100644
index 00000000000..36e3b8c5938
--- /dev/null
+++ b/packages/lexical-playground/src/ui/Dialog.tsx
@@ -0,0 +1,32 @@
+/**
+ * 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 './Dialog.css';
+
+import * as React from 'react';
+import {ReactNode} from 'react';
+
+type Props = Readonly<{
+ 'data-test-id'?: string;
+ children: ReactNode;
+}>;
+
+export function DialogButtonsList({children}: Props): JSX.Element {
+ return {children}
;
+}
+
+export function DialogActions({
+ 'data-test-id': dataTestId,
+ children,
+}: Props): JSX.Element {
+ return (
+
+ {children}
+
+ );
+}