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
@@ -0,0 +1,125 @@
1
+ import { triggerPostMoveFlash } from '@atlaskit/pragmatic-drag-and-drop-flourish/trigger-post-move-flash';
2
+ import * as liveRegion from '@atlaskit/pragmatic-drag-and-drop-live-region';
3
+ import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
4
+ import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
5
+ import { attachInstruction, extractInstruction } from '@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item';
6
+ export class DnD {
7
+ state = {
8
+ source: null,
9
+ target: null,
10
+ position: null
11
+ };
12
+ options;
13
+ uniqueContextId = Symbol('dnd-context');
14
+ constructor(options = {}) {
15
+ this.options = options;
16
+ }
17
+ calculateDropPosition(element, mouseY) {
18
+ const rect = element.getBoundingClientRect();
19
+ const relativeY = mouseY - rect.top;
20
+ if (relativeY < rect.height * 0.25) {
21
+ return 'before';
22
+ }
23
+ else if (relativeY > rect.height * 0.75) {
24
+ return 'after';
25
+ }
26
+ return 'inside';
27
+ }
28
+ updateDropIndicator(element, position) {
29
+ // Remove existing indicators
30
+ document.querySelectorAll('.drop-indicator').forEach((el) => {
31
+ if (el instanceof HTMLElement) {
32
+ el.remove();
33
+ }
34
+ });
35
+ const indicator = document.createElement('div');
36
+ indicator.className = 'drop-indicator';
37
+ switch (position) {
38
+ case 'before':
39
+ indicator.style.cssText = `
40
+ position: absolute;
41
+ left: 0;
42
+ right: 0;
43
+ top: -2px;
44
+ height: 4px;
45
+ background: #0066ff;
46
+ `;
47
+ break;
48
+ case 'after':
49
+ indicator.style.cssText = `
50
+ position: absolute;
51
+ left: 0;
52
+ right: 0;
53
+ bottom: -2px;
54
+ height: 4px;
55
+ background: #0066ff;
56
+ `;
57
+ break;
58
+ case 'inside':
59
+ indicator.style.cssText = `
60
+ position: absolute;
61
+ left: 0;
62
+ right: 0;
63
+ top: 0;
64
+ bottom: 0;
65
+ border: 2px solid #0066ff;
66
+ pointer-events: none;
67
+ `;
68
+ break;
69
+ }
70
+ element.appendChild(indicator);
71
+ }
72
+ // Svelte action that handles both dragging and dropping
73
+ attach = (element, block) => {
74
+ // Make element draggable
75
+ element.draggable = true;
76
+ const cleanup = combine(monitorForElements({
77
+ canMonitor: (args) => {
78
+ const data = args.source.data;
79
+ return data.uniqueContextId === this.uniqueContextId;
80
+ },
81
+ onDragStart: (args) => {
82
+ this.state.source = block;
83
+ args.source.data = {
84
+ uniqueContextId: this.uniqueContextId,
85
+ id: block.id,
86
+ type: 'block',
87
+ block
88
+ };
89
+ },
90
+ onDrop: (args) => {
91
+ // didn't drop on anything
92
+ if (!args.location.current.dropTargets.length) {
93
+ return;
94
+ }
95
+ const target = args.location.current.dropTargets[0];
96
+ const targetData = target.data;
97
+ const targetBlock = targetData.block;
98
+ const position = this.calculateDropPosition(target.element, args.location.current.input.clientY);
99
+ // Check if drop is allowed
100
+ if (this.options.canDrop && !this.options.canDrop(this.state.source, targetBlock)) {
101
+ return;
102
+ }
103
+ this.options.onDrop?.(this.state.source, targetBlock, position);
104
+ triggerPostMoveFlash(target.element);
105
+ liveRegion.announce(`Moved ${block.type} ${position} ${targetBlock.type}`);
106
+ // Reset state
107
+ this.state = {
108
+ source: null,
109
+ target: null,
110
+ position: null
111
+ };
112
+ }
113
+ }));
114
+ return {
115
+ destroy() {
116
+ cleanup();
117
+ document.querySelectorAll('.drop-indicator').forEach((el) => {
118
+ if (el instanceof HTMLElement) {
119
+ el.remove();
120
+ }
121
+ });
122
+ }
123
+ };
124
+ };
125
+ }
@@ -0,0 +1,94 @@
1
+ import { type Snippet } from 'svelte';
2
+ import * as Y from 'yjs';
3
+ import { type JSONBlock, type JSONDoc, type YBlock, type SerializableContent } from './utils/json.js';
4
+ import { EdytorSelection } from './selection/selection.svelte.js';
5
+ import { Block } from './block/block.svelte.js';
6
+ import { Text } from './text/text.svelte.js';
7
+ import { SvelteMap } from 'svelte/reactivity';
8
+ import { Awareness } from 'y-protocols/awareness.js';
9
+ import { batch } from './block/block.utils.js';
10
+ import type { Plugin, InitializedPlugin, BlockDefinition, MarkDefinition, InlineBlockDefinition } from './plugins.js';
11
+ import { HotKeys, type HotKey } from './hotkeys.js';
12
+ import { TRANSACTION } from './constants.js';
13
+ import type { InlineBlock } from './block/inlineBlock.svelte.js';
14
+ export type Snippets = {
15
+ [K in `${string}Block` | `${string}Mark`]: K extends `${string}Block` ? Snippet<[
16
+ {
17
+ block: Block;
18
+ children: Snippet | null;
19
+ content: Snippet;
20
+ }
21
+ ]> : Snippet<[
22
+ {
23
+ mark: SerializableContent;
24
+ text: Text;
25
+ content: Snippet;
26
+ }
27
+ ]>;
28
+ };
29
+ export type EdytorOptions = {
30
+ readonly?: boolean;
31
+ snippets?: Snippets;
32
+ hotKeys?: Record<string, HotKey>;
33
+ plugins?: Plugin[];
34
+ doc?: Y.Doc;
35
+ awareness?: Awareness;
36
+ sync?: boolean;
37
+ value?: JSONDoc;
38
+ onChange?: (value: JSONBlock) => void;
39
+ onSelectionChange?: (selection: EdytorSelection) => void;
40
+ placeholder?: string | Snippet<[{
41
+ block: Block;
42
+ }]>;
43
+ };
44
+ export type RootBlock = Block & {
45
+ readonly type: 'root';
46
+ readonly id: 'root';
47
+ readonly depth: 0;
48
+ };
49
+ export declare class Edytor {
50
+ node?: HTMLElement;
51
+ marks: Map<string, MarkDefinition>;
52
+ blocks: Map<string, BlockDefinition>;
53
+ inlineBlocks: Map<string, InlineBlockDefinition>;
54
+ plugins: InitializedPlugin[];
55
+ container: HTMLDivElement | undefined;
56
+ idToBlock: SvelteMap<string, Block>;
57
+ idToInlineBlock: SvelteMap<string, InlineBlock>;
58
+ idToText: SvelteMap<string, Text>;
59
+ nodeToText: SvelteMap<Node, Text>;
60
+ transaction: TRANSACTION;
61
+ hotKeys: HotKeys;
62
+ initialized: boolean;
63
+ readonly: boolean;
64
+ yRootBlock: YBlock;
65
+ root: Block | undefined;
66
+ synced: boolean;
67
+ edytor: this;
68
+ selection: EdytorSelection;
69
+ defaultType: string;
70
+ private off;
71
+ private onChange?;
72
+ placeholder?: string | Snippet<[{
73
+ block: Block;
74
+ }]>;
75
+ doc: Y.Doc;
76
+ undoManager: Y.UndoManager;
77
+ awareness: Awareness;
78
+ transact: <T>(cb: () => T) => T;
79
+ constructor({ snippets, readonly, hotKeys, plugins, doc, awareness, sync, value, onSelectionChange, placeholder, onChange }: EdytorOptions);
80
+ getBlockDefinition: <M extends "inline" | "block">(mode: M, type: string) => M extends "block" ? BlockDefinition : InlineBlockDefinition;
81
+ get value(): JSONBlock;
82
+ getDefaultBlock: (parent?: Block | Edytor | undefined) => string;
83
+ sync: ({ children }?: JSONDoc) => void;
84
+ onBeforeInput: (e: InputEvent) => Promise<void>;
85
+ batch: typeof batch;
86
+ deleteContentWithinSelection: (args_0: {}) => readonly [Text | null, number];
87
+ getTextById: (id: string) => Text | undefined;
88
+ getBlockByIdOrContent: (idOrContent: string | Text) => Block | undefined;
89
+ getTextNode: (idOrText: string | Text) => Promise<HTMLElement>;
90
+ attach: (node: HTMLDivElement) => {
91
+ destroy: () => void;
92
+ };
93
+ }
94
+ export declare const useEdytor: () => Edytor;
@@ -0,0 +1,262 @@
1
+ import { getContext, hasContext, setContext, tick, onMount } from 'svelte';
2
+ import * as Y from 'yjs';
3
+ import { onBeforeInput } from './events/onBeforeInput.js';
4
+ import {} from './utils/json.js';
5
+ import { onKeyDown } from './events/onKeyDown.js';
6
+ import { EdytorSelection } from './selection/selection.svelte.js';
7
+ import { Block } from './block/block.svelte.js';
8
+ import { Text } from './text/text.svelte.js';
9
+ import { SvelteMap } from 'svelte/reactivity';
10
+ import { Awareness } from 'y-protocols/awareness.js';
11
+ import { batch } from './block/block.utils.js';
12
+ import { on } from 'svelte/events';
13
+ import { HotKeys } from './hotkeys.js';
14
+ import { TRANSACTION } from './constants.js';
15
+ import { deleteContentWithinSelection } from './edytor.utils.js';
16
+ export class Edytor {
17
+ node;
18
+ marks = new Map();
19
+ blocks = new Map();
20
+ inlineBlocks = new Map();
21
+ plugins;
22
+ container = $state();
23
+ idToBlock = new SvelteMap();
24
+ idToInlineBlock = new SvelteMap();
25
+ idToText = new SvelteMap();
26
+ nodeToText = new SvelteMap();
27
+ transaction = new TRANSACTION();
28
+ hotKeys;
29
+ initialized = $state(false);
30
+ readonly = $state(false);
31
+ yRootBlock;
32
+ root = $state();
33
+ synced = $state(false);
34
+ edytor = this;
35
+ selection;
36
+ defaultType = 'paragraph';
37
+ off = [];
38
+ onChange;
39
+ placeholder;
40
+ // YJS Stuff
41
+ doc = new Y.Doc();
42
+ undoManager;
43
+ awareness;
44
+ transact = (cb) => {
45
+ return this.doc.transact(() => {
46
+ const result = cb();
47
+ return result;
48
+ }, this.transaction);
49
+ };
50
+ constructor({ snippets, readonly, hotKeys, plugins, doc = this.doc, awareness = new Awareness(doc), sync, value, onSelectionChange, placeholder, onChange }) {
51
+ this.readonly = readonly || false;
52
+ this.doc = doc;
53
+ this.yRootBlock = this.doc.getMap('content');
54
+ this.awareness = awareness;
55
+ this.onChange = onChange;
56
+ // Initialize plugins
57
+ this.plugins = (plugins || []).map((plugin) => {
58
+ const initializedPlugin = plugin(this);
59
+ initializedPlugin.marks &&
60
+ Object.entries(initializedPlugin.marks).forEach(([key, snippet]) => {
61
+ if (typeof snippet === 'object') {
62
+ this.marks.set(key, snippet);
63
+ }
64
+ else {
65
+ this.marks.set(key, { snippet });
66
+ }
67
+ });
68
+ initializedPlugin.blocks &&
69
+ Object.entries(initializedPlugin.blocks).forEach(([key, definition]) => {
70
+ if (typeof definition === 'object') {
71
+ this.blocks.set(key, definition);
72
+ }
73
+ else {
74
+ this.blocks.set(key, { snippet: definition });
75
+ }
76
+ });
77
+ initializedPlugin.inlineBlocks &&
78
+ Object.entries(initializedPlugin.inlineBlocks).forEach(([key, definition]) => {
79
+ if (typeof definition === 'object') {
80
+ this.inlineBlocks.set(key, definition);
81
+ }
82
+ else {
83
+ this.inlineBlocks.set(key, { snippet: definition });
84
+ }
85
+ });
86
+ return initializedPlugin;
87
+ });
88
+ // We set the custom snippets after plugins are initialized in order to be able to override the plugins snippets
89
+ Object.entries(snippets || {}).forEach(([key, snippet]) => {
90
+ const isMark = key.endsWith('Mark');
91
+ const isInlineBlock = key.endsWith('InlineBlock');
92
+ const isBlock = key.endsWith('Block');
93
+ if (isMark) {
94
+ this.marks.set(key, { snippet: snippet });
95
+ }
96
+ else if (isInlineBlock) {
97
+ // this.inlineBlocks.set(key, { snippet: snippet as Snippet<[InlineBlockSnippetPayload]> });
98
+ }
99
+ else if (isBlock) {
100
+ this.blocks.set(key, { snippet: snippet });
101
+ }
102
+ });
103
+ this.placeholder =
104
+ placeholder || this.plugins.find((plugin) => plugin.placeholder)?.placeholder;
105
+ if (readonly || !sync) {
106
+ this.sync(value || { children: [] });
107
+ }
108
+ this.selection = new EdytorSelection(this, onSelectionChange);
109
+ this.hotKeys = new HotKeys(this, hotKeys, this.plugins);
110
+ this.undoManager = new Y.UndoManager(this.yRootBlock, {
111
+ trackedOrigins: new Set([this.transaction, null])
112
+ });
113
+ }
114
+ getBlockDefinition = (mode, type) => {
115
+ const definition = mode === 'block' ? this.blocks.get(type) : this.inlineBlocks.get(type);
116
+ if (type === 'root') {
117
+ return {};
118
+ }
119
+ if (!definition) {
120
+ throw new Error(`Block type ${type} is not defined`);
121
+ }
122
+ return definition;
123
+ };
124
+ get value() {
125
+ return {
126
+ type: 'root',
127
+ children: this.root?.value.children || []
128
+ };
129
+ }
130
+ getDefaultBlock = (parent = this.selection.state.startText?.parent) => {
131
+ if (!parent || parent instanceof Edytor) {
132
+ return 'paragraph';
133
+ }
134
+ for (const plugin of this.plugins) {
135
+ if (plugin.defaultBlock) {
136
+ const defaultBlock = typeof plugin.defaultBlock === 'function'
137
+ ? plugin.defaultBlock(parent)
138
+ : plugin.defaultBlock;
139
+ if (defaultBlock) {
140
+ return defaultBlock;
141
+ }
142
+ }
143
+ }
144
+ return 'paragraph';
145
+ };
146
+ sync = ({ children = [] } = { children: [] }) => {
147
+ if (this.synced) {
148
+ return;
149
+ }
150
+ if (this.readonly) {
151
+ // children.forEach((child) => {
152
+ // const block = new Block({ parent: this.root, block: child });
153
+ // this.root.yChildren.push([block.yBlock]);
154
+ // });
155
+ }
156
+ else {
157
+ const INITIALIZED = 'INITIALIZED';
158
+ const initializedText = this.doc.getText(INITIALIZED);
159
+ this.initialized = initializedText?.toJSON() === INITIALIZED;
160
+ if (this.initialized) {
161
+ // this.yRootBlock =
162
+ // Root block already exists and has its children
163
+ this.root = new Block({
164
+ edytor: this,
165
+ yBlock: this.yRootBlock,
166
+ block: {
167
+ type: 'root',
168
+ id: 'root',
169
+ children
170
+ }
171
+ });
172
+ }
173
+ else {
174
+ this.root = new Block({
175
+ edytor: this,
176
+ yBlock: this.yRootBlock,
177
+ block: {
178
+ type: 'root',
179
+ id: 'root',
180
+ children
181
+ }
182
+ });
183
+ }
184
+ initializedText.delete(0, initializedText.length);
185
+ initializedText.insert(0, INITIALIZED);
186
+ }
187
+ this.synced = true;
188
+ this.doc.on('update', () => {
189
+ const value = this.value;
190
+ this.onChange?.(value);
191
+ this.plugins.forEach((plugin) => {
192
+ plugin.onChange?.(value);
193
+ });
194
+ });
195
+ };
196
+ onBeforeInput = onBeforeInput.bind(this);
197
+ batch = batch.bind(this);
198
+ deleteContentWithinSelection = this.batch('deleteContentWithinSelection', deleteContentWithinSelection.bind(this));
199
+ getTextById = (id) => {
200
+ const isText = id.startsWith('t');
201
+ if (!isText) {
202
+ throw new Error('Invalid id, expected text id');
203
+ }
204
+ return this.idToText.get(id);
205
+ };
206
+ getBlockByIdOrContent = (idOrContent) => {
207
+ if (typeof idOrContent === 'string') {
208
+ const isText = idOrContent.startsWith('t');
209
+ const isBlock = idOrContent.startsWith('b');
210
+ if (isBlock) {
211
+ return this.idToBlock.get(idOrContent);
212
+ }
213
+ else if (isText) {
214
+ const text = this.idToText.get(idOrContent);
215
+ return text?.parent;
216
+ }
217
+ }
218
+ else if (idOrContent instanceof Text) {
219
+ return idOrContent.parent || undefined;
220
+ }
221
+ return undefined;
222
+ };
223
+ getTextNode = async (idOrText) => {
224
+ await tick();
225
+ const text = idOrText instanceof Text ? idOrText : this.getTextById(idOrText);
226
+ let node = text?.node;
227
+ let breakCount = 0;
228
+ while (!node) {
229
+ await tick();
230
+ node = text?.node;
231
+ breakCount++;
232
+ if (breakCount > 10) {
233
+ throw new Error('Failed to find text node');
234
+ }
235
+ }
236
+ return node;
237
+ };
238
+ attach = (node) => {
239
+ this.node = node;
240
+ this.container = node;
241
+ this.selection.init();
242
+ this.hotKeys.init();
243
+ this.off.push(on(document, 'keydown', onKeyDown.bind(this)), on(node, 'click', this.selection.handleTripleClick), on(node, 'beforeinput', this.onBeforeInput));
244
+ this.plugins.forEach((plugin) => {
245
+ const action = plugin.onEdytorAttached?.({ node });
246
+ action && this.off.push(action);
247
+ });
248
+ return {
249
+ destroy: () => {
250
+ this.selection.destroy();
251
+ this.off.forEach((off) => off());
252
+ }
253
+ };
254
+ };
255
+ }
256
+ export const useEdytor = () => {
257
+ const hasEdytorContext = hasContext('edytor');
258
+ if (hasEdytorContext) {
259
+ return getContext('edytor');
260
+ }
261
+ throw new Error('No Edytor found');
262
+ };
@@ -0,0 +1,3 @@
1
+ import { Text } from './text/text.svelte.js';
2
+ import type { Edytor } from './edytor.svelte.js';
3
+ export declare function deleteContentWithinSelection(this: Edytor, {}: {}): readonly [Text | null, number];
@@ -0,0 +1,78 @@
1
+ import { Block } from './block/block.svelte.js';
2
+ import { Text } from './text/text.svelte.js';
3
+ import { deltaToJson, toDeltas } from './text/deltas.js';
4
+ import { InlineBlock } from './block/inlineBlock.svelte.js';
5
+ export function deleteContentWithinSelection({}) {
6
+ const { startBlock, startText, endBlock, yStart, yEnd, isAtStartOfBlock, isAtEndOfBlock, endText } = this.selection.state;
7
+ const blocksToDelete = this.selection.state.blocks.filter((block, index) => {
8
+ const isFirst = index === 0;
9
+ const isLast = index === this.selection.state.blocks.length - 1;
10
+ if (isFirst) {
11
+ return isAtStartOfBlock;
12
+ }
13
+ else if (isLast) {
14
+ return isAtEndOfBlock;
15
+ }
16
+ else {
17
+ return true;
18
+ }
19
+ });
20
+ const firstRange = startText && startBlock
21
+ ? {
22
+ start: [startText.index, yStart],
23
+ end: [startBlock.lastText.index, startBlock.lastText.length]
24
+ }
25
+ : null;
26
+ if (startBlock !== blocksToDelete[0] && firstRange) {
27
+ // Delete the text from the yStart
28
+ startBlock?.deleteContentAtRange(firstRange);
29
+ }
30
+ // We need to find the content that will be merged into the first block
31
+ if (endBlock && endText && endBlock !== blocksToDelete[blocksToDelete.length - 1]) {
32
+ const contentToMerge = endBlock.content
33
+ .slice(endText.index, endBlock?.content.length)
34
+ .map((part, index) => {
35
+ const isFirstPart = index === 0;
36
+ if (part instanceof Text && isFirstPart) {
37
+ // Delete from offset to end
38
+ part.yText.delete(0, yEnd);
39
+ const deltas = deltaToJson(toDeltas(part.yText)[0]);
40
+ return deltas;
41
+ }
42
+ return part.value;
43
+ });
44
+ const value = contentToMerge.map((part) => {
45
+ if ('type' in part) {
46
+ const block = new InlineBlock({
47
+ parent: startBlock,
48
+ block: part
49
+ });
50
+ return block.yBlock;
51
+ }
52
+ else {
53
+ const text = new Text({
54
+ parent: startBlock,
55
+ content: part
56
+ });
57
+ return text.yText;
58
+ }
59
+ });
60
+ startBlock?.yContent.push(value);
61
+ }
62
+ blocksToDelete.forEach((block, index) => {
63
+ block.removeBlock();
64
+ });
65
+ if (endBlock?.hasChildren) {
66
+ const newBlocks = endBlock.children.map((child) => {
67
+ const newBlock = new Block({
68
+ parent: startBlock.parent,
69
+ edytor: this,
70
+ block: child.value
71
+ });
72
+ return newBlock.yBlock;
73
+ });
74
+ startBlock?.parent?.yChildren.insert(startBlock.index + 1, newBlocks);
75
+ }
76
+ endBlock?.removeBlock();
77
+ return [startText, yStart];
78
+ }
@@ -1,2 +1,2 @@
1
- import { onBeforeInputData } from "../types";
2
- export declare const onBeforeInput: ([doc, onChange, editor]: onBeforeInputData, e: InputEvent) => void;
1
+ import type { Edytor } from '../edytor.svelte.js';
2
+ export declare function onBeforeInput(this: Edytor, e: InputEvent): Promise<void>;