@fileverse-dev/ddoc 6.0.1-dist-slim.0 → 6.0.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.
@@ -2,7 +2,7 @@ import { Extension, Editor } from '@tiptap/core';
2
2
  import { EditorState, PluginKey } from '@tiptap/pm/state';
3
3
  import { Transform } from '@tiptap/pm/transform';
4
4
  import { DecorationSet } from '@tiptap/pm/view';
5
- import { SuggestionType } from '../../types';
5
+ import { SuggestionMultilineStructure, SuggestionType } from '../../types';
6
6
 
7
7
  import * as Y from 'yjs';
8
8
  export interface CommentAnchor {
@@ -15,6 +15,9 @@ export interface CommentAnchor {
15
15
  suggestionType?: SuggestionType;
16
16
  originalContent?: string;
17
17
  suggestedContent?: string;
18
+ multilineStructure?: SuggestionMultilineStructure;
19
+ followsSuggestionId?: string;
20
+ isDraft?: boolean;
18
21
  }
19
22
  interface CommentDecorationPluginState {
20
23
  decorations: DecorationSet;
@@ -46,6 +49,8 @@ export declare function resolveCommentAnchorRangeInState(anchor: Pick<CommentAnc
46
49
  * so we need a separate path that allows a point position.
47
50
  */
48
51
  export declare function resolveCommentAnchorPointInState(anchor: Pick<CommentAnchor, 'anchorFrom'>, state: EditorState): number | null;
52
+ /** Resolve following Adds against the accepted break's persisted Yjs position. */
53
+ export declare function resolveSuggestionAddPointInState(anchor: CommentAnchor, state: EditorState, anchors: CommentAnchor[] | ReadonlyMap<string, CommentAnchor>): number | null;
49
54
  export declare function hasResolvableCommentAnchorInState(anchor: Pick<CommentAnchor, 'anchorFrom' | 'anchorTo' | 'isSuggestion' | 'suggestionType'>, state: EditorState): boolean;
50
55
  export declare function resolveCommentAnchorRangeForAnalysis(anchor: Pick<CommentAnchor, 'id' | 'anchorFrom' | 'anchorTo'>, state: EditorState): CommentAnchorRange | null;
51
56
  export declare function resolveCommentAnchorPointForAnalysis(anchor: Pick<CommentAnchor, 'id' | 'anchorFrom'>, state: EditorState): number | null;
@@ -84,7 +89,7 @@ export declare function createCommentAnchorFromEditor(editor: Editor, from: numb
84
89
  * without selecting text — createCommentAnchorFromEditor rejects from >= to
85
90
  * since an empty range is invalid for regular comments.
86
91
  */
87
- export declare function createCommentAnchorPointFromEditor(editor: Editor, pos: number): CommentAnchorRelativeRange | null;
92
+ export declare function createCommentAnchorPointFromEditor(editor: Editor, pos: number, assoc?: -1 | 1): CommentAnchorRelativeRange | null;
88
93
  export declare function createCommentAnchorFromSelection(editor: Editor): CommentAnchorRelativeRange | null;
89
94
  export declare function triggerDecorationRebuild(editor: Editor): void;
90
95
  export declare function getCommentAtPosition(editor: Editor, pos: number, getAnchors: () => CommentAnchor[]): CommentAnchor | null;
@@ -94,5 +99,5 @@ export declare function getCommentAnchorRange(editor: Editor, commentId: string,
94
99
  * Called by the store's acceptSuggestion action before resolving on-chain.
95
100
  * Returns false if the anchor can't be resolved or the suggestion type is unknown.
96
101
  */
97
- export declare function applyAcceptedSuggestion(editor: Editor, anchor: CommentAnchor): boolean;
102
+ export declare function applyAcceptedSuggestion(editor: Editor, anchor: CommentAnchor, relatedAnchors?: CommentAnchor[]): boolean;
98
103
  export {};
@@ -2,7 +2,7 @@ import { Editor, Mark, Range } from '@tiptap/core';
2
2
  import { Mark as PMMark } from '@tiptap/pm/model';
3
3
  import { PluginKey, EditorState } from '@tiptap/pm/state';
4
4
  import { DecorationSet } from '@tiptap/pm/view';
5
- import { SuggestionType } from '../../types';
5
+ import { SuggestionMultilineStructure, SuggestionType } from '../../types';
6
6
 
7
7
  import * as Y from 'yjs';
8
8
  declare module '@tiptap/core' {
@@ -120,6 +120,8 @@ export interface IComment {
120
120
  suggestionType?: SuggestionType;
121
121
  originalContent?: string;
122
122
  suggestedContent?: string;
123
+ multilineStructure?: SuggestionMultilineStructure;
124
+ followsSuggestionId?: string;
123
125
  }
124
126
  export declare const CommentExtension: Mark<CommentOptions, CommentStorage>;
125
127
  export {};
@@ -1,4 +1,4 @@
1
- export declare function emojiSearch(query: string): Promise<{
1
+ export declare function emojiSearch(query: string): {
2
2
  name: string;
3
3
  emoji: string;
4
- }[]>;
4
+ }[];
@@ -0,0 +1,25 @@
1
+ import { Editor } from '@tiptap/core';
2
+ import { SuggestionMultilineStructure, SuggestionStructureType } from '../../types';
3
+
4
+ /** The selected Enter cannot split at its start if only its end is in a list. */
5
+ export declare function crossesStandaloneParagraphAndListItem(editor: Editor, from: number, to: number): boolean;
6
+ export declare function validMultilineStructure(content: string | undefined, value: SuggestionMultilineStructure | undefined): value is SuggestionMultilineStructure;
7
+ /** Resolve the next key against the proposed cursor context, not just the
8
+ * unchanged document. Enter on an empty list item is blocked. */
9
+ export declare function resolveSuggestionStructureType(editor: Editor, position: number, existing: SuggestionMultilineStructure | undefined, shift: boolean, context?: {
10
+ from: number;
11
+ to: number;
12
+ insertedText: string;
13
+ }): SuggestionStructureType | null;
14
+ export declare function appendSuggestionText(content: string, multilineStructure: SuggestionMultilineStructure | undefined, text: string): {
15
+ content: string;
16
+ multilineStructure?: SuggestionMultilineStructure;
17
+ };
18
+ export declare function appendSuggestionStructureType(content: string, multilineStructure: SuggestionMultilineStructure | undefined, kind: SuggestionStructureType): {
19
+ content: string;
20
+ multilineStructure: SuggestionMultilineStructure;
21
+ };
22
+ export declare function undoSuggestionInput(content: string, multilineStructure: SuggestionMultilineStructure | undefined, lastInput: string): {
23
+ content: string;
24
+ multilineStructure?: SuggestionMultilineStructure;
25
+ };
@@ -17,6 +17,8 @@ export interface SuggestionTrackingOptions {
17
17
  getIsSuggestionMode: () => boolean;
18
18
  /** Viewer types text with a collapsed cursor (Add gesture). */
19
19
  onTextInput: (text: string) => void;
20
+ /** Enter or Shift+Enter may contribute a proposed break, never a doc edit. */
21
+ onBreak: (shift: boolean) => void;
20
22
  /** Viewer types text over a non-empty selection (Replace gesture). */
21
23
  onReplaceTyping: (from: number, to: number, text: string) => void;
22
24
  /** Viewer presses Backspace/Delete with a non-empty selection. */
@@ -1,10 +1,10 @@
1
1
  import { Editor } from '@tiptap/react';
2
2
  import { default as React } from 'react';
3
3
  import { CommentAnchor } from '../extensions/comment/comment-decoration-plugin';
4
+ import { SuggestionMultilineStructure, CommentMutationMeta, CommentMutationType } from '../types';
4
5
  import { CommentFloatingCard, EnsCache, InlineCommentData, InlineCommentDraft, InlineDraftLocation } from '../components/inline-comment/context/types';
5
6
  import { EnsStatus } from '../components/inline-comment/types';
6
7
  import { IComment } from '../extensions/comment';
7
- import { CommentMutationMeta, CommentMutationType } from '../types';
8
8
 
9
9
  import * as Y from 'yjs';
10
10
  export interface CommentExternalDeps {
@@ -53,6 +53,10 @@ export interface DraftSuggestion {
53
53
  originalContent: string;
54
54
  /** Accumulated text the viewer has typed. Empty for a pure Delete draft. */
55
55
  insertedText: string;
56
+ multilineStructure?: SuggestionMultilineStructure;
57
+ followsSuggestionId?: string;
58
+ /** A selected-range Enter owns its break; the next text starts an Add. */
59
+ followUpAddAfterBreak?: boolean;
56
60
  /** Per-keystroke history for undo — each entry is one typed character. */
57
61
  keystrokes: string[];
58
62
  /** True when the draft was created via select+delete or select+type. */
@@ -225,6 +229,7 @@ export interface CommentStoreState {
225
229
  * Creates a new Add draft if no draft exists at the cursor.
226
230
  */
227
231
  appendToDraftAtCursor: (text: string) => void;
232
+ appendBreakToDraftAtCursor: (shift: boolean) => void;
228
233
  /**
229
234
  * Create a Delete (or pending Replace) draft from a selection range.
230
235
  * Captures originalContent, leaves insertedText empty; type becomes 'replace'
@@ -22,6 +22,12 @@ export type InlineCommentData = {
22
22
  };
23
23
  export type CommentMutationType = 'create' | 'edit' | 'resolve' | 'unresolve' | 'delete';
24
24
  export type SuggestionType = 'add' | 'replace' | 'delete' | 'link';
25
+ export type SuggestionStructureType = 'block' | 'listItem' | 'soft' | 'text';
26
+ export interface SuggestionMultilineStructure {
27
+ version: 1;
28
+ insertedTexts: string[];
29
+ structureType: SuggestionStructureType[];
30
+ }
25
31
  export interface CommentMutationMeta {
26
32
  type: CommentMutationType;
27
33
  updateChunk?: string;
@@ -32,6 +38,8 @@ export interface CommentMutationMeta {
32
38
  suggestionType?: SuggestionType;
33
39
  originalContent?: string;
34
40
  suggestedContent?: string;
41
+ multilineStructure?: SuggestionMultilineStructure;
42
+ followsSuggestionId?: string;
35
43
  }
36
44
  export interface SerializedCommentAnchor {
37
45
  id: string;
@@ -43,6 +51,8 @@ export interface SerializedCommentAnchor {
43
51
  suggestionType?: SuggestionType;
44
52
  originalContent?: string;
45
53
  suggestedContent?: string;
54
+ multilineStructure?: SuggestionMultilineStructure;
55
+ followsSuggestionId?: string;
46
56
  }
47
57
  export interface CommentAccountProps {
48
58
  isConnected?: boolean;
@@ -1,4 +1,4 @@
1
- import { D as n, a as o, d as D, g as a, m as r, r as d, b as C } from "./ddoc-persistence-DLdSviUr.mjs";
1
+ import { D as n, a as o, d as D, g as a, m as r, r as d, b as C } from "./ddoc-persistence-C2ay3lLb.mjs";
2
2
  export {
3
3
  n as DDOC_STORE_REPAIRED,
4
4
  o as DEFAULT_DDOC_PERSISTENCE_TIMEOUT_MS,
@@ -1,67 +1,66 @@
1
1
  import { jsx as m, jsxs as L } from "react/jsx-runtime";
2
2
  import { useRef as D, useState as E, useEffect as A } from "react";
3
3
  import { DynamicDropdown as P, Tooltip as O, IconButton as T } from "@fileverse/ui";
4
- import { EditorSelection as R } from "@codemirror/state";
5
- import { redo as _, undo as w } from "@codemirror/commands";
6
- const p = (e, t, o = t) => {
7
- const { state: i } = e, l = i.changeByRange((n) => {
8
- const d = i.sliceDoc(n.from, n.to), r = i.sliceDoc(
9
- Math.max(0, n.from - t.length),
10
- n.from
4
+ import { r as _, u as w, E as R } from "./index-By29BevC.mjs";
5
+ const p = (e, n, o = n) => {
6
+ const { state: i } = e, l = i.changeByRange((t) => {
7
+ const d = i.sliceDoc(t.from, t.to), r = i.sliceDoc(
8
+ Math.max(0, t.from - n.length),
9
+ t.from
11
10
  ), u = i.sliceDoc(
12
- n.to,
13
- Math.min(i.doc.length, n.to + o.length)
11
+ t.to,
12
+ Math.min(i.doc.length, t.to + o.length)
14
13
  );
15
- if (r === t && u === o)
14
+ if (r === n && u === o)
16
15
  return {
17
16
  changes: [
18
- { from: n.from - t.length, to: n.from, insert: "" },
19
- { from: n.to, to: n.to + o.length, insert: "" }
17
+ { from: t.from - n.length, to: t.from, insert: "" },
18
+ { from: t.to, to: t.to + o.length, insert: "" }
20
19
  ],
21
20
  range: R.range(
22
- n.from - t.length,
23
- n.to - t.length
21
+ t.from - n.length,
22
+ t.to - n.length
24
23
  )
25
24
  };
26
- const b = t + d + o;
25
+ const b = n + d + o;
27
26
  return {
28
- changes: { from: n.from, to: n.to, insert: b },
27
+ changes: { from: t.from, to: t.to, insert: b },
29
28
  range: R.range(
30
- n.from + t.length,
31
- n.from + t.length + d.length
29
+ t.from + n.length,
30
+ t.from + n.length + d.length
32
31
  )
33
32
  };
34
33
  });
35
34
  e.dispatch(i.update(l, { scrollIntoView: !0 })), e.focus();
36
- }, B = (e, t) => {
35
+ }, B = (e, n) => {
37
36
  const { state: o } = e, i = [], l = /* @__PURE__ */ new Set();
38
- for (const n of o.selection.ranges) {
39
- let d = n.from;
37
+ for (const t of o.selection.ranges) {
38
+ let d = t.from;
40
39
  for (; ; ) {
41
40
  const r = o.doc.lineAt(d);
42
41
  if (!l.has(r.number)) {
43
42
  l.add(r.number);
44
- const u = t(r.text, r.from);
43
+ const u = n(r.text, r.from);
45
44
  u && i.push(u);
46
45
  }
47
- if (r.to >= n.to) break;
46
+ if (r.to >= t.to) break;
48
47
  d = r.to + 1;
49
48
  }
50
49
  }
51
50
  i.length && e.dispatch(o.update({ changes: i, scrollIntoView: !0 })), e.focus();
52
- }, y = (e, t) => B(
51
+ }, y = (e, n) => B(
53
52
  e,
54
- (o, i) => o.startsWith(t) ? { from: i, to: i + t.length, insert: "" } : { from: i, insert: t }
55
- ), z = (e, t) => {
56
- const o = "#".repeat(t) + " ";
53
+ (o, i) => o.startsWith(n) ? { from: i, to: i + n.length, insert: "" } : { from: i, insert: n }
54
+ ), z = (e, n) => {
55
+ const o = "#".repeat(n) + " ";
57
56
  return B(e, (i, l) => {
58
- const n = i.match(/^(#{1,6})\s/);
59
- return n && n[1].length === t ? { from: l, to: l + n[0].length, insert: "" } : n ? { from: l, to: l + n[0].length, insert: o } : { from: l, insert: o };
57
+ const t = i.match(/^(#{1,6})\s/);
58
+ return t && t[1].length === n ? { from: l, to: l + t[0].length, insert: "" } : t ? { from: l, to: l + t[0].length, insert: o } : { from: l, insert: o };
60
59
  });
61
- }, f = (e, t) => {
60
+ }, f = (e, n) => {
62
61
  const { state: o } = e, i = o.selection.main, r = `${o.doc.lineAt(i.from).text.trim() === "" ? "" : `
63
62
 
64
- `}${t}
63
+ `}${n}
65
64
  `;
66
65
  e.dispatch(
67
66
  o.update({
@@ -70,19 +69,19 @@ const p = (e, t, o = t) => {
70
69
  scrollIntoView: !0
71
70
  })
72
71
  ), e.focus();
73
- }, G = (e, t) => {
72
+ }, G = (e, n) => {
74
73
  const { state: o } = e, i = o.changeByRange((l) => {
75
- const n = o.sliceDoc(l.from, l.to) || "text", d = t ?? "url", r = `[${n}](${d})`, u = l.from + 1 + n.length + 2;
74
+ const t = o.sliceDoc(l.from, l.to) || "text", d = n ?? "url", r = `[${t}](${d})`, u = l.from + 1 + t.length + 2;
76
75
  return {
77
76
  changes: { from: l.from, to: l.to, insert: r },
78
77
  range: R.range(u, u + d.length)
79
78
  };
80
79
  });
81
80
  e.dispatch(o.update(i, { scrollIntoView: !0 })), e.focus();
82
- }, K = (e, t) => {
83
- const o = `<img src="${t.src}" media-type="secure-img" encryptionKey="${t.encryptionKey}" nonce="${t.nonce}" ipfsUrl="${t.ipfsUrl}" ipfsHash="${t.ipfsHash}" version="2" authTag="${t.authTag}" mimeType="${t.mimeType}" />`;
81
+ }, K = (e, n) => {
82
+ const o = `<img src="${n.src}" media-type="secure-img" encryptionKey="${n.encryptionKey}" nonce="${n.nonce}" ipfsUrl="${n.ipfsUrl}" ipfsHash="${n.ipfsHash}" version="2" authTag="${n.authTag}" mimeType="${n.mimeType}" />`;
84
83
  f(e, o);
85
- }, M = (e, t) => f(e, `<img src="${t}" media-type="img" />`), W = `| Column 1 | Column 2 |
84
+ }, M = (e, n) => f(e, `<img src="${n}" media-type="img" />`), W = `| Column 1 | Column 2 |
86
85
  | -------- | -------- |
87
86
  | | |`, c = {
88
87
  bold: (e) => p(e, "**"),
@@ -90,7 +89,7 @@ const p = (e, t, o = t) => {
90
89
  strike: (e) => p(e, "~~"),
91
90
  inlineCode: (e) => p(e, "`"),
92
91
  underline: (e) => p(e, "<u>", "</u>"),
93
- heading: (e, t) => z(e, t),
92
+ heading: (e, n) => z(e, n),
94
93
  bulletList: (e) => y(e, "- "),
95
94
  orderedList: (e) => y(e, "1. "),
96
95
  taskList: (e) => y(e, "- [ ] "),
@@ -98,7 +97,7 @@ const p = (e, t, o = t) => {
98
97
  codeBlock: (e) => f(e, "```\n\n```"),
99
98
  horizontalRule: (e) => f(e, "---"),
100
99
  table: (e) => f(e, W),
101
- link: (e, t) => G(e, t),
100
+ link: (e, n) => G(e, n),
102
101
  undo: (e) => {
103
102
  w(e), e.focus();
104
103
  },
@@ -106,7 +105,7 @@ const p = (e, t, o = t) => {
106
105
  _(e), e.focus();
107
106
  },
108
107
  // Highlight → inline HTML (round-trips via our turndown/DOMPurify rules).
109
- highlight: (e, t) => t ? p(e, `<mark style="background-color: ${t}">`, "</mark>") : p(e, "<mark>", "</mark>")
108
+ highlight: (e, n) => n ? p(e, `<mark style="background-color: ${n}">`, "</mark>") : p(e, "<mark>", "</mark>")
110
109
  }, H = [
111
110
  [
112
111
  { icon: "Undo", label: "Undo", run: (e) => c.undo(e) },
@@ -189,9 +188,9 @@ const p = (e, t, o = t) => {
189
188
  }
190
189
  ]
191
190
  ], $ = 3, V = H.slice(0, $), U = H.slice($), S = "!h-6 !w-6 !min-w-0", j = 560, C = () => /* @__PURE__ */ m("div", { className: "w-[1px] h-4 vertical-divider mx-1" });
192
- function J({
191
+ function X({
193
192
  view: e,
194
- ipfsImageUploadFn: t,
193
+ ipfsImageUploadFn: n,
195
194
  onError: o
196
195
  }) {
197
196
  const i = (s) => {
@@ -201,8 +200,8 @@ function J({
201
200
  const h = (x = a.files) == null ? void 0 : x[0];
202
201
  if (!(!h || !h.type.includes("image/")))
203
202
  try {
204
- if (t) {
205
- const g = await t(h);
203
+ if (n) {
204
+ const g = await n(h);
206
205
  K(s, {
207
206
  src: URL.createObjectURL(h),
208
207
  ipfsUrl: g.ipfsUrl,
@@ -229,9 +228,9 @@ function J({
229
228
  return;
230
229
  }
231
230
  s.run(a);
232
- }, n = D(null), [d, r] = E(!1);
231
+ }, t = D(null), [d, r] = E(!1);
233
232
  A(() => {
234
- const s = n.current;
233
+ const s = t.current;
235
234
  if (!s || typeof ResizeObserver > "u") return;
236
235
  const a = () => r(s.clientWidth < j);
237
236
  a();
@@ -255,7 +254,7 @@ function J({
255
254
  return /* @__PURE__ */ m("div", { className: "flex items-center px-2 py-2 border-b color-border-default shrink-0", children: /* @__PURE__ */ L(
256
255
  "div",
257
256
  {
258
- ref: n,
257
+ ref: t,
259
258
  className: "flex items-center gap-0.5 flex-1 min-w-0 overflow-hidden",
260
259
  children: [
261
260
  V.map((s, a) => b(s, a > 0)),
@@ -286,5 +285,5 @@ function J({
286
285
  ) });
287
286
  }
288
287
  export {
289
- J as default
288
+ X as default
290
289
  };