edytor 0.0.7 → 0.0.9

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.
Files changed (109) hide show
  1. package/README.md +225 -5
  2. package/dist/block/block.svelte.d.ts +123 -0
  3. package/dist/block/block.svelte.js +430 -0
  4. package/dist/block/block.utils.d.ts +82 -0
  5. package/dist/block/block.utils.js +499 -0
  6. package/dist/block/content.svelte.d.ts +14 -0
  7. package/dist/block/content.svelte.js +40 -0
  8. package/dist/block/inlineBlock.svelte.d.ts +30 -0
  9. package/dist/block/inlineBlock.svelte.js +53 -0
  10. package/dist/components/Block.svelte +27 -0
  11. package/dist/components/Block.svelte.d.ts +7 -0
  12. package/dist/components/Content.svelte +44 -0
  13. package/dist/components/Content.svelte.d.ts +7 -0
  14. package/dist/components/Edytor.svelte +165 -0
  15. package/dist/components/Edytor.svelte.d.ts +33 -0
  16. package/dist/components/InlineBlock.svelte +17 -0
  17. package/dist/components/InlineBlock.svelte.d.ts +7 -0
  18. package/dist/components/Mark.svelte +38 -0
  19. package/dist/components/Mark.svelte.d.ts +11 -0
  20. package/dist/components/ReadonlyEditor.svelte +46 -0
  21. package/dist/components/ReadonlyEditor.svelte.d.ts +4 -0
  22. package/dist/components/Text.svelte +37 -0
  23. package/dist/components/Text.svelte.d.ts +7 -0
  24. package/dist/components/readonlyElements.svelte.d.ts +82 -0
  25. package/dist/components/readonlyElements.svelte.js +144 -0
  26. package/dist/constants.d.ts +4 -0
  27. package/dist/constants.js +4 -0
  28. package/dist/dnd.svelte.d.ts +17 -0
  29. package/dist/dnd.svelte.js +125 -0
  30. package/dist/edytor.svelte.d.ts +94 -0
  31. package/dist/edytor.svelte.js +262 -0
  32. package/dist/edytor.utils.d.ts +3 -0
  33. package/dist/edytor.utils.js +78 -0
  34. package/dist/events/onBeforeInput.d.ts +2 -2
  35. package/dist/events/onBeforeInput.js +338 -0
  36. package/dist/events/onKeyDown.d.ts +2 -69
  37. package/dist/events/onKeyDown.js +18 -0
  38. package/dist/hotkeys.d.ts +27 -0
  39. package/dist/hotkeys.js +282 -0
  40. package/dist/index.d.ts +7 -5
  41. package/dist/index.js +7 -8
  42. package/dist/localProvider.d.ts +82 -0
  43. package/dist/localProvider.js +267 -0
  44. package/dist/plugins/arrowMove/arrowMove.d.ts +2 -0
  45. package/dist/plugins/arrowMove/arrowMove.js +66 -0
  46. package/dist/plugins/code/CodePlugin.svelte +218 -0
  47. package/dist/plugins/code/CodePlugin.svelte.d.ts +23 -0
  48. package/dist/plugins/code/prism.css +141 -0
  49. package/dist/plugins/image/ImagePlugin.svelte +22 -0
  50. package/dist/plugins/image/ImagePlugin.svelte.d.ts +20 -0
  51. package/dist/plugins/index.d.ts +3 -0
  52. package/dist/plugins/index.js +3 -0
  53. package/dist/plugins/mention/MentionPlugin.svelte +40 -0
  54. package/dist/plugins/mention/MentionPlugin.svelte.d.ts +20 -0
  55. package/dist/plugins/richtext/RichTextPlugin.svelte +241 -0
  56. package/dist/plugins/richtext/RichTextPlugin.svelte.d.ts +26 -0
  57. package/dist/plugins.d.ts +202 -0
  58. package/dist/plugins.js +19 -0
  59. package/dist/selection/selection.svelte.d.ts +68 -0
  60. package/dist/selection/selection.svelte.js +391 -0
  61. package/dist/selection/selection.utils.d.ts +14 -0
  62. package/dist/selection/selection.utils.js +153 -0
  63. package/dist/text/deltas.d.ts +11 -0
  64. package/dist/text/deltas.js +109 -0
  65. package/dist/text/text.svelte.d.ts +70 -0
  66. package/dist/text/text.svelte.js +119 -0
  67. package/dist/text/text.utils.d.ts +40 -0
  68. package/dist/text/text.utils.js +174 -0
  69. package/dist/utils/json.d.ts +32 -0
  70. package/dist/utils/json.js +2 -0
  71. package/dist/utils/jsx.d.ts +25 -0
  72. package/dist/utils/jsx.js +66 -0
  73. package/dist/utils/serialize.d.ts +1 -0
  74. package/dist/utils/serialize.js +1 -0
  75. package/dist/utils.d.ts +6 -0
  76. package/dist/utils.js +19 -0
  77. package/package.json +81 -33
  78. package/dist/edytor.cjs.development.js +0 -1762
  79. package/dist/edytor.cjs.development.js.map +0 -1
  80. package/dist/edytor.cjs.production.min.js +0 -2
  81. package/dist/edytor.cjs.production.min.js.map +0 -1
  82. package/dist/edytor.esm.js +0 -1691
  83. package/dist/edytor.esm.js.map +0 -1
  84. package/dist/events/index.d.ts +0 -3
  85. package/dist/events/onDrop.d.ts +0 -3
  86. package/dist/operations/deleteText.d.ts +0 -7
  87. package/dist/operations/formatText.d.ts +0 -20
  88. package/dist/operations/index.d.ts +0 -9
  89. package/dist/operations/insertText.d.ts +0 -5
  90. package/dist/operations/merge.d.ts +0 -3
  91. package/dist/operations/moveNode.d.ts +0 -12
  92. package/dist/operations/nestNode.d.ts +0 -2
  93. package/dist/operations/removeEmptyText.d.ts +0 -2
  94. package/dist/operations/splitLeaf.d.ts +0 -2
  95. package/dist/operations/splitNode.d.ts +0 -9
  96. package/dist/types.d.ts +0 -140
  97. package/dist/utils/common.d.ts +0 -17
  98. package/dist/utils/dropper.d.ts +0 -26
  99. package/dist/utils/index.d.ts +0 -6
  100. package/dist/utils/leaves.d.ts +0 -34
  101. package/dist/utils/nodes.d.ts +0 -14
  102. package/dist/utils/selection.d.ts +0 -51
  103. package/dist/utils/yClasses/EdytorDoc.d.ts +0 -16
  104. package/dist/utils/yClasses/index.d.ts +0 -3
  105. package/dist/utils/yClasses/yLeaf.d.ts +0 -7
  106. package/dist/utils/yClasses/yNode.d.ts +0 -12
  107. package/dist/yjs/index.d.ts +0 -1
  108. package/dist/yjs/wsProvider.d.ts +0 -1
  109. package/index.ts +0 -1
package/README.md CHANGED
@@ -1,11 +1,231 @@
1
- # `edytor`
1
+ <div align="center">
2
+ <img src="cover.jpg" alt="Edytor Logo" width="60%"/>
2
3
 
3
- > TODO: description
4
+ <p>A powerful, extensible rich text editor built with Svelte and Y.js</p>
4
5
 
5
- ## Usage
6
+ [![npm version](https://badge.fury.io/js/edytor.svg)](https://badge.fury.io/js/edytor)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com)
9
+ [![Svelte v5](https://img.shields.io/badge/Svelte-v5-FF3E00.svg)](https://svelte.dev)
10
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0-blue.svg)](https://www.typescriptlang.org/)
6
11
 
12
+ <p>
13
+ <a href="#features">Features</a> •
14
+ <a href="#quick-start">Quick Start</a> •
15
+ </p>
16
+ </div>
17
+
18
+ Edytor aims to be the premier rich text editor for Svelte, providing the same level of power, flexibility and extensibility that Slate.js offers for React. Like Slate.js, Edytor strives to be heavily customizable and provide a powerful API to build any kind of collaborative rich text editor.
19
+
20
+ ## ⚠️ Work in progress
21
+
22
+ Edytor is currently in the early stages of development. It is not yet ready for production use.
23
+ I welcome early contributors to help us build a better editor for Svelte.
24
+ Just run it, see what you can do with it, and open issues or PRs.
25
+
26
+ If you want to submit an issue please share the json value of the document. It will help understand and fix the issue.
27
+
28
+ ## ✨ Features
29
+
30
+ - 📑 **Customizable with snippets**: Use snippets to render your own blocks and marks
31
+ - 🎨 **Rich Text Formatting**: Full support for marks, blocks and inline blocks.
32
+ - 🤝 **Real-time Collaboration**: Uses Y.js as data store, collaborative editing is built-in
33
+ - 🔌 **Plugin System**: Extensible architecture for custom features. I try to make every action performed by the editor hackable and preventable to let you build your own features.
34
+ - ⚡ **High Performance**: Optimized for large documents, fine grained update at the leaf level thanks to Y.js and Svelte's reactivity
35
+ - 🔄 **Undo/Redo**: Built-in history management
36
+ - 📦 **Lightweight**: Relatively small bundle size compared to other rich text editors
37
+ - 📦 **AI copilot ready**: Support inline text suggestions for ai completions.
38
+
39
+ ## ✨ Things that are ready
40
+
41
+ - [x] YJS backed editing
42
+ - [x] Basic block operations and text operations.
43
+ - [x] Stable data structure
44
+ - [x] Undo/Redo
45
+ - [x] Rich text formatting
46
+ - [x] Customizable with snippets
47
+ - [x] Plugin system
48
+ - [x] Text suggestions
49
+ - [x] Inline blocks
50
+ - [x] Nesting
51
+ - [x] Selection + movable blocks
52
+ - [x] Content transformation
53
+ - [x] Content normalization
54
+ - [x] Island blocks
55
+ - [x] Customizable hotkeys
56
+ - [x] Void elements and editable void elements
57
+ - [x] Text spanning deletion
58
+ - [x] Block spanning deletion.
59
+ - [x] Readable JSON data structure
60
+ - [x] Readonly edytor to lightweightly render static content without the Y.js extra works.
61
+
62
+ ## ✨ Things that are not ready
63
+
64
+ - [ ] DND
65
+ - [ ] Battle tested collaborative editing + awareness + providers
66
+ - [ ] Children normalization
67
+ - [ ] Children transformation
68
+ - [ ] Block suggestions
69
+ - [ ] Reactive data (inline)block properties with syncrostate.
70
+
71
+ ## 🧠 Concepts
72
+
73
+ Edytor structure is built around this key concepts:
74
+
75
+ - **Blocks**: Container elements like paragraphs, headings, and lists
76
+ - **Content**: The content of a block is an array of inlines blocks or text and marks.
77
+ - **Children**: Children are the blocks that are directly inside a block. They allow an infinite nesting.
78
+ - **Marks**: Texts are simply text with marks that define the formatting.
79
+ - **Inline blocks**: Inline blocks are inline elements that are no editable and render custom components like footnotes, equations, etc.
80
+
81
+ Schematic example of a document:
82
+ (content and children are not dom element, i put them here to help you understand the structure)
83
+
84
+ ```html
85
+ <root>
86
+ <block>
87
+ <content>
88
+ <text mark="bold">Hello</text>
89
+ <text>World</text>
90
+ <inline-block type="footnote">
91
+ <!-- Inline block are rendered by the user code -->
92
+ </inline-block>
93
+ </content>
94
+ <children>
95
+ <nested-block>
96
+ <content>
97
+ <text>World</text>
98
+ </content>
99
+ </nested-block>
100
+ <nested-block>
101
+ <content>
102
+ <text>World</text>
103
+ </content>
104
+ <children>
105
+ <nested-block>
106
+ <content>
107
+ <text>World</text>
108
+ </content>
109
+ </nested-block>
110
+ </children>
111
+ </nested-block>
112
+ </children>
113
+ </block>
114
+ </root>
7
115
  ```
8
- const edytor = require('edytor');
9
116
 
10
- // TODO: DEMONSTRATE API
117
+ ### Blocks
118
+
119
+ Blocks are the container elements like paragraphs, headings, and lists.
120
+ They have a content that is an array of inlines blocks or text.
121
+ They may have children that is an array of nested-blocks.
122
+ Blocks can be nested unless they are void or inside an island
123
+
124
+ An island is a block that is editable but is structuraly stable and isolated from the rest of the document.
125
+ It is impossible to merge an island with another block. It is also impossible to move another block inside an island.
126
+ You may think of an island as a block that is editable but is not completely part of the document structure and isolated from the rest of the document.
127
+
128
+ A void block is a block which does not have children or whose children are not editable and rendered outside of the edytor core logic.
129
+ Void blocks can render and edit their content anyway. That is usefull to render caption.
130
+ You may think of a void block as a block that is completely independent from the rest of the document.
131
+ Void blocks acts also like an island but are even less editables.
132
+
133
+ ### Text
134
+
135
+ Text is the basic text element that is rendered by the editor. At is core it is a Y.js text with any formatting attributes you want.
136
+
137
+ ### Inlines Block
138
+
139
+ Inlines are inline blocks, useful to render custom components like footnotes, equations, etc.
140
+ They are rendered by the user code and are not editable nor focusable.
141
+ They have a data property
142
+
143
+ ## 🚀 Quick Start
144
+
145
+ ### Installation (not published yet)
146
+
147
+ ```bash
148
+ npm install edytor
149
+ # or
150
+ yarn add edytor
151
+ # or
152
+ pnpm add edytor
153
+ ```
154
+
155
+ ### Basic Usage
156
+
157
+ ```svelte
158
+ <script>
159
+ import { Edytor } from 'edytor';
160
+
161
+ let value = {
162
+ children: [
163
+ {
164
+ type: 'paragraph',
165
+ content: [{ text: 'Hello, World!' }]
166
+ }
167
+ ]
168
+ };
169
+
170
+ function onChange(newValue) {
171
+ console.log('Document changed:', newValue);
172
+ }
173
+ </script>
174
+
175
+ <Edytor {value} {onChange} />
176
+ ```
177
+
178
+ ## Testing
179
+
180
+ I'm welcome to any contribution to improve the testing.
181
+ In the end, every block operation should be tested.
182
+ I've implemented a custom jsx parser to simplify testing the editor.
183
+
184
+ So instead of defining the value as a json object, you can define the value as a jsx element.
185
+
186
+ ```html
187
+ <root>
188
+ <paragraph>Hello, World!</paragraph>
189
+ </root>
190
+ ```
191
+
192
+ is the same as
193
+
194
+ ```json
195
+ {
196
+ "type": "root",
197
+ "children": [{ "type": "paragraph", "content": [{ "text": "Hello, World!" }] }]
198
+ }
199
+ ```
200
+
201
+ You can also add one or two cursors with the `|` character into the jsx in order to simulate the cursor position
202
+
203
+ ```jsx
204
+ <root>
205
+ <paragraph>Hello, |World!|</paragraph>
206
+ </root>
207
+ ```
208
+
209
+ I've also implemented the `createTestEdytor` that help with creating an edytor instance from a jsx element in order to test various operations on a virtual edytor and test the expected output.
210
+
211
+ ```jsx
212
+ test('split text', () => {
213
+ const { edytor, expect } = createTestEdytor(
214
+ <root>
215
+ <paragraph>Hello, |World!</paragraph>
216
+ </root>
217
+ );
218
+
219
+ edytor.selection.state.startBlock?.splitBlock({
220
+ index: edytor.selection.state.yStart,
221
+ text: edytor.selection.state.startText
222
+ });
223
+
224
+ expect(
225
+ <root>
226
+ <paragraph>Hello, </paragraph>
227
+ <paragraph>World!</paragraph>
228
+ </root>
229
+ );
230
+ });
11
231
  ```
@@ -0,0 +1,123 @@
1
+ import { Text } from '../text/text.svelte.js';
2
+ import { Edytor } from '../edytor.svelte.js';
3
+ import { type YBlock, type JSONBlock, type JSONText, type JSONInlineBlock } from '../utils/json.js';
4
+ import * as Y from 'yjs';
5
+ import type { BlockDefinition } from '../plugins.js';
6
+ import { InlineBlock } from './inlineBlock.svelte.js';
7
+ export declare const getSetArray: <T = YBlock>(yBlock: YBlock, key?: "children" | "content") => Y.Array<T>;
8
+ export declare const getSetText: (yBlock: YBlock) => Y.Text;
9
+ export declare class Block {
10
+ #private;
11
+ readonly: boolean;
12
+ edytor: Edytor;
13
+ yBlock: YBlock;
14
+ parent?: Block;
15
+ yChildren: Y.Array<YBlock>;
16
+ yContent: Y.Array<YBlock | Y.Text>;
17
+ children: Block[];
18
+ content: (Text | InlineBlock)[];
19
+ id: string;
20
+ data: Record<string, any>;
21
+ node?: HTMLElement;
22
+ definition: BlockDefinition;
23
+ get selected(): boolean;
24
+ get focused(): boolean;
25
+ get insideIsland(): boolean;
26
+ get firstEditableText(): Text | undefined;
27
+ get lastEditableText(): Text | undefined;
28
+ get index(): number;
29
+ set index(value: number);
30
+ get type(): string;
31
+ set type(value: string);
32
+ get depth(): number;
33
+ get path(): number[];
34
+ get isRoot(): boolean;
35
+ get suggestions(): (Text | InlineBlock)[] | null;
36
+ set suggestions(value: (JSONText[] | JSONInlineBlock)[] | null);
37
+ get nextBlock(): Block | null;
38
+ get previousBlock(): Block | null;
39
+ get closestPreviousBlock(): Block | null;
40
+ get closestNextBlock(): Block | null;
41
+ get deepestChild(): Block;
42
+ get hasChildren(): boolean;
43
+ get hasContent(): boolean;
44
+ get isEmpty(): boolean;
45
+ get value(): JSONBlock;
46
+ get firstText(): Text;
47
+ get lastText(): Text;
48
+ private observeContent;
49
+ private observeChildren;
50
+ private batch;
51
+ addChildBlock: (args_0: {
52
+ block: JSONBlock;
53
+ index: number;
54
+ }) => Block;
55
+ addChildBlocks: (args_0: {
56
+ blocks: JSONBlock[];
57
+ index: number;
58
+ }) => Block[];
59
+ insertBlockAfter: (args_0: {
60
+ block: JSONBlock;
61
+ }) => Block | null;
62
+ insertBlockBefore: (args_0: {
63
+ block: JSONBlock;
64
+ }) => Block | null;
65
+ splitBlock: (args_0: {
66
+ index: number;
67
+ text: Text;
68
+ }) => Block | null;
69
+ removeBlock: (args_0?: {
70
+ keepChildren: boolean;
71
+ } | undefined) => void;
72
+ unNestBlock: () => Block | null;
73
+ mergeBlockBackward: () => Block | null;
74
+ mergeBlockForward: () => Block | null;
75
+ nestBlock: () => Block | null;
76
+ setBlock: (args_0: {
77
+ value: JSONBlock;
78
+ }) => void;
79
+ moveBlock: (args_0: {
80
+ path: number[];
81
+ }) => Block | null;
82
+ pushContentIntoBlock: (args_0: {
83
+ value: (Text | InlineBlock)[];
84
+ }) => void;
85
+ removeInlineBlock: (args_0: {
86
+ index: number;
87
+ }) => void;
88
+ addInlineBlock: (args_0: {
89
+ index: number;
90
+ block: JSONInlineBlock;
91
+ text: Text;
92
+ }) => Text;
93
+ normalizeContent: () => void;
94
+ suggestText: (args_0: {
95
+ value: (JSONText | JSONInlineBlock)[] | string | null;
96
+ }) => void;
97
+ acceptSuggestedText: () => void;
98
+ deleteContentAtRange: (args_0: {
99
+ start: [number, number];
100
+ end: [number, number];
101
+ }) => void;
102
+ void: (node: HTMLElement) => void;
103
+ constructor({ parent, block, yBlock, edytor }: {
104
+ parent?: Block;
105
+ edytor: Edytor;
106
+ } & ({
107
+ yBlock?: undefined;
108
+ block: JSONBlock;
109
+ } | {
110
+ yBlock: YBlock;
111
+ block?: undefined;
112
+ } | {
113
+ yBlock: YBlock;
114
+ block: JSONBlock & {
115
+ type: 'root';
116
+ };
117
+ }));
118
+ attach: (node: HTMLElement) => {
119
+ destroy: () => void;
120
+ };
121
+ }
122
+ export declare function observeChildren(this: Block, event: Y.YArrayEvent<YBlock>): void;
123
+ export declare function observeContent(this: Block, event: Y.YArrayEvent<YBlock | Y.Text>): void;