editate 0.0.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2020 inokawa
3
+ Copyright (c) 2024 inokawa
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1 +1,251 @@
1
- # editate
1
+ # editate
2
+
3
+ ![npm](https://img.shields.io/npm/v/editate) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/editate) ![npm](https://img.shields.io/npm/dw/editate) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/inokawa/editate) [![check](https://github.com/inokawa/editate/actions/workflows/check.yml/badge.svg)](https://github.com/inokawa/editate/actions/workflows/check.yml) [![demo](https://github.com/inokawa/editate/actions/workflows/demo.yml/badge.svg)](https://github.com/inokawa/editate/actions/workflows/demo.yml)
4
+
5
+ > An experimental, type-safe, framework agnostic and small (5kB+) [contenteditable](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable) state manager.
6
+
7
+ ## Motivation
8
+
9
+ Web editing is so hard even today. There are excellent libraries to make complex rich text editor, but they are too much for small purposes. Native [textarea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea) element is accessible and easy to use, but it's hardly customizable.
10
+
11
+ [contenteditable](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable) attribute is a primitive for rich text editing, [that was designed for Internet Explorer and copied by other browsers](https://blog.whatwg.org/the-road-to-html-5-contenteditable). As you may know it has [so many problems](https://github.com/grammarly/contenteditable). It has no clear spec, it has many edge case bugs, and has cross browser/OS/input device problems. And it doesn't work well with declarative frontend frameworks... However, at least the core of contenteditable is stable and it works in all browsers except the inconsistencies. This library aims to fill that gap, fix contenteditable to fit modern web development.
12
+
13
+ ## Demo
14
+
15
+ - [React Storybook](https://inokawa.github.io/editate/)
16
+ - [Framework examples](#other-examples)
17
+
18
+ ## Install
19
+
20
+ ```sh
21
+ npm install editate
22
+ ```
23
+
24
+ `typescript >=5.0` is recommended.
25
+
26
+ ### Supported browsers
27
+
28
+ Browser versions supporting [beforeinput event](https://developer.mozilla.org/en-US/docs/Web/API/Element/beforeinput_event#browser_compatibility) are supported.
29
+
30
+ Mobile browsers are also supported, but with some issues (https://github.com/inokawa/editate/issues/97).
31
+
32
+ ## Getting started
33
+
34
+ 1. Define your document as a state.
35
+ 2. Define your editor view declaratively. There are rules you have to follow:
36
+ - You must render all texts in the document as Text nodes in DOM.
37
+ - You must render `<br/>` in empty blocks (limitation of contenteditable).
38
+ - You must render hard breaks in the document as [block element](https://github.com/inokawa/editate/blob/ecd70f084f2fbb54d36bfd3b682f2dd8bbc3f547/src/dom/default.ts#L25).
39
+ - You must render void nodes in the document as [void element](https://github.com/inokawa/editate/blob/ecd70f084f2fbb54d36bfd3b682f2dd8bbc3f547/src/dom/default.ts#L47).
40
+ 3. Use `createPlainEditor`/`createEditor` to initialize `Editor` with the document.
41
+ 4. Call `Editor.input` on mount, with `HTMLElement` which is the root of editor view.
42
+ 5. Update your state with `onChange`, which will be called on edit.
43
+ 6. Call returned function from `Editor.input` on unmount for cleanup.
44
+
45
+ Here is an example for React.
46
+
47
+ ### Plain text
48
+
49
+ ```tsx
50
+ import { useState, useEffect, useRef } from "react";
51
+ import { createPlainEditor } from "editate";
52
+
53
+ export const App = () => {
54
+ const ref = useRef<HTMLDivElement>(null);
55
+ // 1. Define state
56
+ const [text, setText] = useState("Hello world.");
57
+
58
+ useEffect(() => {
59
+ // 3. init
60
+ const editor = createPlainEditor({
61
+ text: text,
62
+ onChange: (v) => {
63
+ // 5. update state
64
+ setText(v);
65
+ },
66
+ });
67
+ // 4. bind to DOM
68
+ const cleanup = editor.input(ref.current);
69
+ return () => {
70
+ // 6. cleanup DOM
71
+ cleanup();
72
+ };
73
+ }, []);
74
+
75
+ // 2. render from state
76
+ return (
77
+ <div
78
+ ref={ref}
79
+ style={{
80
+ backgroundColor: "white",
81
+ border: "solid 1px darkgray",
82
+ padding: 8,
83
+ }}
84
+ >
85
+ {text.split("\n").map((t, i) => (
86
+ <div key={i}>{t ? t : <br />}</div>
87
+ ))}
88
+ </div>
89
+ );
90
+ };
91
+ ```
92
+
93
+ ### Rich text
94
+
95
+ You can define document schema with [Standard Schema](https://github.com/standard-schema/standard-schema) for type-safe editing.
96
+
97
+ ```tsx
98
+ import { useState, useEffect, useRef, useMemo } from "react";
99
+ import { createEditor, ToggleFormat, ToggleBlockAttr } from "editate";
100
+ import * as z from "zod";
101
+
102
+ const schema = z.strictObject({
103
+ children: z.array(
104
+ z.strictObject({
105
+ align: z.enum(["left", "right"]).optional(),
106
+ children: z.array(
107
+ z.strictObject({
108
+ text: z.string(),
109
+ bold: z.boolean().optional(),
110
+ italic: z.boolean().optional(),
111
+ }),
112
+ ),
113
+ }),
114
+ ),
115
+ });
116
+
117
+ export const App = () => {
118
+ const ref = useRef<HTMLDivElement>(null);
119
+
120
+ type Doc = z.infer<typeof schema>;
121
+ const [doc, setDoc] = useState<Doc>({
122
+ children: [
123
+ {
124
+ children: [
125
+ { text: "Hello", bold: true },
126
+ { text: " " },
127
+ { text: "World", italic: true },
128
+ { text: "." },
129
+ ],
130
+ },
131
+ ],
132
+ });
133
+
134
+ const editor = useMemo(
135
+ () =>
136
+ createEditor({
137
+ doc,
138
+ schema,
139
+ onChange: setDoc,
140
+ }),
141
+ [],
142
+ );
143
+
144
+ useEffect(() => {
145
+ return editor.input(ref.current);
146
+ }, []);
147
+
148
+ return (
149
+ <div>
150
+ <div>
151
+ <button
152
+ onClick={() => {
153
+ editor.exec(ToggleFormat, "bold");
154
+ }}
155
+ >
156
+ bold
157
+ </button>
158
+ <button
159
+ onClick={() => {
160
+ editor.exec(ToggleFormat, "italic");
161
+ }}
162
+ >
163
+ italic
164
+ </button>
165
+ <button
166
+ onClick={() => {
167
+ editor.exec(ToggleBlockAttr, "align", "right", undefined);
168
+ }}
169
+ >
170
+ align
171
+ </button>
172
+ </div>
173
+ <div
174
+ ref={ref}
175
+ style={{
176
+ backgroundColor: "white",
177
+ border: "solid 1px darkgray",
178
+ padding: 8,
179
+ }}
180
+ >
181
+ {doc.children.map((b, i) => (
182
+ <div key={i} style={{ textAlign: b.align }}>
183
+ {b.children.map((n, j) => (
184
+ <span
185
+ key={j}
186
+ style={{
187
+ fontWeight: n.bold ? "bold" : undefined,
188
+ fontStyle: n.italic ? "italic" : undefined,
189
+ }}
190
+ >
191
+ {n.text || <br />}
192
+ </span>
193
+ ))}
194
+ </div>
195
+ ))}
196
+ </div>
197
+ </div>
198
+ );
199
+ };
200
+ ```
201
+
202
+ ### Other examples
203
+
204
+ - React ([Demo](https://inokawa.github.io/editate/react), [Source](./examples/react))
205
+ - Vue ([Demo](https://inokawa.github.io/editate/vue), [Source](./examples/vue))
206
+ - Svelte ([Demo](https://inokawa.github.io/editate/svelte), [Source](./examples/svelte))
207
+ - Solid ([Demo](https://inokawa.github.io/editate/solid), [Source](./examples/solid))
208
+ - Angular ([Demo](https://inokawa.github.io/editate/angular), [Source](./examples/angular))
209
+ - Preact ([Demo](https://inokawa.github.io/editate/preact), [Source](./examples/preact))
210
+ - Vanilla ([Demo](https://inokawa.github.io/editate/vanilla), [Source](./examples/vanilla))
211
+
212
+ ...and more! Contribution welcome!
213
+
214
+ ## Documentation
215
+
216
+ - [API reference](./docs/API.md)
217
+ - [Storybook examples](./stories) for more usages
218
+ - [DeepWiki](https://deepwiki.com/inokawa/editate)
219
+
220
+ ## Contribute
221
+
222
+ All contributions are welcome.
223
+ If you find a problem, feel free to create an [issue](https://github.com/inokawa/editate/issues) or a [PR](https://github.com/inokawa/editate/pulls). If you have a question, ask in [discussions](https://github.com/inokawa/editate/discussions).
224
+
225
+ ### Making a Pull Request
226
+
227
+ 1. Fork this repo.
228
+ 2. Run `npm install`.
229
+ 3. Commit your fix.
230
+ 4. Make a PR and confirm all the CI checks passed.
231
+
232
+ ## Inspirations
233
+
234
+ - [ProseMirror](https://prosemirror.net/)
235
+ - [Slate](https://github.com/ianstormtaylor/slate)
236
+ - [Lexical](https://github.com/facebook/lexical)
237
+ - [Quill](https://github.com/slab/quill)
238
+ - [Tiptap](https://github.com/ueberdosis/tiptap)
239
+ - [Draft.js](https://github.com/facebookarchive/draft-js)
240
+ - [rich-textarea](https://github.com/inokawa/rich-textarea) (my early project)
241
+ - [use-editable](https://github.com/FormidableLabs/use-editable)
242
+ - [@react-libraries/markdown-editor](https://github.com/ReactLibraries/markdown-editor)
243
+ - [VS Code](https://github.com/microsoft/vscode)
244
+ - [Language Server Protocol](https://github.com/microsoft/language-server-protocol)
245
+ - [urql](https://github.com/urql-graphql/urql)
246
+ - [TanStack DB](https://github.com/tanstack/db)
247
+ - [Hono](https://github.com/honojs/hono)
248
+ - [Textbus](https://github.com/textbus/textbus)
249
+ - [vistree](https://github.com/mizchi/vistree)
250
+ - Proposed [EditContext API](https://github.com/w3c/edit-context)
251
+ - Proposed [Richer Text Fields](https://open-ui.org/components/richer-text-fields.explainer/) in [Open UI](https://open-ui.org/)
@@ -0,0 +1,42 @@
1
+ import type { Editor } from "./editor.js";
2
+ import type { DocNode, InferBlockNode, InferInlineNode, Path, Range, TextNode } from "./doc/types.js";
3
+ /**
4
+ * Delete content in the selection or specified range.
5
+ */
6
+ export declare function Delete(editor: Editor, range?: Range): void;
7
+ /**
8
+ * Insert text at the caret or specified position.
9
+ */
10
+ export declare function InsertText(editor: Editor, text: string, position?: number): void;
11
+ /**
12
+ * Insert node at the caret or specified position.
13
+ */
14
+ export declare function InsertNode<T extends DocNode>(editor: Editor<T>, node: Exclude<InferInlineNode<T>, TextNode>, position?: number): void;
15
+ /**
16
+ * Replace text in the selection or specified range.
17
+ */
18
+ export declare function ReplaceText(editor: Editor, text: string): void;
19
+ /**
20
+ * Replace document in the editor.
21
+ */
22
+ export declare function ReplaceDoc<T extends DocNode>(editor: Editor<T>, fragment: T["children"]): void;
23
+ type ToggleableKey<T> = {
24
+ [K in keyof T]-?: T[K] extends boolean | undefined ? K : never;
25
+ }[keyof T];
26
+ /**
27
+ * Format content in the selection or specified range.
28
+ */
29
+ export declare function Format<T extends DocNode, N extends Omit<InferInlineNode<T>, "text">, K extends Extract<keyof N, string>>(editor: Editor<T>, key: K, value: N[K], range?: Range): void;
30
+ /**
31
+ * Toggle formatting in the selection or specified range.
32
+ */
33
+ export declare function ToggleFormat<T extends DocNode>(editor: Editor<T>, key: Extract<ToggleableKey<Omit<InferInlineNode<T>, "text">>, string>, range?: Range): void;
34
+ /**
35
+ * Set attr to a block node at the caret or specified position.
36
+ */
37
+ export declare function SetBlockAttr<T extends DocNode, N extends InferBlockNode<T>, K extends Extract<keyof N, string>>(editor: Editor<T>, key: K, value: N[K], path?: Path): void;
38
+ /**
39
+ * Toggle attr of block node at the caret or specified position.
40
+ */
41
+ export declare function ToggleBlockAttr<T extends DocNode, N extends InferBlockNode<T>, K extends Extract<keyof N, string>>(editor: Editor<T>, key: K, onValue: N[K], offValue: N[K], path?: Path): void;
42
+ export {};
@@ -0,0 +1,49 @@
1
+ import type { DocNode, Fragment, Path, BlockNode, Node, DomPosition } from "./types.js";
2
+ declare const OP_DELETE = "delete";
3
+ type DeleteOperation = Readonly<{
4
+ type: typeof OP_DELETE;
5
+ start: number;
6
+ end: number;
7
+ }>;
8
+ declare const OP_INSERT_TEXT = "insert_text";
9
+ type InsertTextOperation = Readonly<{
10
+ type: typeof OP_INSERT_TEXT;
11
+ at: number;
12
+ text: string;
13
+ }>;
14
+ declare const OP_INSERT_NODE = "insert_node";
15
+ type InsertNodeOperation = Readonly<{
16
+ type: typeof OP_INSERT_NODE;
17
+ at: number;
18
+ fragment: Fragment;
19
+ }>;
20
+ declare const OP_SET_ATTR = "set_attr";
21
+ type SetAttrOperation = Readonly<{
22
+ type: typeof OP_SET_ATTR;
23
+ start: number;
24
+ end: number;
25
+ key: string;
26
+ value: unknown;
27
+ }>;
28
+ declare const OP_SET_NODE_ATTR = "set_node_attr";
29
+ type SetNodeAttrOperation = Readonly<{
30
+ type: typeof OP_SET_NODE_ATTR;
31
+ path: Path;
32
+ key: string;
33
+ value: unknown;
34
+ }>;
35
+ export type Operation = DeleteOperation | InsertTextOperation | InsertNodeOperation | SetAttrOperation | SetNodeAttrOperation;
36
+ export declare class Transaction {
37
+ private readonly _ops;
38
+ constructor(ops?: readonly Operation[]);
39
+ get ops(): readonly Operation[];
40
+ insertText(at: number, text: string): this;
41
+ insertFragment(at: number, fragment: Fragment): this;
42
+ delete(start: number, end: number): this;
43
+ format(start: number, end: number, key: string, value: unknown): this;
44
+ attr(at: Path, key: string, value: unknown): this;
45
+ transform(position: number): number;
46
+ }
47
+ export declare const getNodeSize: (node: Node) => number;
48
+ export declare const offsetToPosition: (node: DocNode | BlockNode, offset: number) => DomPosition;
49
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ export interface TextNode {
2
+ readonly text: string;
3
+ }
4
+ export interface VoidNode {
5
+ }
6
+ export type InlineNode = TextNode | VoidNode;
7
+ export interface BlockNode {
8
+ readonly children: readonly InlineNode[];
9
+ }
10
+ export type Node = BlockNode | InlineNode;
11
+ export interface DocNode {
12
+ readonly children: readonly BlockNode[];
13
+ }
14
+ export type Fragment = DocNode["children"];
15
+ type InferChild<T> = T extends {
16
+ children: readonly (infer N)[];
17
+ } ? InferChild<N> : T;
18
+ type InferBlock<T> = T extends {
19
+ children: readonly (infer N)[];
20
+ } ? T & InferBlock<N> : T;
21
+ export type InferInlineNode<T extends DocNode> = InferChild<T>;
22
+ export type InferBlockNode<T extends DocNode> = InferBlock<T>;
23
+ export type Path = readonly number[];
24
+ export type DomPosition = readonly [path: Path, offset: number];
25
+ export type Range = readonly [start: number, end: number];
26
+ export type Selection = readonly [anchor: number, focus: number];
27
+ export type SelectionSnapshot = readonly [
28
+ anchor: DomPosition,
29
+ focus: DomPosition
30
+ ];
31
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export { createParser } from "./parser.js";
2
+ export { defaultIsBlockNode, defaultIsVoidNode } from "./default.js";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export type Parser = <T>(scopeFn: () => T, root?: Node, startNode?: Node) => T;
@@ -0,0 +1,107 @@
1
+ import type { StandardSchemaV1 } from "@standard-schema/spec";
2
+ import type { DocNode, Selection } from "./doc/types.js";
3
+ import { Transaction, type Operation } from "./doc/edit.js";
4
+ import { type CopyHook, type PasteHook, type KeyboardHook } from "./hooks/index.js";
5
+ type EditorCommand<A extends unknown[], T extends DocNode = DocNode> = (editor: Editor<T>, ...args: A) => void | undefined;
6
+ type EditorQuery<A extends unknown[], V, T extends DocNode = DocNode> = (editor: Editor<T>, ...args: A) => V;
7
+ /**
8
+ * Options of {@link createEditor}.
9
+ */
10
+ export interface EditorOptions<T extends DocNode, S extends StandardSchemaV1<T, T> | void = void> {
11
+ /**
12
+ * Optional [Standard Schema](https://github.com/standard-schema/standard-schema) to validate unsafe edits.
13
+ */
14
+ schema?: S;
15
+ /**
16
+ * Initial document.
17
+ */
18
+ doc: T;
19
+ /**
20
+ * The state editable or not.
21
+ */
22
+ readonly?: boolean;
23
+ /**
24
+ * Functions to handle keyboard events.
25
+ *
26
+ * Return `true` if you want to stop propagation.
27
+ */
28
+ keyboard?: KeyboardHook[];
29
+ /**
30
+ * Functions to handle copy events
31
+ * @default [plainCopy()]
32
+ */
33
+ copy?: [CopyHook, ...rest: CopyHook[]];
34
+ /**
35
+ * Functions to handle paste / drop events
36
+ * @default [plainPaste()]
37
+ */
38
+ paste?: [PasteHook, ...rest: PasteHook[]];
39
+ /**
40
+ * TODO
41
+ */
42
+ isBlock?: (node: HTMLElement) => boolean;
43
+ /**
44
+ * Callback invoked when document changes.
45
+ */
46
+ onChange: (doc: T) => void;
47
+ /**
48
+ * Callback invoked when errors happen.
49
+ *
50
+ * @default console.error
51
+ */
52
+ onError?: (message: string) => void;
53
+ }
54
+ type EditorEventMap = {
55
+ change: () => void;
56
+ selectionchange: () => void;
57
+ readonly: () => void;
58
+ };
59
+ type EditorHookMap = {
60
+ apply: (op: Operation, next: (op?: Operation) => void) => void;
61
+ mount: (element: HTMLElement) => void | (() => void);
62
+ keyboard: KeyboardHook;
63
+ };
64
+ /**
65
+ * The editor instance.
66
+ */
67
+ export interface Editor<T extends DocNode = DocNode> {
68
+ readonly doc: T;
69
+ selection: Selection;
70
+ /**
71
+ * The getter/setter for the editor's read-only state.
72
+ * `true` to read-only. `false` to editable.
73
+ */
74
+ readonly: boolean;
75
+ /**
76
+ * Dispatches editing operations.
77
+ * @param tr {@link Transaction}
78
+ */
79
+ apply(tr: Transaction): this;
80
+ /**
81
+ * Executes a function with editor bound as context.
82
+ * @param fn {@link EditorCommand} or {@link EditorQuery}
83
+ * @param args arguments of the function
84
+ */
85
+ exec<A extends unknown[]>(fn: EditorCommand<A, T>, ...args: A): this;
86
+ exec<A extends unknown[], V>(fn: EditorQuery<A, V, T>, ...args: A): V;
87
+ /**
88
+ * A function to subscribe editor events.
89
+ * @returns cleanup function
90
+ */
91
+ on<K extends keyof EditorEventMap>(key: K, callback: EditorEventMap[K]): () => void;
92
+ /**
93
+ * A function to register editor hooks.
94
+ * @returns cleanup function
95
+ */
96
+ hook<K extends keyof EditorHookMap>(key: K, callback: EditorHookMap[K]): () => void;
97
+ /**
98
+ * A function to make DOM editable.
99
+ * @returns A function to stop subscribing DOM changes and restores previous DOM state.
100
+ */
101
+ input: (element: HTMLElement) => () => void;
102
+ }
103
+ /**
104
+ * A function to initialize {@link Editor}.
105
+ */
106
+ export declare const createEditor: <T extends DocNode, S extends StandardSchemaV1<T, T> | void = void>({ doc, readonly, schema, keyboard, copy: copyHooks, paste: pasteHooks, isBlock, onChange, onError, }: EditorOptions<T, S>) => Editor<T>;
107
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { CopyHook } from "./types.js";
2
+ /**
3
+ * An extension to handle copying to HTML.
4
+ */
5
+ export declare const htmlCopy: () => CopyHook;
@@ -0,0 +1,4 @@
1
+ export { plainCopy } from "./plain.js";
2
+ export { htmlCopy } from "./html.js";
3
+ export { internalCopy } from "./internal.js";
4
+ export type { CopyHook } from "./types.js";
@@ -0,0 +1,7 @@
1
+ import type { CopyHook } from "./types.js";
2
+ /**
3
+ * An extension to handle copying to editor instance.
4
+ */
5
+ export declare const internalCopy: ({ key, }?: {
6
+ key?: string;
7
+ }) => CopyHook;
@@ -0,0 +1,6 @@
1
+ import type { DocNode, InferInlineNode } from "../../doc/types.js";
2
+ import type { CopyHook } from "./types.js";
3
+ /**
4
+ * An extension to handle copying to plain text.
5
+ */
6
+ export declare const plainCopy: <T extends DocNode>(serializer?: (node: InferInlineNode<T>) => string) => CopyHook;
@@ -0,0 +1,2 @@
1
+ import type { Fragment } from "../../doc/types.js";
2
+ export type CopyHook = (dataTransfer: DataTransfer, doc: Fragment, element: Element) => void;
@@ -0,0 +1,3 @@
1
+ export * from "./copy/index.js";
2
+ export * from "./paste/index.js";
3
+ export * from "./keyboard.js";
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Functions to handle keyboard events.
3
+ *
4
+ * Return `true` if you want to stop propagation.
5
+ */
6
+ export type KeyboardHook = (keyboard: KeyboardEvent) => boolean | void;
7
+ /**
8
+ * TODO
9
+ */
10
+ export declare const hotkey: (key: string, cb: (e: KeyboardEvent) => void, { mod, shift, alt, }?: {
11
+ mod?: boolean;
12
+ shift?: boolean;
13
+ alt?: boolean;
14
+ }) => KeyboardHook;
@@ -0,0 +1,6 @@
1
+ import type { InlineNode } from "../../doc/types.js";
2
+ import type { PasteHook } from "./types.js";
3
+ /**
4
+ * An extension to handle pasting / dropping from File.
5
+ */
6
+ export declare const filePaste: (handlerByMime: Record<string, (file: File) => InlineNode>) => PasteHook;
@@ -0,0 +1,6 @@
1
+ import type { DocNode, InferInlineNode, TextNode } from "../../doc/types.js";
2
+ import type { PasteHook } from "./types.js";
3
+ /**
4
+ * An extension to handle pasting / dropping from HTML.
5
+ */
6
+ export declare const htmlPaste: <T extends DocNode>(serializeText: (t: string) => Extract<InferInlineNode<T>, TextNode>, serializers?: ((node: HTMLElement) => Exclude<InferInlineNode<T>, TextNode> | void)[]) => PasteHook;
@@ -0,0 +1,5 @@
1
+ export { filePaste } from "./file.js";
2
+ export { plainPaste } from "./plain.js";
3
+ export { htmlPaste } from "./html.js";
4
+ export { internalPaste } from "./internal.js";
5
+ export type { PasteHook } from "./types.js";
@@ -0,0 +1,7 @@
1
+ import type { PasteHook } from "./types.js";
2
+ /**
3
+ * An extension to handle pasting / dropping from editor instance.
4
+ */
5
+ export declare const internalPaste: ({ key, }?: {
6
+ key?: string;
7
+ }) => PasteHook;
@@ -0,0 +1,5 @@
1
+ import type { PasteHook } from "./types.js";
2
+ /**
3
+ * An extension to handle pasting / dropping from plain text.
4
+ */
5
+ export declare const plainPaste: () => PasteHook;
@@ -0,0 +1,3 @@
1
+ import type { Fragment } from "../../doc/types.js";
2
+ import type { Parser } from "../../dom/parser.js";
3
+ export type PasteHook = (dataTransfer: DataTransfer, parser: Parser) => string | Fragment | null;
@@ -0,0 +1 @@
1
+ export {};