edytor 0.1.0-next.30 → 0.1.0-next.31
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/README.md
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
Edytor aims to be for Svelte what Slate.js is for React: a heavily customizable editor with an API to build any kind of collaborative rich text editor.
|
|
17
17
|
|
|
18
|
-
> **Work in progress.** Edytor is a pre-release (`0.1.0-next.
|
|
18
|
+
> **Work in progress.** Edytor is a pre-release (`0.1.0-next.31`, `edytor@next` on npm) and not ready for production; the API changes between releases without a compatibility layer. The untagged `edytor@0.0.11` on npm predates the current API. Issues and PRs are welcome: when you report a bug, include the document's JSON value.
|
|
19
19
|
|
|
20
20
|
## Features
|
|
21
21
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import type { SerializableContent } from '../../utils/json.js';
|
|
5
5
|
import type { HotKey } from '../../session/keymap.js';
|
|
6
6
|
import {
|
|
7
|
+
pastedLink,
|
|
7
8
|
richTextOperations,
|
|
8
9
|
sanitizeLinkHref,
|
|
9
10
|
sanitizeCssColorValue,
|
|
@@ -141,6 +142,19 @@
|
|
|
141
142
|
])
|
|
142
143
|
)
|
|
143
144
|
},
|
|
145
|
+
// Pasting a link over selected text links it (Notion), where the toolbar
|
|
146
|
+
// offers a link: a text range outside code blocks and voids.
|
|
147
|
+
onPaste: ({ e, prevent }) => {
|
|
148
|
+
const { selection } = edytor;
|
|
149
|
+
const { value, projection } = selection;
|
|
150
|
+
if (value.kind !== 'text' || selection.state.isCollapsed) return;
|
|
151
|
+
if (projection.islandRoot !== null || projection.voidRoot !== null) return;
|
|
152
|
+
const href = pastedLink(e.clipboardData?.getData('text/plain'));
|
|
153
|
+
if (href)
|
|
154
|
+
prevent(() =>
|
|
155
|
+
edytor.dispatcher.run('insertFromPaste', () => operations.setLinkAtRange({ href }))
|
|
156
|
+
);
|
|
157
|
+
},
|
|
144
158
|
onBeforeInput: ({ e, prevent }) => {
|
|
145
159
|
const { inputType, data } = e;
|
|
146
160
|
if (isNativeFormatInputType(inputType)) {
|
|
@@ -24,6 +24,13 @@ export declare const sanitizeCssColorValue: (value: unknown) => string | null;
|
|
|
24
24
|
* pass through.
|
|
25
25
|
*/
|
|
26
26
|
export declare const sanitizeLinkHref: (href: unknown) => string | null;
|
|
27
|
+
/**
|
|
28
|
+
* The URL a paste carries when its plain text is one link and nothing else
|
|
29
|
+
* (surrounding whitespace aside): `http:`/`https:` with a host, or
|
|
30
|
+
* `mailto:`. `null` for anything else — words, several URLs, a bare
|
|
31
|
+
* domain, a scriptable scheme.
|
|
32
|
+
*/
|
|
33
|
+
export declare const pastedLink: (plain: string | undefined | null) => string | null;
|
|
27
34
|
export declare const richTextOperations: (edytor: Edytor) => {
|
|
28
35
|
/**
|
|
29
36
|
* Insert a `divider` void block at the caret — the native
|
|
@@ -52,6 +52,25 @@ export const sanitizeLinkHref = (href) => {
|
|
|
52
52
|
return null;
|
|
53
53
|
}
|
|
54
54
|
};
|
|
55
|
+
/**
|
|
56
|
+
* The URL a paste carries when its plain text is one link and nothing else
|
|
57
|
+
* (surrounding whitespace aside): `http:`/`https:` with a host, or
|
|
58
|
+
* `mailto:`. `null` for anything else — words, several URLs, a bare
|
|
59
|
+
* domain, a scriptable scheme.
|
|
60
|
+
*/
|
|
61
|
+
export const pastedLink = (plain) => {
|
|
62
|
+
const text = plain?.trim();
|
|
63
|
+
if (!text || /\s/.test(text))
|
|
64
|
+
return null;
|
|
65
|
+
try {
|
|
66
|
+
const url = new URL(text);
|
|
67
|
+
const web = (url.protocol === 'http:' || url.protocol === 'https:') && url.host;
|
|
68
|
+
return web || (url.protocol === 'mailto:' && url.pathname) ? sanitizeLinkHref(text) : null;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
55
74
|
const formatSelectedTextRange = (edytor, mark, value, toggle) => {
|
|
56
75
|
const { yStart, yEnd, startText, endText, isCollapsed, isReversed } = edytor.selection.state;
|
|
57
76
|
if (isCollapsed || !startText || !endText)
|