edytor 0.1.0-next.43 → 1.0.0-rc.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.
Files changed (48) hide show
  1. package/README.md +2 -2
  2. package/dist/clipboard/insertClipboardFragment.d.ts +8 -0
  3. package/dist/clipboard/insertClipboardFragment.js +23 -0
  4. package/dist/clipboard/moveText.js +1 -1
  5. package/dist/clipboard/textBlocks.d.ts +2 -0
  6. package/dist/clipboard/textBlocks.js +4 -0
  7. package/dist/cloudflare/DocumentRoom.d.ts +6 -6
  8. package/dist/cloudflare/room/context.d.ts +128 -128
  9. package/dist/collaboration/history/HistoryPanel.svelte +2 -2
  10. package/dist/crdt/document.d.ts +19 -7
  11. package/dist/crdt/document.js +34 -16
  12. package/dist/crdt/index.d.ts +1 -0
  13. package/dist/crdt/index.js +3 -2
  14. package/dist/crdt/nodes.d.ts +3 -2
  15. package/dist/crdt/operations.d.ts +161 -0
  16. package/dist/crdt/operations.js +97 -0
  17. package/dist/edytor.svelte.js +2 -2
  18. package/dist/events/onBeforeInput.js +1 -1
  19. package/dist/events/onFocus.js +7 -0
  20. package/dist/events/onPaste.js +12 -1
  21. package/dist/index.d.ts +19 -2
  22. package/dist/labels.d.ts +4 -0
  23. package/dist/labels.js +2 -0
  24. package/dist/plugins/blockHandles/blockHandlesPlugin.d.ts +2 -1
  25. package/dist/plugins/blockHandles/blockHandlesPlugin.js +70 -24
  26. package/dist/plugins/image/ImageEmpty.svelte +4 -4
  27. package/dist/plugins/image/ImageEmpty.svelte.d.ts +3 -3
  28. package/dist/plugins/image/ImagePlugin.svelte +30 -29
  29. package/dist/plugins/image/ImagePlugin.svelte.d.ts +4 -2
  30. package/dist/plugins/media/AudioPlugin.svelte +5 -1
  31. package/dist/plugins/media/FilePlugin.svelte +5 -1
  32. package/dist/plugins/media/MediaEmpty.svelte +42 -11
  33. package/dist/plugins/media/MediaEmpty.svelte.d.ts +2 -1
  34. package/dist/plugins/media/VideoPlugin.svelte +5 -1
  35. package/dist/plugins/media/media.d.ts +17 -2
  36. package/dist/plugins/media/media.js +34 -0
  37. package/dist/plugins/uploads.svelte.d.ts +92 -0
  38. package/dist/plugins/uploads.svelte.js +160 -0
  39. package/dist/selection/selection.svelte.d.ts +5 -8
  40. package/dist/selection/selection.svelte.js +12 -5
  41. package/dist/session/commands.d.ts +5 -53
  42. package/dist/session/commands.js +30 -7
  43. package/dist/session/history.js +1 -1
  44. package/dist/session/selection.d.ts +1 -1
  45. package/dist/surface/projector.svelte.js +1 -1
  46. package/package.json +1 -1
  47. package/dist/plugins/image/uploads.svelte.d.ts +0 -50
  48. package/dist/plugins/image/uploads.svelte.js +0 -111
package/README.md CHANGED
@@ -17,7 +17,7 @@
17
17
 
18
18
  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.
19
19
 
20
- > **Work in progress.** Edytor is a pre-release (`0.1.0-next.43`, `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.
20
+ > **Release candidate.** Edytor `1.0.0-rc.1` is the 1.0 release candidate (`edytor` on npm): its API is frozen, and a change to it before 1.0 is a listed breaking change. It has no production track record yet: read the [limitations](https://edytor.dev/docs/reference/limitations) before you build on it. Issues and PRs are welcome: when you report a bug, include the document's JSON value.
21
21
 
22
22
  ## Features
23
23
 
@@ -42,7 +42,7 @@ Edytor aims to be for Svelte what Slate.js is for React: a heavily customizable
42
42
  The pre-release is on npm under the `next` tag. Name the tag: a bare `edytor` is the old, incompatible `0.0.11`.
43
43
 
44
44
  ```bash
45
- pnpm add edytor@next
45
+ pnpm add edytor
46
46
  ```
47
47
 
48
48
  `svelte@^5` is a peer dependency. Do not install `yjs`: the v14 engine is vendored (`edytor/crdt`). See [installation](https://edytor.dev/docs/getting-started) and [platform support](https://edytor.dev/docs/reference/platform-support) (Chrome, Edge, Firefox and Safari; real phones are not tested yet).
@@ -4,6 +4,14 @@ import { type SelectionInsertionTarget, type SelectionReplacementState } from '.
4
4
  import { type JSONText } from '../utils/json.js';
5
5
  import type { EdytorClipboardFragment } from './types.js';
6
6
  export declare const flowOfText: (text: string, marks?: JSONText["marks"]) => Flow;
7
+ /**
8
+ * A pasted `text/plain` as markdown (`paste.markdown`): `null` unless a line
9
+ * holds block markdown (`hasBlockMarkdown`), else the blocks it reads as
10
+ * (`textToBlocks`). A kind the view does not register is a paragraph of its
11
+ * text, its children after it (a divider is dropped); without a paragraph
12
+ * kind, nothing converts.
13
+ */
14
+ export declare const flowOfMarkdown: (edytor: Pick<Edytor, "blocks">, text: string) => Flow | null;
7
15
  export declare const flowOfFragment: (fragment: EdytorClipboardFragment) => Flow;
8
16
  /**
9
17
  * Place `flow` (`flow.*`) at `at`, over the selected blocks (unless
@@ -4,6 +4,7 @@ import { cloneJsonSafe, jsonBlockToSpec, jsonContentToItems } from '../utils/jso
4
4
  import { id } from '../utils.js';
5
5
  import { caretAt } from '../session/attempt.js';
6
6
  import { isValidEdytorClipboardFragment } from './fragmentData.js';
7
+ import { hasBlockMarkdown, textToBlocks } from './textBlocks.js';
7
8
  // Admission (`flow.shape`): every id is minted fresh here, once.
8
9
  const run = (content) => ({
9
10
  id: id('b'),
@@ -12,6 +13,28 @@ const run = (content) => ({
12
13
  export const flowOfText = (text, marks) => ({
13
14
  lines: text.split(/\r\n|\r|\n/).map((line) => run(line ? [{ text: line, marks }] : []))
14
15
  });
16
+ /**
17
+ * A pasted `text/plain` as markdown (`paste.markdown`): `null` unless a line
18
+ * holds block markdown (`hasBlockMarkdown`), else the blocks it reads as
19
+ * (`textToBlocks`). A kind the view does not register is a paragraph of its
20
+ * text, its children after it (a divider is dropped); without a paragraph
21
+ * kind, nothing converts.
22
+ */
23
+ export const flowOfMarkdown = (edytor, text) => {
24
+ if (!edytor.blocks.has('paragraph') || !hasBlockMarkdown(text))
25
+ return null;
26
+ const known = (block) => {
27
+ const children = (block.children ?? []).flatMap(known);
28
+ if (edytor.blocks.has(block.type))
29
+ return [{ ...block, ...(block.children ? { children } : {}) }];
30
+ const own = block.type === 'divider' || (!block.content?.length && block.children?.length)
31
+ ? []
32
+ : [{ type: 'paragraph', content: block.content ?? [] }];
33
+ return [...own, ...children];
34
+ };
35
+ const blocks = textToBlocks(text).flatMap(known);
36
+ return blocks.length ? { lines: blocks.map((block) => jsonBlockToSpec(block, true)) } : null;
37
+ };
15
38
  export const flowOfFragment = (fragment) => fragment.kind === 'content'
16
39
  ? { lines: [run(fragment.content)] }
17
40
  : {
@@ -28,7 +28,7 @@ export const dropText = (edytor, drag, to) => {
28
28
  const { copy } = drag;
29
29
  /** Nothing written: the range stays selected (the drop's point is not adopted). */
30
30
  const keep = () => {
31
- edytor.selection.select(drag.range, 'model');
31
+ edytor.selection.select(drag.range);
32
32
  return false;
33
33
  };
34
34
  // A move onto itself: nothing to write.
@@ -19,5 +19,7 @@ export type TextToBlocksOptions = {
19
19
  /** The kind of a paragraph (default `paragraph`). */
20
20
  type?: string;
21
21
  };
22
+ /** Whether `text` holds block markdown (one line of it is enough), as a paste reads it. */
23
+ export declare const hasBlockMarkdown: (text: string) => boolean;
22
24
  /** `text` as blocks (see the module comment). */
23
25
  export declare const textToBlocks: (text: string, { markdown, type }?: TextToBlocksOptions) => JSONBlock[];
@@ -21,6 +21,10 @@ const runs = (text) => {
21
21
  out.push({ text: text.slice(at) });
22
22
  return out;
23
23
  };
24
+ /** A line that opens block markdown: a heading, a list or to-do item, a quote, a fence, a divider. */
25
+ const BLOCK_LINE = /^\s*(?:#{1,6}\s|[-*+]\s|\d+[.)]\s|>|```|(?:-{3,}|\*{3,}|_{3,})\s*$)/;
26
+ /** Whether `text` holds block markdown (one line of it is enough), as a paste reads it. */
27
+ export const hasBlockMarkdown = (text) => text.split(/\r?\n/).some((line) => BLOCK_LINE.test(line));
24
28
  /** One line's kind, data and text, or `null` for a paragraph line. */
25
29
  const lineKind = (line) => {
26
30
  let m = /^(#{1,6})\s+(.*)$/.exec(line);
@@ -110,7 +110,7 @@ import { type HistoryEntry, type HistoryOptions, type KVLike, type R2BucketLike
110
110
  import type { LockOptions } from './locks.js';
111
111
  import type { CommitResult, ExportedBlocks, ImportReceipt, ImportRequest, LateEditBatch, MoveNamespace } from './move.js';
112
112
  import type { AwarenessEntry } from '../crdt/protocol.js';
113
- import type { DocumentSemanticsConfig, EdytorDoc, JSONBlock, JSONDoc, YDoc } from '../crdt/index.js';
113
+ import type { DocumentSemanticsConfig, DocumentOperations, JSONBlock, JSONDoc, YDoc } from '../crdt/index.js';
114
114
  import type { CommentActor, CommentChange, CommentOutcome, CommentRequest, CommentSnapshot } from '../crdt/protocols/comments.js';
115
115
  /** Under SQLite-backed Durable Objects' 2 MB row cap, with room for the other columns. */
116
116
  export declare const DEFAULT_MAX_ROW_BYTES: number;
@@ -481,7 +481,7 @@ export type FrameValidation = {
481
481
  /** A block as it is now (`null`: it does not show). */
482
482
  after: (id: string) => ValidatedBlock | null;
483
483
  /** The live document. Read it; never write from `validate` (defer a `transact` instead). */
484
- facade: EdytorDoc;
484
+ facade: DocumentOperations;
485
485
  };
486
486
  /** The room's comment threads (`comments` of {@link AttachRoomOptions}). */
487
487
  export type CommentOptions = {
@@ -678,7 +678,7 @@ export declare class AttachedDocument {
678
678
  * first drops a direct write whose append failed (`heal`), so the next
679
679
  * write through it is stored.
680
680
  */
681
- get facade(): EdytorDoc;
681
+ get facade(): DocumentOperations;
682
682
  /**
683
683
  * Manipulate: run `fn` on the facade in one transaction. The edit is
684
684
  * stored, then broadcast to every socket. It is not a rollback, like
@@ -695,7 +695,7 @@ export declare class AttachedDocument {
695
695
  * without writing: the engine would queue the write until that one
696
696
  * ends, so it could not be stored before returning.
697
697
  */
698
- transact<T>(fn: (facade: EdytorDoc) => T): T;
698
+ transact<T>(fn: (facade: DocumentOperations) => T): T;
699
699
  /** The document as JSON. */
700
700
  read(): JSONDoc;
701
701
  /**
@@ -1044,10 +1044,10 @@ export declare class DocumentRoom<Env = DocumentRoomEnv> extends DurableObject<E
1044
1044
  /** Generation cutover, also over RPC — see {@link AttachedDocument.reset}. */
1045
1045
  reset(): Promise<void>;
1046
1046
  /** Server-side edit — see {@link AttachedDocument.transact}. */
1047
- transact<T>(fn: (facade: EdytorDoc) => T): T;
1047
+ transact<T>(fn: (facade: DocumentOperations) => T): T;
1048
1048
  /** The document as JSON. */
1049
1049
  read(): JSONDoc;
1050
- get facade(): EdytorDoc;
1050
+ get facade(): DocumentOperations;
1051
1051
  get doc(): YDoc | null;
1052
1052
  get failure(): Error | null;
1053
1053
  get refusals(): Refusal[];