@plannotator/ui 0.41.2 → 0.42.0

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/types.ts CHANGED
@@ -1,6 +1,16 @@
1
1
  import type { DiagramAnchor } from '@plannotator/core/diagram-anchor';
2
+ import type { DiagramRenderKind } from '@plannotator/core/annotatable';
2
3
 
3
4
  export type { DiagramAnchor } from '@plannotator/core/diagram-anchor';
5
+ export type { DiagramRenderKind } from '@plannotator/core/annotatable';
6
+
7
+ /**
8
+ * How a document's body is rendered. `markdown` and `html` are the original
9
+ * pair; the two diagram kinds are whole-file diagram sources (.mmd/.mermaid,
10
+ * .dot/.gv) that render as ONE diagram through the same engine a ```mermaid
11
+ * fence uses — see diagramDocumentBlocks in utils/parser.
12
+ */
13
+ export type DocumentRenderAs = 'markdown' | 'html' | DiagramRenderKind;
4
14
 
5
15
  export enum AnnotationType {
6
16
  DELETION = 'DELETION',
@@ -192,6 +202,16 @@ export interface Block {
192
202
  order: number; // Sorting order
193
203
  startLine: number; // 1-based line number in source
194
204
  sourceLineCount?: number; // Number of source lines consumed when it differs from content lines
205
+ /**
206
+ * Line offset a diagram comment's `sourceLine` is measured from, when it
207
+ * differs from `startLine`. A ```mermaid fence in a document has its opening
208
+ * line ABOVE the diagram's first line, so `startLine` is the right offset
209
+ * there and this stays unset. A whole-file diagram source (.mmd/.dot) has no
210
+ * fence: its first line IS document line 1, so it sets 0 here while
211
+ * `startLine` keeps naming the block's own first line for the export's
212
+ * `(lines a–b)` label.
213
+ */
214
+ diagramSourceLineOffset?: number;
195
215
  }
196
216
 
197
217
  export interface DiffResult {
package/utils/parser.ts CHANGED
@@ -541,6 +541,39 @@ export const resolveReferenceLinks = (markdown: string): string => {
541
541
  .join('\n');
542
542
  };
543
543
 
544
+ /**
545
+ * The block list for a whole-file diagram source (`plannotator annotate
546
+ * flow.mmd`): ONE code block carrying the file's raw text, which `Viewer`
547
+ * hands to the same `DiagramBlock` a ```mermaid fence in a plan produces.
548
+ * Everything downstream — diagram comments, the annotations rail, the export's
549
+ * `Diagram node <label> (<id>), line <n>` location line, drafts, restore — is
550
+ * the fence path unchanged.
551
+ *
552
+ * `diagramSourceLineOffset: 0` is the load-bearing part. `DiagramBlock` passes
553
+ * it as the viewer's `sourceLineOffset` and the codec adds it to the 1-based
554
+ * line WITHIN the diagram source; for a fence that offset is the fence's own
555
+ * opening line, which sits one line above the diagram's first line. A diagram
556
+ * FILE has no fence, so its first line is document line 1 and the offset is 0
557
+ * — the 1 a synthesized ```mermaid wrapper would produce puts every exported
558
+ * diagram line one too high. `startLine`/`sourceLineCount` still describe the
559
+ * block itself, so the export's `(lines a–b)` label names the file's real
560
+ * span.
561
+ */
562
+ export const diagramDocumentBlocks = (text: string, kind: 'mermaid' | 'graphviz'): Block[] => [
563
+ {
564
+ id: 'block-0',
565
+ type: 'code',
566
+ content: text,
567
+ // `dot` is what isGraphvizLanguage reads for the Graphviz engine.
568
+ language: kind === 'graphviz' ? 'dot' : 'mermaid',
569
+ order: 1,
570
+ startLine: 1,
571
+ // A trailing newline ends the last line, it does not start another.
572
+ sourceLineCount: text === '' ? 0 : text.replace(/\n$/, '').split('\n').length,
573
+ diagramSourceLineOffset: 0,
574
+ },
575
+ ];
576
+
544
577
  /**
545
578
  * A simplified markdown parser that splits content into linear blocks.
546
579
  * For a production app, we would use a robust AST walker (remark),
package/utils/sharing.ts CHANGED
@@ -8,7 +8,8 @@
8
8
  * Inspired by textarea.my's approach.
9
9
  */
10
10
 
11
- import { AnnotationType, type Annotation, type ImageAttachment } from '../types';
11
+ import { AnnotationType, type Annotation, type DocumentRenderAs, type ImageAttachment } from '../types';
12
+ import { isDiagramRenderKind } from '@plannotator/core/annotatable';
12
13
  import { compress, decompress } from '@plannotator/core/compress';
13
14
  import { encrypt, decrypt } from '@plannotator/core/crypto';
14
15
 
@@ -31,6 +32,32 @@ export interface SharePayload {
31
32
  r?: 'html'; // render mode flag (omitted = markdown)
32
33
  }
33
34
 
35
+ /**
36
+ * The markdown a document ships as in a share payload's `p`.
37
+ *
38
+ * A whole-file diagram source (.mmd/.dot) has no fence of its own — the
39
+ * annotate session renders it as one diagram because the SERVER said so in
40
+ * `renderAs`, and a share link carries no server. So it travels as the fenced
41
+ * form, which the portal's ordinary markdown parse turns back into the same
42
+ * diagram block. This is deliberately smaller than adding a render-mode flag
43
+ * (`r: 'html'`'s sibling): the portal needs no change at all.
44
+ *
45
+ * Diagram comments themselves still degrade to text comments in a share link,
46
+ * exactly as they do today — `diagramAnchor` is dropped like `htmlAnchor`
47
+ * (see sharing.multiTarget.test.ts).
48
+ */
49
+ export function shareableDocumentMarkdown(
50
+ markdown: string,
51
+ renderAs: DocumentRenderAs | undefined,
52
+ ): string {
53
+ if (!isDiagramRenderKind(renderAs) || markdown === '') return markdown;
54
+ const language = renderAs === 'graphviz' ? 'dot' : 'mermaid';
55
+ // A diagram source can itself contain a ``` run only in a comment/label;
56
+ // a four-backtick fence keeps such a body intact.
57
+ const fence = markdown.includes('```') ? '````' : '```';
58
+ return `${fence}${language}\n${markdown.replace(/\n+$/, '')}\n${fence}`;
59
+ }
60
+
34
61
  /**
35
62
  * Convert ShareableImage[] to ImageAttachment[] (handles old plain-string format)
36
63
  */