stilo-editor 0.2.1 → 0.3.1
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 +46 -1
- package/dist/action-lB2jnYNO.js +66 -0
- package/dist/content.css +9 -0
- package/dist/core/editor.d.ts +12 -2
- package/dist/index.js +1 -1
- package/dist/react/index.d.ts +5 -0
- package/dist/react/stilo-editor.d.ts +37 -0
- package/dist/react/use-stilo-editor.d.ts +15 -0
- package/dist/react.js +75 -0
- package/dist/{src-CV6pgfTS.js → src-DxTXpULc.js} +402 -392
- package/dist/style.css +9 -0
- package/dist/svelte/action.d.ts +5 -0
- package/dist/svelte/action.js +1 -0
- package/dist/svelte/editor-action.d.ts +15 -0
- package/dist/svelte/editor-with-ui-action.d.ts +35 -0
- package/dist/svelte/index.d.ts +5 -0
- package/dist/svelte/index.js +3 -0
- package/dist/svelte/stilo-editor.svelte +47 -0
- package/dist/svelte/stilo-editor.svelte.d.ts +22 -0
- package/dist/ui/components/link-popover.d.ts +4 -1
- package/dist/ui-WFNvrkbM.js +2351 -0
- package/dist/ui.js +1 -2350
- package/dist/vue/index.d.ts +5 -0
- package/dist/vue/stilo-editor.d.ts +52 -0
- package/dist/vue/use-stilo-editor.d.ts +19 -0
- package/dist/vue.js +101 -0
- package/package.json +46 -3
package/README.md
CHANGED
|
@@ -20,6 +20,9 @@
|
|
|
20
20
|
|
|
21
21
|
<p align="center">
|
|
22
22
|
<a href="https://kojak8791.github.io/stilo-editor/"><strong>Live demo</strong></a> ·
|
|
23
|
+
<a href="docs/frameworks/react.md"><strong>React</strong></a> ·
|
|
24
|
+
<a href="docs/frameworks/vue.md"><strong>Vue</strong></a> ·
|
|
25
|
+
<a href="docs/frameworks/svelte.md"><strong>Svelte</strong></a> ·
|
|
23
26
|
<a href="docs/API.md"><strong>API</strong></a> ·
|
|
24
27
|
<a href="docs/FEATURES.md"><strong>All features</strong></a>
|
|
25
28
|
</p>
|
|
@@ -76,6 +79,48 @@ document.querySelector('#undo')!.addEventListener('click', () => editor.commands
|
|
|
76
79
|
|
|
77
80
|
Commands, button states and events: [API reference](docs/API.md).
|
|
78
81
|
|
|
82
|
+
### React
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
import 'stilo-editor/style.css';
|
|
86
|
+
import { StiloEditor } from 'stilo-editor/react';
|
|
87
|
+
|
|
88
|
+
<StiloEditor content="<p>Hello</p>" onInput={({ editor }) => save(editor.getHTML())} />;
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
React 18 and 19, server-side rendering included; `useStiloEditor` for your own UI:
|
|
92
|
+
[React guide](docs/frameworks/react.md).
|
|
93
|
+
|
|
94
|
+
### Vue
|
|
95
|
+
|
|
96
|
+
```vue
|
|
97
|
+
<script setup>
|
|
98
|
+
import 'stilo-editor/style.css';
|
|
99
|
+
import { StiloEditor } from 'stilo-editor/vue';
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<template>
|
|
103
|
+
<StiloEditor content="<p>Hello</p>" @input="({ editor }) => save(editor.getHTML())" />
|
|
104
|
+
</template>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Vue 3.4 and later, server-side rendering included; `useStiloEditor` for your own UI:
|
|
108
|
+
[Vue guide](docs/frameworks/vue.md).
|
|
109
|
+
|
|
110
|
+
### Svelte
|
|
111
|
+
|
|
112
|
+
```svelte
|
|
113
|
+
<script>
|
|
114
|
+
import 'stilo-editor/style.css';
|
|
115
|
+
import { StiloEditor } from 'stilo-editor/svelte';
|
|
116
|
+
</script>
|
|
117
|
+
|
|
118
|
+
<StiloEditor content="<p>Hello</p>" oninput={({ editor }) => save(editor.getHTML())} />
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
A component for Svelte 5, actions for Svelte 4 and 5, server-side rendering included:
|
|
122
|
+
[Svelte guide](docs/frameworks/svelte.md).
|
|
123
|
+
|
|
79
124
|
## What's included
|
|
80
125
|
|
|
81
126
|
- **Text:** bold, italic, underline, strikethrough, code, sub/superscript, fonts, sizes,
|
|
@@ -104,7 +149,7 @@ from the keyboard alone. Every feature, shortcut and option: [All features](docs
|
|
|
104
149
|
|
|
105
150
|
`0.x` preview: it works, but APIs may change in minor versions until `1.0.0`.
|
|
106
151
|
Read the [changelog](CHANGELOG.md) before updating.
|
|
107
|
-
Next:
|
|
152
|
+
Next: real-time collaboration ([roadmap](docs/SPEC.md)).
|
|
108
153
|
|
|
109
154
|
## Contributing
|
|
110
155
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Q as e, t } from "./src-DxTXpULc.js";
|
|
2
|
+
import { h as n, t as r } from "./ui-WFNvrkbM.js";
|
|
3
|
+
//#region src/svelte/editor-action.ts
|
|
4
|
+
function i(t, n) {
|
|
5
|
+
let { onready: r, ...i } = n, o = new e({
|
|
6
|
+
...i,
|
|
7
|
+
element: t
|
|
8
|
+
});
|
|
9
|
+
return r?.(o), {
|
|
10
|
+
update: (e) => a(o, e.editable),
|
|
11
|
+
destroy: () => o.destroy()
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function a(e, t) {
|
|
15
|
+
let n = t ?? !0;
|
|
16
|
+
e.isEditable !== n && e.setEditable(n);
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/svelte/editor-with-ui-action.ts
|
|
20
|
+
var o = {
|
|
21
|
+
input: "oninput",
|
|
22
|
+
selectionchange: "onselectionchange",
|
|
23
|
+
transaction: "ontransaction",
|
|
24
|
+
focus: "onfocus",
|
|
25
|
+
blur: "onblur"
|
|
26
|
+
};
|
|
27
|
+
function s(i, s = {}) {
|
|
28
|
+
let u = s, { extensions: d = [t()], toolbar: f = !0, statusBar: p = !1, messages: m, onready: h, ...g } = s, _ = f ? c(i) : null, v = c(i), y = p ? c(i) : null, b = new e({
|
|
29
|
+
...g,
|
|
30
|
+
extensions: d,
|
|
31
|
+
element: v
|
|
32
|
+
});
|
|
33
|
+
_ && r(b, {
|
|
34
|
+
...f === !0 ? {} : f,
|
|
35
|
+
container: _,
|
|
36
|
+
messages: m
|
|
37
|
+
}), y && n(b, {
|
|
38
|
+
container: y,
|
|
39
|
+
messages: m
|
|
40
|
+
});
|
|
41
|
+
for (let e of Object.keys(o)) l(b, e, () => u);
|
|
42
|
+
return h?.(b), {
|
|
43
|
+
update: (e) => {
|
|
44
|
+
u = e, a(b, e.editable);
|
|
45
|
+
},
|
|
46
|
+
destroy: () => {
|
|
47
|
+
b.destroy();
|
|
48
|
+
for (let e of [
|
|
49
|
+
_,
|
|
50
|
+
v,
|
|
51
|
+
y
|
|
52
|
+
]) e?.remove();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function c(e) {
|
|
57
|
+
return e.appendChild(document.createElement("div"));
|
|
58
|
+
}
|
|
59
|
+
function l(e, t, n) {
|
|
60
|
+
e.on(t, (e) => {
|
|
61
|
+
let r = n()[o[t]];
|
|
62
|
+
r?.(e);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
export { i as n, s as t };
|
package/dist/content.css
CHANGED
|
@@ -152,6 +152,15 @@ li.ProseMirror-selectednode:after {
|
|
|
152
152
|
|
|
153
153
|
/* Stilo content defaults */
|
|
154
154
|
|
|
155
|
+
/*
|
|
156
|
+
* The editable area gets some room around the text and a visible height when empty.
|
|
157
|
+
* `:where()` has no specificity, so any rule of the page replaces these values.
|
|
158
|
+
*/
|
|
159
|
+
:where(.stilo-content.ProseMirror) {
|
|
160
|
+
min-height: 6em;
|
|
161
|
+
padding: 12px 16px;
|
|
162
|
+
}
|
|
163
|
+
|
|
155
164
|
/* Lists: list items hold paragraphs, which must not add their own margins. */
|
|
156
165
|
.stilo-content ul,
|
|
157
166
|
.stilo-content ol {
|
package/dist/core/editor.d.ts
CHANGED
|
@@ -94,7 +94,10 @@ export declare class Editor {
|
|
|
94
94
|
* the name is unknown.
|
|
95
95
|
*/
|
|
96
96
|
getAttributes(name: string): Record<string, unknown>;
|
|
97
|
-
/**
|
|
97
|
+
/**
|
|
98
|
+
* Switches read-only mode on/off. A change dispatches an empty transaction, so the UIs that
|
|
99
|
+
* refresh on `transaction` follow it.
|
|
100
|
+
*/
|
|
98
101
|
setEditable(editable: boolean): void;
|
|
99
102
|
/** Focuses the editor; optionally moves the cursor to the start or end of the document. */
|
|
100
103
|
focus(position?: 'start' | 'end'): void;
|
|
@@ -107,8 +110,15 @@ export declare class Editor {
|
|
|
107
110
|
/** Emits `destroy`, destroys the view, removes all handlers. Calling it twice is a no-op. */
|
|
108
111
|
destroy(): void;
|
|
109
112
|
private createState;
|
|
110
|
-
/** Builds `commands` from the extension commands; `can`
|
|
113
|
+
/** Builds `commands` from the extension commands; `can` does not apply them. */
|
|
111
114
|
private createRunners;
|
|
115
|
+
/**
|
|
116
|
+
* Runs `command`, or only tells whether it would apply. In read-only mode a command that
|
|
117
|
+
* changes the document or the stored marks does not apply and returns `false`; the others
|
|
118
|
+
* (selection, search) do. To know, the command builds its transaction: `can` costs as much
|
|
119
|
+
* as a run there.
|
|
120
|
+
*/
|
|
121
|
+
private runCommand;
|
|
112
122
|
private setContent;
|
|
113
123
|
/**
|
|
114
124
|
* Removes the DOM selection when it lies inside the editor. Replacing many nodes while the
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { B as Blockquote, z as Bold, R as BulletList, L as ClearFormatting, I as Code, F as CodeBlock, X as DEFAULT_PRIORITY, P as Document, N as DropCursor, Q as Editor, M as GapCursor, j as HardBreak, A as Heading, k as Highlight, O as History, D as HorizontalRule, E as Image, T as Italic, w as LineHeight, C as Link, S as ListItem, x as MoveBlock, b as OrderedList, y as Paragraph, v as Placeholder, g as Search, nt as StiloError, h as Strike, m as Subscript, p as Superscript, d as Table, u as TaskItem, l as TaskList, c as Text, s as TextAlign, o as TextCase, r as TextStyle, n as Underline, $ as attrsMatch, t as defaultExtensions, Z as defineExtension, i as getFontSize, _ as getSearchResults, f as getTableHeaders, V as getWordCount, U as insertBlock, W as insertBlockNode, et as isMarkActive, tt as isNodeActive, Y as markInputRule, G as setMark, H as textDecorationRules, a as toFontSize, J as toggleList, K as toggleMark, q as unsetMark } from "./src-
|
|
1
|
+
export { B as Blockquote, z as Bold, R as BulletList, L as ClearFormatting, I as Code, F as CodeBlock, X as DEFAULT_PRIORITY, P as Document, N as DropCursor, Q as Editor, M as GapCursor, j as HardBreak, A as Heading, k as Highlight, O as History, D as HorizontalRule, E as Image, T as Italic, w as LineHeight, C as Link, S as ListItem, x as MoveBlock, b as OrderedList, y as Paragraph, v as Placeholder, g as Search, nt as StiloError, h as Strike, m as Subscript, p as Superscript, d as Table, u as TaskItem, l as TaskList, c as Text, s as TextAlign, o as TextCase, r as TextStyle, n as Underline, $ as attrsMatch, t as defaultExtensions, Z as defineExtension, i as getFontSize, _ as getSearchResults, f as getTableHeaders, V as getWordCount, U as insertBlock, W as insertBlockNode, et as isMarkActive, tt as isNodeActive, Y as markInputRule, G as setMark, H as textDecorationRules, a as toFontSize, J as toggleList, K as toggleMark, q as unsetMark } from "./src-DxTXpULc.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Public API of the Stilo React wrapper. */
|
|
2
|
+
/** The editor with the default UI. */
|
|
3
|
+
export { StiloEditor, type StiloEditorEventProps, type StiloEditorProps } from './stilo-editor';
|
|
4
|
+
/** The editor alone, for a custom UI. */
|
|
5
|
+
export { type UseStiloEditorOptions, type UseStiloEditorResult, useStiloEditor, } from './use-stilo-editor';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type ReactElement } from 'react';
|
|
2
|
+
import { type Editor, type EditorEvents, type EditorOptions, type EventHandler } from '../index';
|
|
3
|
+
import { type Messages, type ToolbarOptions } from '../ui/index';
|
|
4
|
+
/** Editor events forwarded to the props of {@link StiloEditor}. */
|
|
5
|
+
declare const EVENT_PROPS: {
|
|
6
|
+
readonly input: 'onInput';
|
|
7
|
+
readonly selectionchange: 'onSelectionChange';
|
|
8
|
+
readonly transaction: 'onTransaction';
|
|
9
|
+
readonly focus: 'onFocus';
|
|
10
|
+
readonly blur: 'onBlur';
|
|
11
|
+
};
|
|
12
|
+
type ForwardedEvent = keyof typeof EVENT_PROPS;
|
|
13
|
+
/** Event props of {@link StiloEditor}: `onInput` for `input`, and so on. */
|
|
14
|
+
export type StiloEditorEventProps = {
|
|
15
|
+
[E in ForwardedEvent as (typeof EVENT_PROPS)[E]]?: EventHandler<EditorEvents[E]>;
|
|
16
|
+
};
|
|
17
|
+
/** Props of {@link StiloEditor}. */
|
|
18
|
+
export interface StiloEditorProps extends Omit<EditorOptions, 'element' | 'extensions'>, StiloEditorEventProps {
|
|
19
|
+
/** Extensions to load. Default: `[defaultExtensions()]`. */
|
|
20
|
+
extensions?: EditorOptions['extensions'];
|
|
21
|
+
/** The default toolbar: `true` (default), `false`, or its options without `container`. */
|
|
22
|
+
toolbar?: boolean | Omit<ToolbarOptions, 'container' | 'messages'>;
|
|
23
|
+
/** The status bar with the word and character count, under the editor. Default: `false`. */
|
|
24
|
+
statusBar?: boolean;
|
|
25
|
+
/** Strings of the toolbar and the status bar. Default: `en`. */
|
|
26
|
+
messages?: Messages;
|
|
27
|
+
/** Class of the element that holds the toolbar, the editor and the status bar. */
|
|
28
|
+
className?: string;
|
|
29
|
+
/** Called once the editor is created, with the editor. */
|
|
30
|
+
onReady?: (editor: Editor) => void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The editor with the default UI. The props are read once, when the editor is created, except
|
|
34
|
+
* `editable` and the event handlers, which follow their changes.
|
|
35
|
+
*/
|
|
36
|
+
export declare function StiloEditor(props: StiloEditorProps): ReactElement;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Editor, type EditorOptions } from '../index';
|
|
2
|
+
/** Options of {@link useStiloEditor}: the editor options without `element`. */
|
|
3
|
+
export type UseStiloEditorOptions = Omit<EditorOptions, 'element'>;
|
|
4
|
+
/** What {@link useStiloEditor} returns. */
|
|
5
|
+
export interface UseStiloEditorResult {
|
|
6
|
+
/** Ref of the element that holds the editor. */
|
|
7
|
+
ref: (element: HTMLElement | null) => void;
|
|
8
|
+
/** The editor; `null` before the element is mounted, on the server and after unmount. */
|
|
9
|
+
editor: Editor | null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Creates an editor inside the element that gets `ref` and destroys it when the element goes.
|
|
13
|
+
* The options are read once, when the editor is created; only `editable` follows its changes.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useStiloEditor(options: UseStiloEditorOptions): UseStiloEditorResult;
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Q as e, t } from "./src-DxTXpULc.js";
|
|
3
|
+
import { h as n, t as r } from "./ui-WFNvrkbM.js";
|
|
4
|
+
import { createElement as i, useEffect as a, useRef as o, useState as s } from "react";
|
|
5
|
+
//#region src/react/use-stilo-editor.ts
|
|
6
|
+
function c(t) {
|
|
7
|
+
let [n, r] = s(null), [i, c] = s(null), l = o(t);
|
|
8
|
+
a(() => {
|
|
9
|
+
if (!n) return;
|
|
10
|
+
let t = new e({
|
|
11
|
+
...l.current,
|
|
12
|
+
element: n
|
|
13
|
+
});
|
|
14
|
+
return c(t), () => {
|
|
15
|
+
t.destroy(), c(null);
|
|
16
|
+
};
|
|
17
|
+
}, [n]);
|
|
18
|
+
let u = t.editable ?? !0;
|
|
19
|
+
return a(() => {
|
|
20
|
+
i && !i.isDestroyed && i.isEditable !== u && i.setEditable(u);
|
|
21
|
+
}, [i, u]), {
|
|
22
|
+
ref: r,
|
|
23
|
+
editor: i
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/react/stilo-editor.ts
|
|
28
|
+
var l = {
|
|
29
|
+
input: "onInput",
|
|
30
|
+
selectionchange: "onSelectionChange",
|
|
31
|
+
transaction: "onTransaction",
|
|
32
|
+
focus: "onFocus",
|
|
33
|
+
blur: "onBlur"
|
|
34
|
+
};
|
|
35
|
+
function u(e) {
|
|
36
|
+
let [u] = s(() => ({
|
|
37
|
+
extensions: e.extensions ?? [t()],
|
|
38
|
+
toolbar: e.toolbar ?? !0,
|
|
39
|
+
statusBar: e.statusBar ?? !1,
|
|
40
|
+
messages: e.messages
|
|
41
|
+
})), { ref: f, editor: p } = c({
|
|
42
|
+
...e,
|
|
43
|
+
extensions: u.extensions
|
|
44
|
+
}), m = o(null), h = o(null), g = o(e);
|
|
45
|
+
return a(() => {
|
|
46
|
+
g.current = e;
|
|
47
|
+
}), a(() => {
|
|
48
|
+
if (!p || p.isDestroyed) return;
|
|
49
|
+
let { toolbar: e, statusBar: t, messages: i } = u, a, o;
|
|
50
|
+
e && m.current && (a = r(p, {
|
|
51
|
+
...e === !0 ? {} : e,
|
|
52
|
+
container: m.current,
|
|
53
|
+
messages: i
|
|
54
|
+
})), t && h.current && (o = n(p, {
|
|
55
|
+
container: h.current,
|
|
56
|
+
messages: i
|
|
57
|
+
}));
|
|
58
|
+
let s = Object.keys(l).map((e) => d(p, e, g));
|
|
59
|
+
return g.current.onReady?.(p), () => {
|
|
60
|
+
if (!p.isDestroyed) {
|
|
61
|
+
a?.destroy(), o?.destroy();
|
|
62
|
+
for (let e of s) e();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}, [p, u]), i("div", { className: e.className }, u.toolbar ? i("div", { ref: m }) : null, i("div", { ref: f }), u.statusBar ? i("div", { ref: h }) : null);
|
|
66
|
+
}
|
|
67
|
+
function d(e, t, n) {
|
|
68
|
+
let r = (e) => {
|
|
69
|
+
let r = n.current[l[t]];
|
|
70
|
+
r?.(e);
|
|
71
|
+
};
|
|
72
|
+
return e.on(t, r), () => e.off(t, r);
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
75
|
+
export { u as StiloEditor, c as useStiloEditor };
|