@restless-dreams/orbit 0.0.0-stage → 0.2.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.
Files changed (124) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +168 -2
  3. package/dist/bin/orbit.js +11666 -0
  4. package/dist/bin/orbit.js.map +60 -0
  5. package/dist/chunk-fkdfgtx9.js +17295 -0
  6. package/dist/chunk-fkdfgtx9.js.map +75 -0
  7. package/dist/chunk-y748hzcr.js +82 -0
  8. package/dist/chunk-y748hzcr.js.map +10 -0
  9. package/dist/chunk-zze4tc9n.js +408 -0
  10. package/dist/chunk-zze4tc9n.js.map +10 -0
  11. package/dist/core/auto-render.d.ts +85 -0
  12. package/dist/core/branch-colors.d.ts +57 -0
  13. package/dist/core/browser.d.ts +23 -0
  14. package/dist/core/create.d.ts +23 -0
  15. package/dist/core/diagnostics.d.ts +40 -0
  16. package/dist/core/dispatch.d.ts +23 -0
  17. package/dist/core/document-options.d.ts +18 -0
  18. package/dist/core/document-source.d.ts +128 -0
  19. package/dist/core/editing.d.ts +66 -0
  20. package/dist/core/engine/animation-clock.d.ts +40 -0
  21. package/dist/core/engine/camera.d.ts +70 -0
  22. package/dist/core/engine/colors.d.ts +51 -0
  23. package/dist/core/engine/display.d.ts +125 -0
  24. package/dist/core/engine/export.d.ts +32 -0
  25. package/dist/core/engine/glide.d.ts +34 -0
  26. package/dist/core/engine/labels.d.ts +106 -0
  27. package/dist/core/engine/node-drag.d.ts +49 -0
  28. package/dist/core/engine/scene.d.ts +160 -0
  29. package/dist/core/engine/spin.d.ts +62 -0
  30. package/dist/core/engine/surface-pattern.d.ts +20 -0
  31. package/dist/core/engine/text-measure.d.ts +116 -0
  32. package/dist/core/engine/views.d.ts +361 -0
  33. package/dist/core/extensions.d.ts +155 -0
  34. package/dist/core/format-upgrades.d.ts +33 -0
  35. package/dist/core/index.d.ts +46 -0
  36. package/dist/core/input-controller.d.ts +116 -0
  37. package/dist/core/languages.d.ts +201 -0
  38. package/dist/core/layout.d.ts +61 -0
  39. package/dist/core/map-tools/definitions.d.ts +71 -0
  40. package/dist/core/map-tools/input.d.ts +62 -0
  41. package/dist/core/map-tools/reading.d.ts +40 -0
  42. package/dist/core/map-tools/tools.d.ts +51 -0
  43. package/dist/core/markdown-writing.d.ts +87 -0
  44. package/dist/core/material.d.ts +25 -0
  45. package/dist/core/media.d.ts +42 -0
  46. package/dist/core/node-attributes.d.ts +31 -0
  47. package/dist/core/node-links.d.ts +25 -0
  48. package/dist/core/other-apps/freemind.d.ts +8 -0
  49. package/dist/core/other-apps/icons.d.ts +16 -0
  50. package/dist/core/other-apps/ideas.d.ts +76 -0
  51. package/dist/core/other-apps/import.d.ts +28 -0
  52. package/dist/core/other-apps/inflate.d.ts +22 -0
  53. package/dist/core/other-apps/markup.d.ts +51 -0
  54. package/dist/core/other-apps/notes.d.ts +80 -0
  55. package/dist/core/other-apps/opml.d.ts +26 -0
  56. package/dist/core/other-apps/reading.d.ts +36 -0
  57. package/dist/core/other-apps/xmind.d.ts +14 -0
  58. package/dist/core/other-apps/zip.d.ts +37 -0
  59. package/dist/core/parser-markdown.d.ts +42 -0
  60. package/dist/core/parser-yaml.d.ts +8 -0
  61. package/dist/core/print-layout.d.ts +70 -0
  62. package/dist/core/render-to-svg.d.ts +57 -0
  63. package/dist/core/renderer/content-painter.d.ts +30 -0
  64. package/dist/core/renderer/dom.d.ts +15 -0
  65. package/dist/core/renderer/families.d.ts +35 -0
  66. package/dist/core/renderer/label-painter.d.ts +93 -0
  67. package/dist/core/renderer/node-painter.d.ts +113 -0
  68. package/dist/core/renderer/numbers.d.ts +2 -0
  69. package/dist/core/renderer/options.d.ts +12 -0
  70. package/dist/core/renderer/rings-and-links.d.ts +23 -0
  71. package/dist/core/renderer/scene-helpers.d.ts +33 -0
  72. package/dist/core/renderer/trees.d.ts +22 -0
  73. package/dist/core/serializer-markdown.d.ts +18 -0
  74. package/dist/core/serializer-yaml.d.ts +2 -0
  75. package/dist/core/source-patch.d.ts +24 -0
  76. package/dist/core/source.d.ts +27 -0
  77. package/dist/core/styles.d.ts +6 -0
  78. package/dist/core/suggest.d.ts +8 -0
  79. package/dist/core/svg-renderer.d.ts +626 -0
  80. package/dist/core/text-layout.d.ts +54 -0
  81. package/dist/core/themes.d.ts +62 -0
  82. package/dist/core/types.d.ts +471 -0
  83. package/dist/core/ui/actions.d.ts +75 -0
  84. package/dist/core/ui/controls.d.ts +61 -0
  85. package/dist/core/ui/detail-sheet.d.ts +88 -0
  86. package/dist/core/ui/frames.d.ts +11 -0
  87. package/dist/core/ui/icons.d.ts +14 -0
  88. package/dist/core/ui/inline-editor.d.ts +79 -0
  89. package/dist/core/ui/media-players.d.ts +65 -0
  90. package/dist/core/ui/media-viewer.d.ts +169 -0
  91. package/dist/core/ui/media-zoom.d.ts +51 -0
  92. package/dist/core/ui/note-markdown.d.ts +19 -0
  93. package/dist/core/ui/outline.d.ts +44 -0
  94. package/dist/core/url-guard.d.ts +40 -0
  95. package/dist/core/utils.d.ts +23 -0
  96. package/dist/core/web-page/page.d.ts +59 -0
  97. package/dist/core/web-page/runtime.d.ts +13 -0
  98. package/dist/core/web-page/start.d.ts +1 -0
  99. package/dist/core/yaml-mini.d.ts +54 -0
  100. package/dist/index.d.ts +1 -0
  101. package/dist/index.js +4357 -0
  102. package/dist/index.js.map +29 -0
  103. package/dist/marked/index.d.ts +31 -0
  104. package/dist/marked/index.js +110 -0
  105. package/dist/marked/index.js.map +10 -0
  106. package/dist/react/index.d.ts +55 -0
  107. package/dist/react/index.js +352 -0
  108. package/dist/react/index.js.map +1 -0
  109. package/dist/web-page.d.ts +2 -0
  110. package/dist/web-page.js +130 -0
  111. package/llms-full.txt +2785 -0
  112. package/llms.txt +36 -0
  113. package/package.json +118 -4
  114. package/skills/orbit/SKILL.md +140 -0
  115. package/skills/orbit/references/editing.md +195 -0
  116. package/skills/orbit/references/extending.md +247 -0
  117. package/skills/orbit/references/format.md +331 -0
  118. package/skills/orbit/references/guide.md +546 -0
  119. package/skills/orbit/references/import-export.md +115 -0
  120. package/skills/orbit/references/languages.md +160 -0
  121. package/skills/orbit/references/map-tools.md +188 -0
  122. package/skills/orbit/references/media.md +160 -0
  123. package/skills/orbit/references/recipes.md +236 -0
  124. package/skills/orbit/references/theming.md +199 -0
@@ -0,0 +1,42 @@
1
+ import type { ParsedOrbitDocument } from './types.js';
2
+ export { OrbitParseError } from './diagnostics.js';
3
+ export { SUPPORTED_SCHEMA_VERSION } from './format-upgrades.js';
4
+ export interface ParseOptions {
5
+ /**
6
+ * Throw an `OrbitParseError` on the first problem instead of recording a
7
+ * diagnostic and carrying on. Off by default; `orbit validate` turns it on.
8
+ */
9
+ strict?: boolean;
10
+ /**
11
+ * The name of the root Orbit makes up for a document with no single top
12
+ * heading and no title, in the reader's language. Default "Untitled map".
13
+ * Its id is `untitled-map` whatever its name.
14
+ */
15
+ untitled?: string;
16
+ }
17
+ /** Text of the generated root when a document has no single top-level heading or title. */
18
+ export declare const UNTITLED_ROOT_TEXT = "Untitled map";
19
+ /** The generated root's id, whatever the `untitled` option names it. */
20
+ export declare const UNTITLED_ROOT_ID = "untitled-map";
21
+ /** Whether an icon reads back from the start of a title (emoji do; other symbols need an `icon:` attribute). */
22
+ export declare const isTitleIcon: (icon: string) => boolean;
23
+ /** The emoji a title starts with, which a map reads as the node's icon, and the text after it; null for a title without one. */
24
+ export declare const leadingEmoji: (title: string) => {
25
+ icon: string;
26
+ text: string;
27
+ } | null;
28
+ export interface TitleParts {
29
+ text: string;
30
+ icon?: string;
31
+ link?: string;
32
+ status?: string;
33
+ tags?: string[];
34
+ }
35
+ /**
36
+ * Reads a heading's or list item's text. `[ ]`, `[x]` and `[/]` set the
37
+ * status, an emoji first is the icon, hashtags at the end are tags, a link
38
+ * gives the node its link, and bold, italics, code and strikethrough show
39
+ * as plain text. A backslash keeps any of those characters literal.
40
+ */
41
+ export declare const parseTitle: (raw: string) => TitleParts;
42
+ export declare const parseOrbitMarkdown: (input: string, options?: ParseOptions) => ParsedOrbitDocument;
@@ -0,0 +1,8 @@
1
+ import type { ParsedOrbitDocument } from './types.js';
2
+ export interface ParseYamlOptions {
3
+ /** Throw on the first problem instead of recording a diagnostic. Off by default. */
4
+ strict?: boolean;
5
+ /** The name of the root Orbit makes up for several top-level nodes and no title. Default "Untitled map"; its id is `untitled-map` whatever its name. */
6
+ untitled?: string;
7
+ }
8
+ export declare const parseOrbitYAML: (input: string, options?: ParseYamlOptions) => ParsedOrbitDocument;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * A map laid out for paper: its title, the map as a picture that fits the
3
+ * page, then every idea in reading order with its details, link, note and
4
+ * media. Orbit's web pages print with it, and so can any page that shows a
5
+ * map: lay it out in an element that only shows in print.
6
+ */
7
+ import { type OrbitNodeType, type OrbitStatusStyle } from './extensions.js';
8
+ import { type OrbitStrings } from './languages.js';
9
+ import { type OrbitThemeName } from './themes.js';
10
+ import type { OrbitDocument, OrbitNode, OrbitRendererTheme, OrbitThemePreset, ViewMode } from './types.js';
11
+ export interface OrbitPrintOptions {
12
+ /** The heading at the top. Default: the map's `title`, or its root's text. */
13
+ title?: string;
14
+ /** Whether the map's picture comes before the outline. Default: true. */
15
+ picture?: boolean;
16
+ /** What the picture shows: `focus`, a node with its orbit, or `all`, the whole map. Default: the map's `view`, or `focus`. */
17
+ viewMode?: ViewMode;
18
+ /** The node in the middle of the picture in focus mode, by id. Default: the root. */
19
+ focus?: string;
20
+ /**
21
+ * The map's theme: a theme name or `{ preset, tokens }`. Default: the
22
+ * document's. Paper is light, so a dark theme prints as its light
23
+ * counterpart (see `printTheme`), and nothing prints a background.
24
+ */
25
+ theme?: OrbitThemePreset | (string & {}) | OrbitRendererTheme;
26
+ /** The map's colors: the root's, then one per top-level branch. Default: the document's, or the theme's. */
27
+ palette?: string[];
28
+ /** The language of the few words the layout has: a BCP 47 tag. Default: English. */
29
+ language?: string;
30
+ /** Words to change, over the language's. */
31
+ strings?: Partial<OrbitStrings>;
32
+ /** Resolves relative picture, video and link URLs. Default: the document's `baseUrl`. */
33
+ baseUrl?: string;
34
+ /** Node types by name, before the registered ones: their icons, colors, labels and details. */
35
+ nodeTypes?: Record<string, OrbitNodeType>;
36
+ /** Status words and how they look, before the registered ones. */
37
+ statuses?: Record<string, OrbitStatusStyle>;
38
+ /** The type a node that names none is laid out as (see `RendererOptions.nodeTypeFor`). */
39
+ nodeTypeFor?: (node: OrbitNode) => string | undefined;
40
+ /** Prefix for the picture's SVG ids; give each layout in one page its own. Default: `orbit-print`. */
41
+ idPrefix?: string;
42
+ }
43
+ /** The light theme each dark built-in theme prints as. Light themes print as themselves. */
44
+ export declare const PRINT_THEMES: Readonly<Partial<Record<OrbitThemePreset, OrbitThemeName>>>;
45
+ /**
46
+ * The theme a map prints in: the map's own when it's light, otherwise its
47
+ * light counterpart (`PRINT_THEMES`), always without a background. A dark
48
+ * theme of your own keeps only its colors (`color-root` to `color-7`).
49
+ */
50
+ export declare const printTheme: (theme: string | OrbitRendererTheme | undefined) => OrbitRendererTheme;
51
+ /**
52
+ * Lays a map out for print in `container`, replacing what it held, and
53
+ * returns the layout: the title, the map as a picture that fits the page,
54
+ * then every idea in reading order, nested by depth, with its icon, status,
55
+ * priority, tags, link (its address printed), note, picture and video. An
56
+ * idea stays whole across page breaks, and a heading stays with what
57
+ * follows it.
58
+ *
59
+ * It's laid out on screen like any element: hide it there and show it in
60
+ * print, as Orbit's web pages do.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * import { renderPrintLayout } from '@restless-dreams/orbit';
65
+ *
66
+ * renderPrintLayout(document.querySelector('#print'), markdown, { viewMode: 'all' });
67
+ * // #print { display: none } @media print { #print { display: block } #app { display: none } }
68
+ * ```
69
+ */
70
+ export declare const renderPrintLayout: (container: HTMLElement, input: string | OrbitDocument, options?: OrbitPrintOptions) => HTMLElement;
@@ -0,0 +1,57 @@
1
+ import { type OrbitNodeType, type OrbitStatusStyle } from './extensions.js';
2
+ import type { OrbitDocument, OrbitNode, OrbitRendererTheme, OrbitThemePreset, ViewMode } from './types.js';
3
+ import { type OrbitStrings } from './languages.js';
4
+ /**
5
+ * The largest width or height the exporter accepts: a million pixels, far
6
+ * past any drawing. The label grid numbers its 64 px cells, and past about
7
+ * 6 × 10⁹ px a side those numbers stop being exact; past about 6 × 10¹⁷ its
8
+ * loops stop advancing and the export never finishes.
9
+ */
10
+ export declare const MAX_SVG_EXPORT_SIZE = 1000000;
11
+ export interface RenderToSVGOptions {
12
+ /** Width of the drawing, in pixels: positive, at most `MAX_SVG_EXPORT_SIZE`. Default 800. */
13
+ width?: number;
14
+ /** Height of the drawing, in pixels: positive, at most `MAX_SVG_EXPORT_SIZE`. Default 600. */
15
+ height?: number;
16
+ /** `focus` (default) or `all` for the overview. */
17
+ viewMode?: ViewMode;
18
+ /** The node at the center in focus mode, by id. Default: the root. */
19
+ focus?: string;
20
+ /** A theme name or an object of theme values. Default: the document's theme, or `paper`. */
21
+ theme?: OrbitThemePreset | (string & {}) | OrbitRendererTheme;
22
+ palette?: string[];
23
+ maxDepth?: number;
24
+ showRings?: boolean;
25
+ /** The SVG's title and accessible name. Default: the document's title, or the root's text. */
26
+ title?: string;
27
+ /** The language of the few words the drawing has (an untitled idea, the empty map): a BCP 47 tag. Default: English. */
28
+ language?: string;
29
+ /** Words to change, over the language's. */
30
+ strings?: Partial<OrbitStrings>;
31
+ /** Resolves relative image URLs. */
32
+ baseUrl?: string;
33
+ /** Size the SVG to its container (100% wide and tall) instead of in pixels. */
34
+ responsive?: boolean;
35
+ /** Prefix for the SVG's ids; give each SVG inlined in one page its own. */
36
+ idPrefix?: string;
37
+ /** Node types by name, before the registered ones: their icons, colors and tokens. */
38
+ nodeTypes?: Record<string, OrbitNodeType>;
39
+ /** Status words and how they look, before the registered ones. */
40
+ statuses?: Record<string, OrbitStatusStyle>;
41
+ /** The type a node that names none is drawn as, for display only (see `RendererOptions.nodeTypeFor`). */
42
+ nodeTypeFor?: (node: OrbitNode) => string | undefined;
43
+ }
44
+ /**
45
+ * Renders a map to a standalone SVG string, without a browser: for files,
46
+ * the command line, static sites and server rendering. It draws what the
47
+ * renderer shows at rest, with the theme's colors resolved to plain values
48
+ * and the labels as SVG text.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * import { renderToSVGString } from '@restless-dreams/orbit';
53
+ *
54
+ * const svg = renderToSVGString('# Launch\n## Research\n## Build', { width: 1200, height: 800, theme: 'cosmos' });
55
+ * ```
56
+ */
57
+ export declare const renderToSVGString: (input: string | OrbitDocument | OrbitNode, options?: RenderToSVGOptions) => string;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * What node types draw inside their nodes (`render`), in an HTML layer over
3
+ * the map: a 100 × 100 px box per node, moved and scaled with it each frame,
4
+ * created when the node comes on the map and cleaned up when it leaves.
5
+ */
6
+ import type { Display } from '../engine/display.js';
7
+ import type { Viewport } from '../engine/camera.js';
8
+ import type { MapExtensions } from '../extensions.js';
9
+ /** What node contents need from the map around them. */
10
+ export interface ContentHost {
11
+ extensions(): MapExtensions;
12
+ viewport(): Viewport;
13
+ /** Nodes changed since the last frame. */
14
+ changedIds(): ReadonlySet<string>;
15
+ }
16
+ export declare class ContentPainter {
17
+ private readonly layer;
18
+ private readonly host;
19
+ private readonly contents;
20
+ constructor(layer: HTMLDivElement, host: ContentHost);
21
+ /** Cleans up every node's content. */
22
+ clear(): void;
23
+ /**
24
+ * Draws what node types render inside their nodes: a 100 × 100 px box per
25
+ * node, moved and scaled with it each frame, created when the node comes
26
+ * on the map and cleaned up when it leaves.
27
+ */
28
+ paint(display: Display): void;
29
+ private remove;
30
+ }
@@ -0,0 +1,15 @@
1
+ /** The page around a map: its elements, events, focus and scrolling, as the renderer reads them. */
2
+ import { OrbitWords } from '../languages.js';
3
+ export declare const reportListenerError: (error: unknown) => void;
4
+ export declare const createEmptyState: (words: OrbitWords) => HTMLDivElement;
5
+ /** The empty map's message and hint, in `words`' language. */
6
+ export declare const fillEmptyState: (empty: HTMLDivElement, words: OrbitWords) => void;
7
+ /** The + in arrow-key order around the orbit. */
8
+ export declare const SLOT_STOP = "\0slot";
9
+ export declare const isAddSlot: (target: EventTarget | null) => boolean;
10
+ export declare const nodeIdFrom: (target: EventTarget | null) => string | null;
11
+ export declare const isFocusVisible: (target: EventTarget | null) => boolean;
12
+ export declare const isApplePlatform: () => boolean;
13
+ /** Whether the document, or any element around `element`, can scroll. */
14
+ export declare const scrollsAround: (element: Element) => boolean;
15
+ export declare const parentAcrossShadow: (element: Element) => Element | null;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Families: the renderer draws nodes in groups of siblings, and a group whose
3
+ * members come or go together in a flight (one `Cluster`) moves as one, with
4
+ * one transform per frame instead of one per node.
5
+ */
6
+ import type { Cluster, DisplayNode } from '../engine/display.js';
7
+ import { NodeView } from '../engine/views.js';
8
+ /**
9
+ * Children of one parent, drawn in one group in the layer of their role. In
10
+ * a flight, the members of a family often come or go together, growing out
11
+ * of their parent or shrinking into it, and then the group moves instead of
12
+ * each of them: one transform per frame instead of hundreds.
13
+ */
14
+ export interface Family {
15
+ group: SVGGElement;
16
+ layer: 'sun' | 'moon' | 'node';
17
+ parentId: string;
18
+ transform: string;
19
+ opacity: string;
20
+ hidden: boolean;
21
+ /** This frame's members, and the motion they all share (null if they don't), once worked out. */
22
+ members: FamilyMember[];
23
+ motion?: Cluster | null;
24
+ }
25
+ export interface FamilyMember {
26
+ entry: DisplayNode;
27
+ view: NodeView;
28
+ family: Family;
29
+ }
30
+ export declare const sameMotion: (first: Cluster, second: Cluster) => boolean;
31
+ /** The motion all of a family's members share this frame, or null when they move each on their own. */
32
+ export declare const familyMotion: (family: Family) => Cluster | null;
33
+ /** A cluster too faint or too small to draw. */
34
+ export declare const clusterHidden: (cluster: Cluster) => boolean;
35
+ export declare const moveFamily: (family: Family, motion: Cluster | null) => void;
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Names and "+N" counts, in the HTML layer over the map. Each frame's names
3
+ * are planned for its display (see `planLabels`), shown a share at a time on
4
+ * an animated map, and ride along as one layer while only the camera moves.
5
+ */
6
+ import type { LabelFonts } from '../engine/text-measure.js';
7
+ import type { Viewport } from '../engine/camera.js';
8
+ import type { Display, DisplayNode } from '../engine/display.js';
9
+ import type { Scene } from '../engine/scene.js';
10
+ import type { MapExtensions } from '../extensions.js';
11
+ import { type LabelPlacement, type NodeView } from '../engine/views.js';
12
+ /** What the names need from the map around them. */
13
+ export interface LabelHost {
14
+ extensions(): MapExtensions;
15
+ viewport(): Viewport;
16
+ /** The scene on screen, or null during a flight: names keep their order for a scene. */
17
+ restingScene(): Scene | null;
18
+ inFlight(): boolean;
19
+ /** Whether only the camera moves: a camera flight, a wheel zoom, a glide or a drag. */
20
+ cameraMoving(): boolean;
21
+ /** Nodes changed since the last frame. */
22
+ changedIds(): ReadonlySet<string>;
23
+ /** The node whose text is being typed, which shows the field instead of its name. */
24
+ editedId(): string | null;
25
+ animationsEnabled(): boolean;
26
+ requestPaint(): void;
27
+ nodeView(id: string): NodeView | undefined;
28
+ themeTokens(): Record<string, string>;
29
+ }
30
+ export declare class LabelPainter {
31
+ private readonly layer;
32
+ private readonly fonts;
33
+ private readonly host;
34
+ private readonly labels;
35
+ private readonly counts;
36
+ /**
37
+ * Nodes in the order their labels are placed, for one display, and their
38
+ * ids for a scene at rest: the order holds while the orbit spins, only the
39
+ * entries are new each frame.
40
+ */
41
+ private labelOrder;
42
+ /** The camera labels and counts were last placed for, and the nodes they were placed for. */
43
+ private placed;
44
+ /** Names planned to show that wait for a later frame (see `LABELS_SHOWN_PER_FRAME`), placed for `placed`'s camera, and whether the map moved then. */
45
+ private waiting;
46
+ private layerTransform;
47
+ private readonly lightText;
48
+ /** The theme's label colors, resolved when first needed after each theme change. */
49
+ private textColors;
50
+ constructor(layer: HTMLDivElement, fonts: LabelFonts, host: LabelHost);
51
+ /** Places the names and counts for this frame's display, or lets them ride along with the camera. */
52
+ paint(display: Display): void;
53
+ /** Where the node's name is drawn now. */
54
+ placementOf(id: string): LabelPlacement | undefined;
55
+ /** Forgets which nodes' names are light (their colors may have changed). */
56
+ forgetLightText(): void;
57
+ /** Forgets the theme's text colors and which names are light (the theme changed). */
58
+ forgetTextColors(): void;
59
+ /** Forgets a node that left the map. */
60
+ forgetNode(id: string): void;
61
+ /** Takes every name and count off the map. */
62
+ clear(): void;
63
+ /**
64
+ * While only the camera moves (a pan, a pinch, a zoom, a glide), labels and counts ride along
65
+ * as one layer instead of being placed again on every frame, which for a big view means
66
+ * restyling hundreds of them. They're placed again once the camera rests, or has gone far
67
+ * enough that they'd be too big or too small, or missing for nodes coming into view. Returns
68
+ * the layer's transform from where they were placed, or null to place them now.
69
+ */
70
+ private ride;
71
+ /** Fits and places every label again, where it is (the fonts changed). */
72
+ refit(): void;
73
+ /** Whether the labels were placed for this very view: the same nodes, the camera where it was, nothing changed. */
74
+ private still;
75
+ private setLayerTransform;
76
+ private paintLabels;
77
+ /** Shows a planned label: its view (made when it has none yet) placed and fitted as planned. */
78
+ private showLabel;
79
+ /**
80
+ * While the labels ride along with the camera, shows the next names
81
+ * waiting to: placed as planned, for the camera the labels were placed
82
+ * at, so they ride along with the rest.
83
+ */
84
+ private showWaiting;
85
+ /** Whether the node shows a picture or its type's own content, so its label goes outside. */
86
+ private showsImage;
87
+ /** Whether the theme's light text has more contrast on this node's color than its dark text. Measured once per node and color. */
88
+ usesLightText(entry: DisplayNode): boolean;
89
+ /** The theme's label colors as plain values. */
90
+ private resolveTextColors;
91
+ /** The "+N" of nodes with children that aren't drawn, at their lower right. In the label layer, so they ride along with the labels. */
92
+ private paintCounts;
93
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * The nodes on the map: a view per node, drawn in groups of siblings (see
3
+ * `families.ts`), kept in step with each frame's display. Small flat bodies
4
+ * become specks, an orbit spinning turns the layers its planets and moons are
5
+ * in, and while only the camera moves the nodes hold still.
6
+ */
7
+ import type { Display } from '../engine/display.js';
8
+ import type { Scene } from '../engine/scene.js';
9
+ import type { MapExtensions } from '../extensions.js';
10
+ import type { OrbitWords } from '../languages.js';
11
+ import { NodeView, type ViewIds } from '../engine/views.js';
12
+ /** What the nodes need from the map around them. */
13
+ export interface NodeHost {
14
+ extensions(): MapExtensions;
15
+ words(): OrbitWords;
16
+ baseUrl(): string | undefined;
17
+ /** The scene on screen (the one a flight leaves, until it lands). */
18
+ scene(): Scene | null;
19
+ inFlight(): boolean;
20
+ /** Whether the orbit is at rest: not dragged, coasting or settling. */
21
+ spinResting(): boolean;
22
+ /** Whether the slow drift is running. */
23
+ driftRunning(): boolean;
24
+ /** The node whose text is being typed, if any. */
25
+ editedId(): string | null;
26
+ /** The node lifted to be dragged, the bodies carried under the press (null when nothing is), and the node it would drop into. */
27
+ drag(): {
28
+ liftedId: string | null;
29
+ carried: Set<string> | null;
30
+ targetId: string | null;
31
+ };
32
+ /** Nodes changed since the last frame. */
33
+ changedIds(): ReadonlySet<string>;
34
+ requestPaint(): void;
35
+ /** A node's view came on the map: the map's tab stops need placing again. */
36
+ tabStopsChanged(): void;
37
+ /** A node's view left the map. */
38
+ viewRemoved(id: string): void;
39
+ }
40
+ /** The layers nodes are drawn in. */
41
+ export interface NodeLayers {
42
+ moons: SVGGElement;
43
+ nodes: SVGGElement;
44
+ suns: SVGGElement;
45
+ carried: SVGGElement;
46
+ }
47
+ export declare class NodePainter {
48
+ private readonly root;
49
+ private readonly definitions;
50
+ private readonly ids;
51
+ private readonly layers;
52
+ private readonly host;
53
+ /** The orbit's turn as last written to the layers of its planets and moons (see `paintTurn`). */
54
+ private turnTransform;
55
+ /** The turn the shading of specks is turned back by (see `turnShading`). */
56
+ private speckLighting;
57
+ /** The on-screen radius (px) below which bodies were last drawn as specks (see `speckRadius`). */
58
+ private specksBelow;
59
+ /**
60
+ * The nodes as last painted at rest, with what they were drawn for: while
61
+ * only the camera or the orbit's turn changes, they hold still, all but
62
+ * the bodies turned back upright (see `paintNodes`).
63
+ */
64
+ private stillNodes;
65
+ private readonly nodeViews;
66
+ /** The family group each node's element is in (see `Family`). */
67
+ private readonly nodeGroups;
68
+ private readonly families;
69
+ /** Counts flights, so each one's arrivals get groups of their own. */
70
+ private flightCount;
71
+ private familyCount;
72
+ /** The lifted node and the drop target last drawn, so a change draws every node again. */
73
+ private dragMarks;
74
+ constructor(root: HTMLDivElement, definitions: SVGDefsElement, ids: ViewIds, layers: NodeLayers, host: NodeHost);
75
+ /** The view drawing a node, if it's on the map. */
76
+ view(id: string): NodeView | undefined;
77
+ /** Every node's view, by id. */
78
+ entries(): IterableIterator<[string, NodeView]>;
79
+ /** A new flight starts: the ideas it brings in get families of their own. */
80
+ startFlight(): void;
81
+ /** Takes a node's view off the map. */
82
+ removeView(id: string): void;
83
+ /** Takes every node off the map. */
84
+ clear(): void;
85
+ /**
86
+ * Turns the layers of the planets and moons with the orbit (see
87
+ * `OrbitTurn`). Returns the turn (degrees) its bodies are drawn in, or
88
+ * undefined when each is drawn where it is.
89
+ */
90
+ paintTurn(display: Display): number | undefined;
91
+ paintNodes(display: Display, turn: number | undefined): void;
92
+ /**
93
+ * The on-screen radius (px) below which flat bodies are specks, for this
94
+ * screen's pixels; the stylesheet sizes specks' rims from it.
95
+ */
96
+ private speckRadius;
97
+ /**
98
+ * A family whose members don't all move alike in this flight (some travel
99
+ * on, the rest leave) splits in two, the fewer of them moving to a group of
100
+ * their own, so each part moves as one.
101
+ */
102
+ private splitIfMixed;
103
+ /**
104
+ * The group a node is drawn in: its family's, in the layer of its role. A
105
+ * node stays in its group while its parent and role do, so nothing moves
106
+ * between groups when a flight lands; the ideas a flight brings in get a
107
+ * group of their own, so they can move as one while their siblings travel.
108
+ */
109
+ private placeInFamily;
110
+ /** A new family's group; one that starts hidden (newcomers yet to appear) is hidden before it joins the map, so its members aren't styled until they show. */
111
+ private createFamily;
112
+ private moveIntoFamily;
113
+ }
@@ -0,0 +1,2 @@
1
+ /** Numbers as the renderer writes them into the DOM: rounded, so unchanged values compare equal and attributes stay short. */
2
+ export declare const round: (value: number, decimals?: number) => number;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The renderer's options: the caller's merged over the document's over the
3
+ * defaults, and the values Orbit works out from them (insets, spin settings).
4
+ */
5
+ import type { Insets } from '../engine/camera.js';
6
+ import { type SpinSettings } from '../engine/spin.js';
7
+ import type { OrbitInsets, OrbitSpinOptions, RendererOptions } from '../types.js';
8
+ export type ResolvedRendererOptions = RendererOptions & Required<Pick<RendererOptions, 'viewMode' | 'showRings' | 'interactive' | 'orbitAnimation' | 'orbitSpeed' | 'showControls'>>;
9
+ export declare const spinSettings: (options: OrbitSpinOptions | undefined) => SpinSettings;
10
+ export declare const mergeRendererOptions: (base: RendererOptions, overrides: RendererOptions) => ResolvedRendererOptions;
11
+ /** The room the page's controls take at the map's edges, as numbers of px (none for anything else). */
12
+ export declare const resolveInsets: (insets: OrbitInsets | undefined) => Insets;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The rings around orbits and the lines between nodes in the overview, kept
3
+ * in step with each frame's display: one view each, written only when what it
4
+ * shows changed.
5
+ */
6
+ import type { Display } from '../engine/display.js';
7
+ /** The layers rings and links are drawn in, below the nodes. */
8
+ export interface RingAndLinkLayers {
9
+ rings: SVGGElement;
10
+ links: SVGGElement;
11
+ }
12
+ export declare class RingsAndLinks {
13
+ private readonly layers;
14
+ private readonly rings;
15
+ private readonly links;
16
+ constructor(layers: RingAndLinkLayers);
17
+ /** Draws the display's rings (unless `showRings` is off) and links. */
18
+ paint(display: Display, showRings: boolean): void;
19
+ /** Takes every ring and link off the map. */
20
+ clear(): void;
21
+ private paintRings;
22
+ private paintLinks;
23
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Views of a scene the renderer works out: where its orbit starts, its planets
3
+ * in order, what of a display shows, where a view lands inside another, and a
4
+ * flight's display with a new or renamed node in it.
5
+ */
6
+ import type { Camera, Similarity, Viewport } from '../engine/camera.js';
7
+ import { type Display } from '../engine/display.js';
8
+ import type { Scene, SceneNode } from '../engine/scene.js';
9
+ /** Resizes within this share of the size a view was laid out for keep its layout: no one sees 2% in a node's size. */
10
+ export declare const RELAYOUT_THRESHOLD = 0.02;
11
+ /** A node an edit just added, and where it was typed: its first frame is there. */
12
+ export interface Arrival {
13
+ id: string;
14
+ x: number;
15
+ y: number;
16
+ radius: number;
17
+ }
18
+ /** Whether `size` is within `RELAYOUT_THRESHOLD` of `laidOut` in both directions. */
19
+ export declare const closeInSize: (size: Viewport, laidOut: Viewport) => boolean;
20
+ /** How far the nearest planet's edge (or the +'s) is from the sun, in world units: the room around the sun. */
21
+ export declare const innerEdges: WeakMap<Scene, number>;
22
+ export declare const innerOrbitEdge: (scene: Scene) => number;
23
+ /** Planets clockwise from the top. */
24
+ export declare const orderedPlanets: (scene: Scene) => SceneNode[];
25
+ export declare const clockwiseFromTop: (angle: number) => number;
26
+ /** Places `target` so its fitted view matches `camera`: the views cross-fade without the camera moving. */
27
+ export declare const overlayPlacement: (target: Scene, camera: Camera) => Similarity;
28
+ /** Drops what has already faded out, so it isn't carried into the next flight. */
29
+ export declare const visiblePart: (display: Display) => Display;
30
+ /** `display` with a node an edit just added already where it was typed, so it stays there as the others make room. */
31
+ export declare const withArrival: (display: Display, arrival: Arrival | null, target: Scene) => Display;
32
+ /** `display` with the nodes an edit gave new ids under the new ones, so they move rather than leave and arrive. */
33
+ export declare const renameNodes: (display: Display, renamed: ReadonlyMap<string, string>) => Display;
@@ -0,0 +1,22 @@
1
+ /** Maps as the renderer takes them: documents or trees, compared, checked and carried over between renders. */
2
+ import { OrbitWords } from '../languages.js';
3
+ import type { OrbitDocument, OrbitNode } from '../types.js';
4
+ import type { EditorText } from '../ui/inline-editor.js';
5
+ /** The field's text for a new idea under `parent`. */
6
+ export declare const newIdeaText: (parent: OrbitNode, words: OrbitWords) => EditorText;
7
+ export declare const sameValues: (first: unknown, second: unknown) => boolean;
8
+ /** Says how to call an editing method that got something other than an object. */
9
+ export declare const expectObject: (method: string, value: unknown, example: string) => void;
10
+ /** Whether two trees hold the same map: the same nodes, ids and attributes, wherever their source wrote them. */
11
+ export declare const sameTree: (first: OrbitNode, second: OrbitNode) => boolean;
12
+ /**
13
+ * Moves where a fresh parse of the same map came from onto the tree as drawn:
14
+ * each node's own place, and the source itself (keyed by node, see
15
+ * `documentSource`), so saving writes the new text against the nodes the map
16
+ * already shows.
17
+ */
18
+ export declare const transplantSource: (kept: OrbitNode, fresh: OrbitNode) => void;
19
+ /** An object's entries that have a value. */
20
+ export declare const definedEntries: (value: object) => Record<string, unknown>;
21
+ export declare const isOrbitDocument: (input: OrbitNode | OrbitDocument) => input is OrbitDocument;
22
+ export declare const isEmptyTree: (tree: OrbitNode) => boolean;
@@ -0,0 +1,18 @@
1
+ import type { OrbitDocument } from './types.js';
2
+ export interface SerializeOptions {
3
+ /**
4
+ * Keep the source's own lines for everything an edit didn't change (the
5
+ * default, for a document parsed from markdown): its formatting, and the
6
+ * text Orbit doesn't read, such as other HTML comments or frontmatter
7
+ * keys of other apps. `false` writes the whole map in Orbit's own form.
8
+ */
9
+ keepSource?: boolean;
10
+ }
11
+ /**
12
+ * A map as orbit-md. A document parsed from markdown comes back as it was
13
+ * written, with only what changed since rewritten, so maps written by hand
14
+ * or by other apps keep their formatting and everything Orbit doesn't read.
15
+ * Other documents (built in code, or read from YAML) are written in Orbit's
16
+ * own form: headings for the root and its children, lists below them.
17
+ */
18
+ export declare const serializeOrbitMarkdown: (doc: OrbitDocument, options?: SerializeOptions) => string;
@@ -0,0 +1,2 @@
1
+ import type { OrbitDocument } from './types.js';
2
+ export declare const serializeOrbitYAML: (doc: OrbitDocument) => string;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Saving an edited map without rewriting it. Every line an edit didn't
3
+ * change is written back as it was, and only what changed is written again,
4
+ * in place, in Orbit's own form: a renamed idea gets a new title, a moved
5
+ * one takes its lines along. A map written by hand, or by another app,
6
+ * keeps its formatting and everything Orbit doesn't read: other HTML
7
+ * comments, rules, the frontmatter keys of other apps.
8
+ *
9
+ * The result is read back before it's used: when it doesn't read as the
10
+ * edited map, saving falls back to rewriting the changed ideas whole, then
11
+ * to Orbit's own form for the whole map.
12
+ */
13
+ import type { OrbitDocument } from './types.js';
14
+ import { type DocumentSource } from './document-source.js';
15
+ /**
16
+ * The document as markdown, its source's lines kept wherever nothing
17
+ * changed; null when that can't be done faithfully.
18
+ */
19
+ export declare const patchMarkdown: (document: OrbitDocument, source: DocumentSource) => string | null;
20
+ /**
21
+ * The patched text without checking that it reads back, or why it couldn't
22
+ * be made: for tests and debugging.
23
+ */
24
+ export declare const patchedText: (document: OrbitDocument, source: DocumentSource, coarse?: boolean) => string;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Source text helpers shared by the dispatcher and both parsers. Normalizing
3
+ * never adds or removes lines, so diagnostics keep pointing at the line the
4
+ * author wrote.
5
+ */
6
+ /**
7
+ * Strips a byte-order mark, converts CRLF/CR line endings to LF, and removes
8
+ * indentation shared by every non-blank line, so markdown indented inside
9
+ * HTML or a template literal parses like flush-left markdown.
10
+ */
11
+ export declare const normalizeSource: (input: string) => string;
12
+ /** The indentation every non-blank line shares, which `normalizeSource` removes. */
13
+ export declare const sharedIndentation: (text: string) => string;
14
+ export declare const dedent: (text: string) => string;
15
+ export declare const firstContentLineIndex: (lines: string[]) => number;
16
+ export interface FrontmatterBlock {
17
+ /** The YAML between the fences. */
18
+ yaml: string;
19
+ /** 0-based index of the opening `---` line. */
20
+ openIndex: number;
21
+ /** 0-based index of the closing `---` line. */
22
+ closeIndex: number;
23
+ }
24
+ /** Frontmatter is a `---` fenced block starting on the first non-blank line. */
25
+ export declare const findFrontmatter: (lines: string[]) => FrontmatterBlock | null;
26
+ /** 1-based line of the first `key:` entry inside a frontmatter or YAML block. */
27
+ export declare const lineOfKey: (lines: string[], key: string, fromIndex?: number, toIndex?: number) => number | undefined;