Skip to content

Commit

Permalink
Capture the expected payload type in commands (#2537)
Browse files Browse the repository at this point in the history
  • Loading branch information
PAkerstrand authored Jul 11, 2022
1 parent 4f5c6ba commit 04a8b55
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 54 deletions.
10 changes: 4 additions & 6 deletions packages/lexical-code/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1160,24 +1160,22 @@ export function registerCodeHighlighting(editor: LexicalEditor): () => void {
),
editor.registerCommand(
KEY_ARROW_UP_COMMAND,
(payload: KeyboardEvent): boolean =>
handleShiftLines(KEY_ARROW_UP_COMMAND, payload),
(payload): boolean => handleShiftLines(KEY_ARROW_UP_COMMAND, payload),
COMMAND_PRIORITY_LOW,
),
editor.registerCommand(
KEY_ARROW_DOWN_COMMAND,
(payload: KeyboardEvent): boolean =>
handleShiftLines(KEY_ARROW_DOWN_COMMAND, payload),
(payload): boolean => handleShiftLines(KEY_ARROW_DOWN_COMMAND, payload),
COMMAND_PRIORITY_LOW,
),
editor.registerCommand(
MOVE_TO_END,
(payload: KeyboardEvent): boolean => handleMoveTo(MOVE_TO_END, payload),
(payload): boolean => handleMoveTo(MOVE_TO_END, payload),
COMMAND_PRIORITY_LOW,
),
editor.registerCommand(
MOVE_TO_START,
(payload: KeyboardEvent): boolean => handleMoveTo(MOVE_TO_START, payload),
(payload): boolean => handleMoveTo(MOVE_TO_START, payload),
COMMAND_PRIORITY_LOW,
),
);
Expand Down
23 changes: 14 additions & 9 deletions packages/lexical-plain-text/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*
*/

import type {EditorState, LexicalEditor} from 'lexical';
import type {CommandPayloadType, EditorState, LexicalEditor} from 'lexical';

import {
$getHtmlContent,
Expand Down Expand Up @@ -64,12 +64,13 @@ const updateOptions: {
} = options;

function onCopyForPlainText(
event: ClipboardEvent,
event: CommandPayloadType<typeof COPY_COMMAND>,
editor: LexicalEditor,
): void {
event.preventDefault();
editor.update(() => {
const clipboardData = event.clipboardData;
const clipboardData =
event instanceof KeyboardEvent ? null : event.clipboardData;
const selection = $getSelection();

if (selection !== null) {
Expand All @@ -87,21 +88,25 @@ function onCopyForPlainText(
}

function onPasteForPlainText(
event: ClipboardEvent,
event: CommandPayloadType<typeof PASTE_COMMAND>,
editor: LexicalEditor,
): void {
event.preventDefault();
editor.update(() => {
const selection = $getSelection();
const clipboardData = event.clipboardData;
const clipboardData =
event instanceof InputEvent ? null : event.clipboardData;

if (clipboardData != null && $isRangeSelection(selection)) {
$insertDataTransferForPlainText(clipboardData, selection);
}
});
}

function onCutForPlainText(event: ClipboardEvent, editor: LexicalEditor): void {
function onCutForPlainText(
event: CommandPayloadType<typeof CUT_COMMAND>,
editor: LexicalEditor,
): void {
onCopyForPlainText(event, editor);
editor.update(() => {
const selection = $getSelection();
Expand Down Expand Up @@ -378,7 +383,7 @@ export function registerPlainText(
},
COMMAND_PRIORITY_EDITOR,
),
editor.registerCommand<ClipboardEvent>(
editor.registerCommand(
COPY_COMMAND,
(event) => {
const selection = $getSelection();
Expand All @@ -392,7 +397,7 @@ export function registerPlainText(
},
COMMAND_PRIORITY_EDITOR,
),
editor.registerCommand<ClipboardEvent>(
editor.registerCommand(
CUT_COMMAND,
(event) => {
const selection = $getSelection();
Expand All @@ -406,7 +411,7 @@ export function registerPlainText(
},
COMMAND_PRIORITY_EDITOR,
),
editor.registerCommand<ClipboardEvent>(
editor.registerCommand(
PASTE_COMMAND,
(event) => {
const selection = $getSelection();
Expand Down
7 changes: 2 additions & 5 deletions packages/lexical-playground/src/plugins/ActionsPlugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,7 @@ export default function ActionsPlugin({
{SUPPORT_SPEECH_RECOGNITION && (
<button
onClick={() => {
editor.dispatchCommand<boolean>(
SPEECH_TO_TEXT_COMMAND,
!isSpeechToText,
);
editor.dispatchCommand(SPEECH_TO_TEXT_COMMAND, !isSpeechToText);
setIsSpeechToText(!isSpeechToText);
}}
className={
Expand Down Expand Up @@ -210,7 +207,7 @@ function ShowClearDialog({
<div className="Modal__content">
<Button
onClick={() => {
editor.dispatchCommand<void>(CLEAR_EDITOR_COMMAND, undefined);
editor.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined);
editor.focus();
onClose();
}}>
Expand Down
2 changes: 1 addition & 1 deletion packages/lexical-playground/src/plugins/CommentPlugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,7 @@ export default function CommentPlugin({
}, [editor, markNodeMap]);

const onAddComment = () => {
editor.dispatchCommand(INSERT_INLINE_COMMAND, null);
editor.dispatchCommand(INSERT_INLINE_COMMAND, undefined);
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ function TextFormatFloatingToolbar({
}, [editor, isLink]);

const insertComment = () => {
editor.dispatchCommand(INSERT_INLINE_COMMAND, null);
editor.dispatchCommand(INSERT_INLINE_COMMAND, undefined);
};

const updateTextFormatFloatingToolbar = useCallback(() => {
Expand Down
27 changes: 18 additions & 9 deletions packages/lexical-rich-text/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import type {
CommandPayloadType,
DOMConversionMap,
DOMConversionOutput,
EditorConfig,
Expand Down Expand Up @@ -372,13 +373,14 @@ function initializeEditor(
}

function onPasteForRichText(
event: ClipboardEvent,
event: CommandPayloadType<typeof PASTE_COMMAND>,
editor: LexicalEditor,
): void {
event.preventDefault();
editor.update(() => {
const selection = $getSelection();
const clipboardData = event.clipboardData;
const clipboardData =
event instanceof InputEvent ? null : event.clipboardData;
if (
clipboardData != null &&
($isRangeSelection(selection) || $isGridSelection(selection))
Expand All @@ -388,11 +390,15 @@ function onPasteForRichText(
});
}

function onCopyForRichText(event: ClipboardEvent, editor: LexicalEditor): void {
function onCopyForRichText(
event: CommandPayloadType<typeof COPY_COMMAND>,
editor: LexicalEditor,
): void {
event.preventDefault();
const selection = $getSelection();
if (selection !== null) {
const clipboardData = event.clipboardData;
const clipboardData =
event instanceof KeyboardEvent ? null : event.clipboardData;
const htmlString = $getHtmlContent(editor);
const lexicalString = $getLexicalContent(editor);

Expand Down Expand Up @@ -423,7 +429,10 @@ function onCopyForRichText(event: ClipboardEvent, editor: LexicalEditor): void {
}
}

function onCutForRichText(event: ClipboardEvent, editor: LexicalEditor): void {
function onCutForRichText(
event: CommandPayloadType<typeof CUT_COMMAND>,
editor: LexicalEditor,
): void {
onCopyForRichText(event, editor);
const selection = $getSelection();
if ($isRangeSelection(selection)) {
Expand Down Expand Up @@ -518,7 +527,7 @@ export function registerRichText(
},
COMMAND_PRIORITY_EDITOR,
),
editor.registerCommand<InputEvent | string>(
editor.registerCommand(
CONTROLLED_TEXT_INSERTION_COMMAND,
(eventOrText) => {
const selection = $getSelection();
Expand Down Expand Up @@ -806,23 +815,23 @@ export function registerRichText(
},
COMMAND_PRIORITY_EDITOR,
),
editor.registerCommand<ClipboardEvent>(
editor.registerCommand(
COPY_COMMAND,
(event) => {
onCopyForRichText(event, editor);
return true;
},
COMMAND_PRIORITY_EDITOR,
),
editor.registerCommand<ClipboardEvent>(
editor.registerCommand(
CUT_COMMAND,
(event) => {
onCutForRichText(event, editor);
return true;
},
COMMAND_PRIORITY_EDITOR,
),
editor.registerCommand<ClipboardEvent>(
editor.registerCommand(
PASTE_COMMAND,
(event) => {
const selection = $getSelection();
Expand Down
12 changes: 8 additions & 4 deletions packages/lexical/src/LexicalCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ export const DELETE_CHARACTER_COMMAND: LexicalCommand<boolean> =
export const INSERT_LINE_BREAK_COMMAND: LexicalCommand<boolean> =
createCommand();
export const INSERT_PARAGRAPH_COMMAND: LexicalCommand<void> = createCommand();
export const CONTROLLED_TEXT_INSERTION_COMMAND: LexicalCommand<string> =
export const CONTROLLED_TEXT_INSERTION_COMMAND: LexicalCommand<
InputEvent | string
> = createCommand();
export const PASTE_COMMAND: LexicalCommand<ClipboardEvent | InputEvent> =
createCommand();
export const PASTE_COMMAND: LexicalCommand<ClipboardEvent> = createCommand();
export const REMOVE_TEXT_COMMAND: LexicalCommand<void> = createCommand();
export const DELETE_WORD_COMMAND: LexicalCommand<boolean> = createCommand();
export const DELETE_LINE_COMMAND: LexicalCommand<boolean> = createCommand();
Expand Down Expand Up @@ -57,8 +59,10 @@ export const FORMAT_ELEMENT_COMMAND: LexicalCommand<ElementFormatType> =
export const DRAGSTART_COMMAND: LexicalCommand<DragEvent> = createCommand();
export const DRAGOVER_COMMAND: LexicalCommand<DragEvent> = createCommand();
export const DRAGEND_COMMAND: LexicalCommand<DragEvent> = createCommand();
export const COPY_COMMAND: LexicalCommand<ClipboardEvent> = createCommand();
export const CUT_COMMAND: LexicalCommand<ClipboardEvent> = createCommand();
export const COPY_COMMAND: LexicalCommand<ClipboardEvent | KeyboardEvent> =
createCommand();
export const CUT_COMMAND: LexicalCommand<ClipboardEvent | KeyboardEvent> =
createCommand();
export const CLEAR_EDITOR_COMMAND: LexicalCommand<void> = createCommand();
export const CLEAR_HISTORY_COMMAND: LexicalCommand<void> = createCommand();
export const CAN_REDO_COMMAND: LexicalCommand<boolean> = createCommand();
Expand Down
30 changes: 28 additions & 2 deletions packages/lexical/src/LexicalEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,30 @@ export const COMMAND_PRIORITY_HIGH = 3;
export const COMMAND_PRIORITY_CRITICAL = 4;

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export type LexicalCommand<T = never> = Readonly<Record<string, unknown>>;
export type LexicalCommand<TPayload> = Record<string, never>;
/**
* Type helper for extracting the payload type from a command.
*
* @example
* ```ts
* const MY_COMMAND = createCommand<SomeType>();
*
* // ...
*
* editor.registerCommand(MY_COMMAND, payload => {
* // Type of `payload` is inferred here. But lets say we want to extract a function to delegate to
* handleMyCommand(editor, payload);
* return true;
* });
*
* function handleMyCommand(editor: LexicalEditor, payload: CommandPayloadType<typeof MY_COMMAND>) {
* // `payload` is of type `SomeType`, extracted from the command.
* }
* ```
*/
export type CommandPayloadType<TCommand extends LexicalCommand<unknown>> =
TCommand extends LexicalCommand<infer TPayload> ? TPayload : never;

type Commands = Map<
LexicalCommand<unknown>,
Array<Set<CommandListener<unknown>>>
Expand Down Expand Up @@ -634,7 +657,10 @@ export class LexicalEditor {
return true;
}

dispatchCommand<P>(type: LexicalCommand<P>, payload: P): boolean {
dispatchCommand<
TCommand extends LexicalCommand<unknown>,
TPayload extends CommandPayloadType<TCommand>,
>(type: TCommand, payload: TPayload): boolean {
return dispatchCommand(this, type, payload);
}

Expand Down
Loading

2 comments on commit 04a8b55

@vercel
Copy link

@vercel vercel bot commented on 04a8b55 Jul 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

lexical – ./packages/lexical-website-new

lexical.dev
lexical-fbopensource.vercel.app
lexical-git-main-fbopensource.vercel.app
lexicaljs.org
www.lexical.dev
lexicaljs.com

@vercel
Copy link

@vercel vercel bot commented on 04a8b55 Jul 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

lexical-playground – ./packages/lexical-playground

lexical-playground.vercel.app
lexical-playground-fbopensource.vercel.app
playground.lexical.dev
lexical-playground-git-main-fbopensource.vercel.app

Please sign in to comment.