slate-vue3 0.3.3 → 0.3.5
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 +72 -14
- package/dist/slate-yjs/hooks/useDecorateRemoteCursors.d.ts +25 -0
- package/dist/slate-yjs/hooks/useRemoteCursorStates.d.ts +2 -0
- package/dist/slate-yjs/hooks/useUnsetCursorPositionOnBlur.d.ts +2 -1
- package/dist/slate-yjs/index.d.ts +4 -3
- package/dist/yjs.js +81 -5
- package/package.json +1 -1
- package/dist/slate-yjs/hooks/useRemoteCursorStateStore.d.ts +0 -5
package/README.md
CHANGED
|
@@ -5,34 +5,36 @@
|
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<a href="https://
|
|
9
|
-
<img src="
|
|
8
|
+
<a href="https://www.npmjs.com/package/slate-vue3?activeTab=code">
|
|
9
|
+
<img src="https://img.shields.io/npm/unpacked-size/slate-vue3">
|
|
10
|
+
<img src="https://img.shields.io/bundlephobia/min/slate-vue3">
|
|
10
11
|
</a>
|
|
11
12
|
<a href="https://join.slack.com/t/slate-js/shared_invite/zt-f8t986ip-7dA1DyiqPpzootz1snKXkw">
|
|
12
13
|
<img src="https://img.shields.io/badge/slack-slate--js-brightgreen.svg?logo=slack">
|
|
13
14
|
</a>
|
|
14
|
-
<a href="./
|
|
15
|
+
<a href="./package.json">
|
|
15
16
|
<img src="https://img.shields.io/npm/v/slate-vue3.svg?maxAge=3600&label=version&colorB=007ec6">
|
|
16
17
|
</a>
|
|
17
18
|
</p>
|
|
18
19
|
<br/>
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
### Why use it?
|
|
21
22
|
|
|
22
23
|
1. :sparkles: Highly customizable features, use slate core at the bottom level
|
|
23
|
-
2. :zap: Use vue3 for high-performance rendering, and later connect to vapor mode
|
|
24
|
-
3. :coffee: The latest version of the core, design tends to be stable
|
|
25
|
-
4. :point_right: Check out the [**live demo**](https://guan-erjia.github.io/slate-vue3/examples/rich-text) of all of the examples
|
|
24
|
+
2. :zap: Use `vue3` for high-performance rendering, and later connect to vapor mode
|
|
25
|
+
3. :coffee: The **latest** version of the core, design tends to be stable
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
<br />
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
### How to use?
|
|
30
|
+
|
|
31
|
+
#### 1. Install slate-vue3
|
|
30
32
|
|
|
31
33
|
```sh
|
|
32
34
|
npm install slate-vue3
|
|
33
35
|
```
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
#### 2. Now, you can use it in vue-sfc :point_right: [**live demo**](https://guan-erjia.github.io/slate-vue3/examples/rich-text)
|
|
36
38
|
|
|
37
39
|
```vue
|
|
38
40
|
<script setup lang="ts">
|
|
@@ -71,16 +73,72 @@ editor.children = initialValue;
|
|
|
71
73
|
</template>
|
|
72
74
|
```
|
|
73
75
|
|
|
74
|
-
|
|
76
|
+
<br />
|
|
77
|
+
|
|
78
|
+
### Examples
|
|
79
|
+
|
|
80
|
+
To get a sense for how you might use Slate, check out a few of the examples:
|
|
81
|
+
|
|
82
|
+
- [**Rich text**](https://guan-erjia.github.io/slate-vue3/examples/rich-text) — the features you'd expect from a basic editor.
|
|
83
|
+
- [**Collaborative editing**](https://guan-erjia.github.io/slate-vue3/examples/remote-cursor) — to achieve collaborative editing and cursor.
|
|
84
|
+
- [**Markdown preview**](https://guan-erjia.github.io/slate-vue3/examples/markdown-preview) — to add key handlers for Markdown-like shortcuts.
|
|
85
|
+
- [**Inlines**](https://guan-erjia.github.io/slate-vue3/examples/inlines) — wrap text in inline nodes with associated data.
|
|
86
|
+
- [**Images**](https://guan-erjia.github.io/slate-vue3/examples/images) — to use void (text-less) nodes to add images.
|
|
87
|
+
- [**Hovering toolbar**](https://guan-erjia.github.io/slate-vue3/examples/hovering-toolbar) — a hovering toolbar can be implemented.
|
|
88
|
+
- [**Tables**](https://guan-erjia.github.io/slate-vue3/examples/tables) — to nest blocks to render more advanced components.
|
|
89
|
+
- [**Paste HTML**](https://guan-erjia.github.io/slate-vue3/examples/paste-html) — to use an HTML serializer to handle pasted HTML.
|
|
90
|
+
- [**Mentions**](https://guan-erjia.github.io/slate-vue3/examples/mentions) — to use inline void nodes for simple @-mentions.
|
|
91
|
+
- [**See all the examples...**](https://guan-erjia.github.io/slate-vue3)
|
|
92
|
+
|
|
93
|
+
If you have an idea for an example that shows a common use case, pull request it!
|
|
94
|
+
|
|
95
|
+
<br/>
|
|
96
|
+
|
|
97
|
+
### Documentation
|
|
98
|
+
|
|
99
|
+
This [**`document`**](https://guan-erjia.github.io/slate-vue3) serves only as a supplement to the slate document and mainly provides case studies and differences between `slate-vue3` and `slate-react`
|
|
100
|
+
|
|
101
|
+
If you're using `slate` for the first time, check out the [Getting Started](https://docs.slatejs.org/walkthroughs/01-installing-slate) walkthroughs and the [Concepts](http://docs.slatejs.org/concepts) to familiarize yourself with slate's architecture and mental models.
|
|
102
|
+
|
|
103
|
+
- [**Walkthroughs**](https://docs.slatejs.org/walkthroughs/01-installing-slate)
|
|
104
|
+
- [**Concepts**](https://docs.slatejs.org/concepts)
|
|
105
|
+
- [**FAQ**](https://docs.slatejs.org/general/faq)
|
|
106
|
+
- [**Resources**](https://docs.slatejs.org/general/resources)
|
|
107
|
+
|
|
108
|
+
<br/>
|
|
109
|
+
|
|
110
|
+
### Sub packages
|
|
111
|
+
|
|
112
|
+
Due to the complexity of maintaining multiple packages and the lack of reusability of sub packages in other frameworks, slate-vue3 does not use workspace and only performs sub packaging during packaging
|
|
113
|
+
|
|
114
|
+
| **Package** | **Version** | **Description** |
|
|
115
|
+
| :------------------------------------------------------- | --------------------------------------------------------------------------------: | :----------------------------------------------- |
|
|
116
|
+
| [`slate-vue3/core`](./packages/slate) |  | slate's core data model logic. |
|
|
117
|
+
| [`slate-vue3/dom`](./packages/slate) |  | DOM implementation of slate |
|
|
118
|
+
| [`slate-vue3/history`](./packages/slate-history) |  | a plugin that adds undo/redo history to slate. |
|
|
119
|
+
| [`slate-vue3/hyperscript`](./packages/slate-hyperscript) |  | a hyperscript tool to write JSX slate documents! |
|
|
120
|
+
| [`slate-vue3/yjs`](./packages/slate-yjs) |  | integration of `slate-yjs` |
|
|
121
|
+
|
|
122
|
+
<br />
|
|
123
|
+
|
|
124
|
+
### Contributing!
|
|
125
|
+
|
|
126
|
+
Welcome to provide suggestions on the issue, it would be even better if **`PR`** could be mentioned along with it
|
|
127
|
+
|
|
128
|
+
`slate-vue3` is [MIT-licensed](./License.md).
|
|
129
|
+
|
|
130
|
+
<br/>
|
|
131
|
+
|
|
132
|
+
### FAQ
|
|
75
133
|
|
|
76
|
-
|
|
134
|
+
##### 1. Why do I have to pass renderFunction into <Slate /> component ?
|
|
77
135
|
|
|
78
136
|
This ensures that your rich text is as expected, and slate-vue3 provides some default rendering functions, you can directly use the default rendering behavior
|
|
79
137
|
|
|
80
|
-
|
|
138
|
+
##### 2. Can I use jsx in slate-vue3 ?
|
|
81
139
|
|
|
82
140
|
Of coures yes, but we do not recommend it unless you have already configured jsx in the project, as a branch, using the h function directly is already simple enough
|
|
83
141
|
|
|
84
|
-
|
|
142
|
+
##### 3. Why do rendering functions not use vue components ?
|
|
85
143
|
|
|
86
144
|
Vue uses lazy updates, rendering with components generates additional state, which can cause unexpected results during updates, it would be better to use functions as branches directly
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BaseRange, BaseText, NodeEntry } from '../../slate/index.ts';
|
|
2
|
+
import { DOMEditor } from '../../slate-dom/index.ts';
|
|
3
|
+
import { JsonObject } from '@liveblocks/client';
|
|
4
|
+
import { CursorEditor, CursorState } from '../plugins/withCursors';
|
|
5
|
+
export declare const REMOTE_CURSOR_DECORATION_PREFIX = "remote-cursor-";
|
|
6
|
+
export declare const REMOTE_CURSOR_CARET_DECORATION_PREFIX = "remote-caret-";
|
|
7
|
+
export type RemoteCaretDecoration<TCursorData extends JsonObject = JsonObject> = {
|
|
8
|
+
[key: `${typeof REMOTE_CURSOR_CARET_DECORATION_PREFIX}${string}`]: CursorState<TCursorData> & {
|
|
9
|
+
isBackward: boolean;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export type RemoteCursorDecoration<TCursorData extends JsonObject = JsonObject> = {
|
|
13
|
+
[key: `${typeof REMOTE_CURSOR_DECORATION_PREFIX}${string}`]: CursorState<TCursorData>;
|
|
14
|
+
};
|
|
15
|
+
export type RemoteCursorDecoratedRange<TCursorData extends JsonObject = JsonObject> = BaseRange & RemoteCursorDecoration<TCursorData>;
|
|
16
|
+
export type RemoteCaretDecoratedRange<TCursorData extends JsonObject = JsonObject> = BaseRange & RemoteCaretDecoration<TCursorData>;
|
|
17
|
+
export type TextWithRemoteCursors<TCursorData extends JsonObject = JsonObject> = BaseText & RemoteCursorDecoration<TCursorData> & RemoteCaretDecoration<TCursorData>;
|
|
18
|
+
export declare function getRemoteCursorsOnLeaf<TCursorData extends JsonObject, TLeaf extends TextWithRemoteCursors<TCursorData>>(leaf: TLeaf): CursorState<TCursorData>[];
|
|
19
|
+
export declare function getRemoteCaretsOnLeaf<TCursorData extends JsonObject, TLeaf extends TextWithRemoteCursors<TCursorData>>(leaf: TLeaf): (CursorState<TCursorData> & {
|
|
20
|
+
isBackward: boolean;
|
|
21
|
+
})[];
|
|
22
|
+
export type UseDecorateRemoteCursorsOptions = {
|
|
23
|
+
carets?: boolean;
|
|
24
|
+
};
|
|
25
|
+
export declare function useDecorateRemoteCursors<TCursorData extends JsonObject = JsonObject>(editor: CursorEditor<TCursorData> & DOMEditor, carets: boolean): (entry: NodeEntry) => (RemoteCursorDecoratedRange<TCursorData> | RemoteCaretDecoratedRange<TCursorData>)[];
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Ref } from 'vue';
|
|
2
2
|
import { JsonObject } from '@liveblocks/client';
|
|
3
|
+
import { Store } from './utils';
|
|
3
4
|
import { CursorState } from '../plugins/withCursors';
|
|
5
|
+
export type CursorStore<TCursorData extends JsonObject = JsonObject> = Store<Record<string, CursorState<TCursorData>>>;
|
|
4
6
|
export declare function useRemoteCursorStates<TCursorData extends JsonObject = JsonObject>(): Ref<Record<string, CursorState<TCursorData>>>;
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import { JsonObject } from '@liveblocks/client';
|
|
2
|
+
export declare function useUnsetCursorPositionOnBlur<TCursor extends JsonObject>(): void;
|
|
@@ -2,9 +2,10 @@ import { RelativeRange } from './model/types';
|
|
|
2
2
|
import { CursorEditor, CursorState, CursorStateChangeEvent, RemoteCursorChangeEventListener, WithCursorsOptions, WithYHistoryOptions, WithYjsOptions, YHistoryEditor, withCursors, withYHistory, withYjs, YjsEditor } from './plugins';
|
|
3
3
|
import { slateNodesToInsertDelta, yTextToSlateElement } from './utils/convert';
|
|
4
4
|
import { relativePositionToSlatePoint, relativeRangeToSlateRange, slatePointToRelativePosition, slateRangeToRelativeRange } from './utils/position';
|
|
5
|
-
import { useRemoteCursorStates } from './hooks/useRemoteCursorStates';
|
|
5
|
+
import { CursorStore, useRemoteCursorStates } from './hooks/useRemoteCursorStates';
|
|
6
6
|
import { useUnsetCursorPositionOnBlur } from './hooks/useUnsetCursorPositionOnBlur';
|
|
7
7
|
import { getCursorRange } from './hooks/utils';
|
|
8
8
|
import { CursorOverlayData, useRemoteCursorOverlayPositions } from './hooks/useRemoteCursorOverlayPositions';
|
|
9
|
-
|
|
10
|
-
export {
|
|
9
|
+
import { getRemoteCaretsOnLeaf, getRemoteCursorsOnLeaf, REMOTE_CURSOR_CARET_DECORATION_PREFIX, REMOTE_CURSOR_DECORATION_PREFIX, RemoteCaretDecoratedRange, RemoteCaretDecoration, RemoteCursorDecoratedRange, RemoteCursorDecoration, TextWithRemoteCursors, useDecorateRemoteCursors, UseDecorateRemoteCursorsOptions } from './hooks/useDecorateRemoteCursors';
|
|
10
|
+
export type { WithYjsOptions, YHistoryEditor, WithYHistoryOptions, CursorState, CursorStore, CursorEditor, CursorOverlayData, WithCursorsOptions, RemoteCursorChangeEventListener, CursorStateChangeEvent, RelativeRange, UseDecorateRemoteCursorsOptions, RemoteCursorDecoration, RemoteCaretDecoration, RemoteCursorDecoratedRange, RemoteCaretDecoratedRange, TextWithRemoteCursors, };
|
|
11
|
+
export { YjsEditor, withYjs, withYHistory, withCursors, yTextToSlateElement, slateNodesToInsertDelta, slateRangeToRelativeRange, relativeRangeToSlateRange, slatePointToRelativePosition, relativePositionToSlatePoint, useRemoteCursorStates, useUnsetCursorPositionOnBlur, useRemoteCursorOverlayPositions, getCursorRange, getRemoteCursorsOnLeaf, getRemoteCaretsOnLeaf, useDecorateRemoteCursors, REMOTE_CURSOR_DECORATION_PREFIX, REMOTE_CURSOR_CARET_DECORATION_PREFIX };
|
package/dist/yjs.js
CHANGED
|
@@ -1291,7 +1291,7 @@ function withCursors(editor, awareness, {
|
|
|
1291
1291
|
return e;
|
|
1292
1292
|
}
|
|
1293
1293
|
const EDITOR_TO_CURSOR_STORE = new toRawWeakMap();
|
|
1294
|
-
function
|
|
1294
|
+
function useRemoteCursorStates() {
|
|
1295
1295
|
const editor = useEditor();
|
|
1296
1296
|
const cursors = ref({});
|
|
1297
1297
|
const changed = /* @__PURE__ */ new Set();
|
|
@@ -1319,10 +1319,6 @@ function useRemoteCursorStateStore() {
|
|
|
1319
1319
|
};
|
|
1320
1320
|
const store = [subscribe, cursors];
|
|
1321
1321
|
EDITOR_TO_CURSOR_STORE.set(editor, store);
|
|
1322
|
-
return store;
|
|
1323
|
-
}
|
|
1324
|
-
function useRemoteCursorStates() {
|
|
1325
|
-
const [subscribe, cursors] = useRemoteCursorStateStore();
|
|
1326
1322
|
let unsubscribe;
|
|
1327
1323
|
onMounted(() => {
|
|
1328
1324
|
unsubscribe = subscribe();
|
|
@@ -1531,14 +1527,94 @@ function useRemoteCursorOverlayPositions(containerRef, shouldGenerateOverlay) {
|
|
|
1531
1527
|
);
|
|
1532
1528
|
return [overlayData, refresh];
|
|
1533
1529
|
}
|
|
1530
|
+
const REMOTE_CURSOR_DECORATION_PREFIX = "remote-cursor-";
|
|
1531
|
+
const REMOTE_CURSOR_CARET_DECORATION_PREFIX = "remote-caret-";
|
|
1532
|
+
function getRemoteCursorsOnLeaf(leaf) {
|
|
1533
|
+
return Object.entries(leaf).filter(([key]) => key.startsWith(REMOTE_CURSOR_DECORATION_PREFIX)).map(([, data]) => data);
|
|
1534
|
+
}
|
|
1535
|
+
function getRemoteCaretsOnLeaf(leaf) {
|
|
1536
|
+
return Object.entries(leaf).filter(([key]) => key.startsWith(REMOTE_CURSOR_CARET_DECORATION_PREFIX)).map(([, data]) => data);
|
|
1537
|
+
}
|
|
1538
|
+
function getDecoration(clientId, state, range, caret) {
|
|
1539
|
+
if (!caret) {
|
|
1540
|
+
const key2 = `${REMOTE_CURSOR_DECORATION_PREFIX}${clientId}`;
|
|
1541
|
+
return { ...range, [key2]: state };
|
|
1542
|
+
}
|
|
1543
|
+
const key = `${REMOTE_CURSOR_CARET_DECORATION_PREFIX}${clientId}`;
|
|
1544
|
+
return {
|
|
1545
|
+
...range,
|
|
1546
|
+
anchor: range.focus,
|
|
1547
|
+
[key]: state
|
|
1548
|
+
};
|
|
1549
|
+
}
|
|
1550
|
+
function useDecorateRemoteCursors(editor, carets) {
|
|
1551
|
+
const cursors = ref({});
|
|
1552
|
+
const changed = /* @__PURE__ */ new Set();
|
|
1553
|
+
const addChanged = changed.add.bind(changed);
|
|
1554
|
+
const changeHandler = (event) => {
|
|
1555
|
+
event.added.forEach(addChanged);
|
|
1556
|
+
event.removed.forEach(addChanged);
|
|
1557
|
+
event.updated.forEach(addChanged);
|
|
1558
|
+
if (changed.size === 0) {
|
|
1559
|
+
return cursors;
|
|
1560
|
+
}
|
|
1561
|
+
changed.forEach((clientId) => {
|
|
1562
|
+
const state = CursorEditor.cursorState(editor, clientId);
|
|
1563
|
+
if (state === null) {
|
|
1564
|
+
delete cursors.value[clientId.toString()];
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1567
|
+
cursors.value[clientId] = state;
|
|
1568
|
+
});
|
|
1569
|
+
changed.clear();
|
|
1570
|
+
};
|
|
1571
|
+
const subscribe = () => {
|
|
1572
|
+
CursorEditor.on(editor, "change", changeHandler);
|
|
1573
|
+
return () => CursorEditor.off(editor, "change", changeHandler);
|
|
1574
|
+
};
|
|
1575
|
+
let unsubscribe;
|
|
1576
|
+
onMounted(() => {
|
|
1577
|
+
unsubscribe = subscribe();
|
|
1578
|
+
});
|
|
1579
|
+
onUnmounted(() => {
|
|
1580
|
+
unsubscribe == null ? void 0 : unsubscribe();
|
|
1581
|
+
});
|
|
1582
|
+
return (entry) => {
|
|
1583
|
+
const [, path] = entry;
|
|
1584
|
+
if (path.length !== 1) {
|
|
1585
|
+
return [];
|
|
1586
|
+
}
|
|
1587
|
+
return Object.entries(cursors.value).flatMap(([clientId, state]) => {
|
|
1588
|
+
const range = getCursorRange(editor, state);
|
|
1589
|
+
if (!range) {
|
|
1590
|
+
return [];
|
|
1591
|
+
}
|
|
1592
|
+
if (carets && Range.isCollapsed(range)) {
|
|
1593
|
+
return getDecoration(clientId, state, range, true);
|
|
1594
|
+
}
|
|
1595
|
+
if (!carets) {
|
|
1596
|
+
return getDecoration(clientId, state, range, false);
|
|
1597
|
+
}
|
|
1598
|
+
return [
|
|
1599
|
+
getDecoration(clientId, state, range, false),
|
|
1600
|
+
getDecoration(clientId, state, range, true)
|
|
1601
|
+
];
|
|
1602
|
+
});
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1534
1605
|
export {
|
|
1606
|
+
REMOTE_CURSOR_CARET_DECORATION_PREFIX,
|
|
1607
|
+
REMOTE_CURSOR_DECORATION_PREFIX,
|
|
1535
1608
|
YjsEditor,
|
|
1536
1609
|
getCursorRange,
|
|
1610
|
+
getRemoteCaretsOnLeaf,
|
|
1611
|
+
getRemoteCursorsOnLeaf,
|
|
1537
1612
|
relativePositionToSlatePoint,
|
|
1538
1613
|
relativeRangeToSlateRange,
|
|
1539
1614
|
slateNodesToInsertDelta,
|
|
1540
1615
|
slatePointToRelativePosition,
|
|
1541
1616
|
slateRangeToRelativeRange,
|
|
1617
|
+
useDecorateRemoteCursors,
|
|
1542
1618
|
useRemoteCursorOverlayPositions,
|
|
1543
1619
|
useRemoteCursorStates,
|
|
1544
1620
|
useUnsetCursorPositionOnBlur,
|
package/package.json
CHANGED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { JsonObject } from '@liveblocks/client';
|
|
2
|
-
import { Store } from './utils';
|
|
3
|
-
import { CursorState } from '../plugins/withCursors';
|
|
4
|
-
export type CursorStore<TCursorData extends JsonObject = JsonObject> = Store<Record<string, CursorState<TCursorData>>>;
|
|
5
|
-
export declare function useRemoteCursorStateStore<TCursorData extends JsonObject = JsonObject>(): CursorStore<TCursorData>;
|