Make 'slate' and 'slate-react' Plugin types generic (#40777)

* Added slate-react onContextMenu prop type

* Added onContextMenu to unit test

* Made Plugin related interfaces generic to allow using slate-react Editor type in plugins.
This commit is contained in:
Brian Ingles
2019-12-04 15:51:47 -08:00
committed by Ron Buckton
parent fc68244f36
commit c6dea7c0bf
4 changed files with 101 additions and 34 deletions
+16 -14
View File
@@ -11,6 +11,7 @@
// Jack Allen <https://github.com/jackall3n>
// Benjamin Evenson <https://github.com/benjiro>
// Kay Delaney <https://github.com/kaydelaney>
// Brian Ingles <https://github.com/bmingles>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
import {
@@ -101,15 +102,15 @@ export interface RenderInlineProps extends RenderNodeProps {
export type EventHook<T = Event> = (event: T, editor: Editor, next: () => any) => any;
export interface Plugin extends CorePlugin {
decorateNode?: (node: SlateNode, editor: CoreEditor, next: () => any) => any;
renderAnnotation?: (props: RenderAnnotationProps, editor: CoreEditor, next: () => any) => any;
renderBlock?: (props: RenderBlockProps, editor: CoreEditor, next: () => any) => any;
renderDecoration?: (props: RenderDecorationProps, editor: CoreEditor, next: () => any) => any;
renderDocument?: (props: RenderDocumentProps, editor: CoreEditor, next: () => any) => any;
renderEditor?: (props: EditorProps, editor: CoreEditor, next: () => any) => any;
renderInline?: (props: RenderInlineProps, editor: CoreEditor, next: () => any) => any;
renderMark?: (props: RenderMarkProps, editor: CoreEditor, next: () => any) => any;
export interface Plugin<T extends Controller = Editor> extends CorePlugin<T> {
decorateNode?: (node: SlateNode, editor: T, next: () => any) => any;
renderAnnotation?: (props: RenderAnnotationProps, editor: T, next: () => any) => any;
renderBlock?: (props: RenderBlockProps, editor: T, next: () => any) => any;
renderDecoration?: (props: RenderDecorationProps, editor: T, next: () => any) => any;
renderDocument?: (props: RenderDocumentProps, editor: T, next: () => any) => any;
renderEditor?: (props: EditorProps, editor: T, next: () => any) => any;
renderInline?: (props: RenderInlineProps, editor: T, next: () => any) => any;
renderMark?: (props: RenderMarkProps, editor: T, next: () => any) => any;
shouldNodeComponentUpdate?: (
previousProps: RenderNodeProps,
@@ -123,6 +124,7 @@ export interface Plugin extends CorePlugin {
onClick?: EventHook<React.MouseEvent>;
onCompositionEnd?: EventHook<React.CompositionEvent>;
onCompositionStart?: EventHook<React.CompositionEvent>;
onContextMenu?: EventHook<React.MouseEvent>;
onCopy?: EventHook<React.ClipboardEvent>;
onCut?: EventHook<React.ClipboardEvent>;
onDragEnd?: EventHook<React.DragEvent>;
@@ -139,8 +141,8 @@ export interface Plugin extends CorePlugin {
onSelect?: EventHook<React.SyntheticEvent>;
}
export type PluginOrPlugins = Plugin | Plugins;
export interface Plugins extends Array<PluginOrPlugins> {}
export type PluginOrPlugins<T extends Controller = Editor> = Plugin<T> | Plugins<T>;
export interface Plugins<T extends Controller = Editor> extends Array<PluginOrPlugins<T>> {}
export interface OnChangeParam {
operations: Immutable.List<Operation>;
@@ -148,14 +150,14 @@ export interface OnChangeParam {
}
export type OnChangeFn = (change: OnChangeParam) => any;
export interface BasicEditorProps {
export interface BasicEditorProps<T extends Controller = Editor> {
value: Value;
autoCorrect?: boolean;
autoFocus?: boolean;
className?: string;
onChange?: OnChangeFn;
placeholder?: any;
plugins?: Plugins;
plugins?: Plugins<T>;
readOnly?: boolean;
role?: string;
schema?: SchemaProperties;
@@ -164,7 +166,7 @@ export interface BasicEditorProps {
tabIndex?: number;
}
export type EditorProps = BasicEditorProps & Plugin;
export type EditorProps<T extends Controller = Editor> = BasicEditorProps<T> & Plugin<T>;
export interface EditorState {
value: Value;
+25 -3
View File
@@ -1,11 +1,32 @@
import { Editor, Plugin, EditorProps, OnChangeFn, RenderBlockProps, RenderInlineProps } from 'slate-react';
import { Value, Editor as Controller, Point, Range, Inline, Mark, Document, Decoration, Operation } from 'slate';
import { Value, Point, Range, Inline, Mark, Document, Decoration, Operation } from 'slate';
import * as React from "react";
import { List } from "immutable";
declare module 'slate-react' {
// Plugins can add command and query method.
// Testing that if we extend the interface, the compiler is aware of the
// new methods inside of other plugin functions.
interface Editor {
someCommand: () => Editor;
someQuery: () => string;
}
}
class MyPlugin implements Plugin {
renderBlock(props: RenderBlockProps, editor: Controller, next: () => void) {
commands = {
someCommand: (editor: Editor) => editor,
};
queries = {
someQuery: (editor: Editor) => 'query result',
};
renderBlock(props: RenderBlockProps, editor: Editor, next: () => void) {
const { node } = props;
editor.someCommand();
const queryResult: string = editor.someQuery();
if (node) {
switch (node.object) {
case 'block':
@@ -15,7 +36,7 @@ class MyPlugin implements Plugin {
}
}
}
renderInline(props: RenderInlineProps, editor: Controller, next: () => void) {
renderInline(props: RenderInlineProps, editor: Editor, next: () => void) {
const { node } = props;
if (node) {
switch (node.object) {
@@ -38,6 +59,7 @@ const eventPlugin: Plugin = {
onClick: (event, editor, next) => {[event.nativeEvent, event.clientX, ]; },
onCompositionEnd: (event, editor, next) => {[event.nativeEvent, event.data, ]; },
onCompositionStart: (event, editor, next) => {[event.nativeEvent, event.data, ]; },
onContextMenu: (event, editor, next) => {[event.nativeEvent, event.clientX, ]; },
onCopy: (event, editor, next) => {[event.nativeEvent, event.clipboardData, ]; },
onCut: (event, editor, next) => {[event.nativeEvent, event.clipboardData, ]; },
onDragEnd: (event, editor, next) => {[event.nativeEvent.dataTransfer, event.clientX, ]; },
+17 -16
View File
@@ -15,6 +15,7 @@
// Yuichiro Tsuchiya <https://github.com/tuttieee>
// Kamil Kamiński <https://github.com/0ctothorp>
// Jay Chen <https://github.com/Jay0328>
// Brian Ingles <https://github.com/bmingles>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
import * as Immutable from "immutable";
@@ -1457,28 +1458,28 @@ export interface Query {
args: any[];
}
export type CommandFunc = (editor: Editor, ...args: any[]) => Editor;
export type QueryFunc = (editor: Editor, ...args: any[]) => any;
export type CommandFunc<T extends Controller = Controller> = (editor: T, ...args: any[]) => T;
export type QueryFunc<T extends Controller = Controller> = (editor: T, ...args: any[]) => any;
export interface Plugin {
normalizeNode?: (node: Node, editor: Editor, next: () => void) => ((editor: Editor) => void) | void;
onChange?: (editor: Editor, next: () => void) => void;
onCommand?: (command: Command, editor: Editor, next: () => void) => void;
onConstruct?: (editor: Editor, next: () => void) => void;
onQuery?: (query: Query, editor: Editor, next: () => void) => void;
validateNode?: (node: Node, editor: Editor, next: () => void) => SlateError | void;
export interface Plugin<T extends Controller = Controller> {
normalizeNode?: (node: Node, editor: T, next: () => void) => ((editor: T) => void) | void;
onChange?: (editor: T, next: () => void) => void;
onCommand?: (command: Command, editor: T, next: () => void) => void;
onConstruct?: (editor: T, next: () => void) => void;
onQuery?: (query: Query, editor: T, next: () => void) => void;
validateNode?: (node: Node, editor: T, next: () => void) => SlateError | void;
commands?: {[name: string]: CommandFunc};
queries?: {[name: string]: QueryFunc};
commands?: {[name: string]: CommandFunc<T>};
queries?: {[name: string]: QueryFunc<T>};
schema?: SchemaProperties;
}
export interface Plugins extends Array<Plugin | Plugins> {}
export interface Plugins<T extends Controller = Controller> extends Array<Plugin<T> | Plugins<T>> {}
export interface EditorProperties {
export interface EditorProperties<T extends Controller = Controller> {
object?: "editor";
onChange?: (change: { operations: Immutable.List<Operation>; value: Value }) => void;
plugins?: Plugins;
plugins?: Plugins<T>;
readOnly?: boolean;
value?: Value;
}
@@ -1495,11 +1496,11 @@ export class Editor implements Controller {
middleware: object;
onChange: (change: { operations: Immutable.List<Operation>, value: Value }) => void;
operations: Immutable.List<Operation>;
plugins: Plugin[];
plugins: Array<Plugin<Editor>>;
readOnly: boolean;
value: Value;
constructor(attributes: EditorProperties, options?: EditorOptions);
constructor(attributes: EditorProperties<Editor>, options?: EditorOptions);
/**
* Synchronously flush the current changes to editor, calling onChange.
+43 -1
View File
@@ -1,5 +1,6 @@
import {
Block,
Controller,
Value,
Data,
BlockJSON,
@@ -108,6 +109,47 @@ const schema2: SchemaProperties = {
}
};
const pluginDefault: Plugin = {
normalizeNode: (node: Node, editor, next: () => void) => {
// $ExpectType Controller
editor;
},
onChange: (editor, next: () => void) => {
// $ExpectType Controller
editor;
},
onCommand: (command: Command, editor, next: () => void) => {
// $ExpectType Controller
editor;
},
onConstruct: (editor, next: () => void) => {
// $ExpectType Controller
editor;
},
onQuery: (query: Query, editor, next: () => void) => {
// $ExpectType Controller
editor;
},
validateNode: (node: Node, editor, next: () => void) => {
// $ExpectType Controller
editor;
},
commands: {
someCommand: (editor, ...args: any[]) => {
// $ExpectType Controller
editor;
return editor;
}
},
queries: {
someQuery: (editor, ...args: any[]) => {
// $ExpectType Controller
editor;
}
},
};
const pluginCommandName = 'plugin_command';
const pluginCommandFunc = (editor: Editor, ...args: any[]) => editor;
@@ -115,7 +157,7 @@ const pluginQueryName = 'plugin_query';
const pluginQueryResult = 1000;
const pluginQueryFunc = (editor: Editor, ...args: any[]) => pluginQueryResult;
const plugin: Plugin = {
const plugin: Plugin<Editor> = {
normalizeNode: (node: Node, editor: Editor, next: () => void) => next(),
onChange: (editor: Editor, next: () => void) => next(),
onCommand: (command: Command, editor: Editor, next: () => void) => next(),