@restless-dreams/orbit 0.0.0-stage → 0.1.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 (100) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +165 -2
  3. package/dist/bin/orbit.js +8907 -0
  4. package/dist/bin/orbit.js.map +48 -0
  5. package/dist/chunk-0gwh723s.js +408 -0
  6. package/dist/chunk-0gwh723s.js.map +10 -0
  7. package/dist/chunk-7n00wx0t.js +82 -0
  8. package/dist/chunk-7n00wx0t.js.map +10 -0
  9. package/dist/chunk-mtrnm0yc.js +16993 -0
  10. package/dist/chunk-mtrnm0yc.js.map +63 -0
  11. package/dist/core/auto-render.d.ts +85 -0
  12. package/dist/core/browser.d.ts +23 -0
  13. package/dist/core/create.d.ts +23 -0
  14. package/dist/core/diagnostics.d.ts +40 -0
  15. package/dist/core/dispatch.d.ts +23 -0
  16. package/dist/core/document-options.d.ts +18 -0
  17. package/dist/core/document-source.d.ts +128 -0
  18. package/dist/core/editing.d.ts +63 -0
  19. package/dist/core/engine/animation-clock.d.ts +40 -0
  20. package/dist/core/engine/camera.d.ts +70 -0
  21. package/dist/core/engine/colors.d.ts +51 -0
  22. package/dist/core/engine/display.d.ts +125 -0
  23. package/dist/core/engine/export.d.ts +32 -0
  24. package/dist/core/engine/glide.d.ts +34 -0
  25. package/dist/core/engine/labels.d.ts +106 -0
  26. package/dist/core/engine/node-drag.d.ts +49 -0
  27. package/dist/core/engine/scene.d.ts +159 -0
  28. package/dist/core/engine/spin.d.ts +62 -0
  29. package/dist/core/engine/surface-pattern.d.ts +20 -0
  30. package/dist/core/engine/text-measure.d.ts +116 -0
  31. package/dist/core/engine/views.d.ts +353 -0
  32. package/dist/core/extensions.d.ts +155 -0
  33. package/dist/core/format-upgrades.d.ts +33 -0
  34. package/dist/core/index.d.ts +36 -0
  35. package/dist/core/input-controller.d.ts +109 -0
  36. package/dist/core/languages.d.ts +199 -0
  37. package/dist/core/layout.d.ts +61 -0
  38. package/dist/core/map-tools/definitions.d.ts +71 -0
  39. package/dist/core/map-tools/input.d.ts +62 -0
  40. package/dist/core/map-tools/reading.d.ts +40 -0
  41. package/dist/core/map-tools/tools.d.ts +51 -0
  42. package/dist/core/markdown-writing.d.ts +87 -0
  43. package/dist/core/material.d.ts +25 -0
  44. package/dist/core/media.d.ts +42 -0
  45. package/dist/core/node-attributes.d.ts +31 -0
  46. package/dist/core/node-links.d.ts +25 -0
  47. package/dist/core/parser-markdown.d.ts +42 -0
  48. package/dist/core/parser-yaml.d.ts +8 -0
  49. package/dist/core/render-to-svg.d.ts +57 -0
  50. package/dist/core/serializer-markdown.d.ts +18 -0
  51. package/dist/core/serializer-yaml.d.ts +2 -0
  52. package/dist/core/source-patch.d.ts +24 -0
  53. package/dist/core/source.d.ts +27 -0
  54. package/dist/core/styles.d.ts +6 -0
  55. package/dist/core/suggest.d.ts +8 -0
  56. package/dist/core/svg-renderer.d.ts +729 -0
  57. package/dist/core/text-layout.d.ts +54 -0
  58. package/dist/core/themes.d.ts +62 -0
  59. package/dist/core/types.d.ts +463 -0
  60. package/dist/core/ui/actions.d.ts +75 -0
  61. package/dist/core/ui/controls.d.ts +61 -0
  62. package/dist/core/ui/detail-sheet.d.ts +88 -0
  63. package/dist/core/ui/frames.d.ts +11 -0
  64. package/dist/core/ui/icons.d.ts +14 -0
  65. package/dist/core/ui/inline-editor.d.ts +79 -0
  66. package/dist/core/ui/media-players.d.ts +65 -0
  67. package/dist/core/ui/media-viewer.d.ts +169 -0
  68. package/dist/core/ui/media-zoom.d.ts +51 -0
  69. package/dist/core/ui/note-markdown.d.ts +19 -0
  70. package/dist/core/ui/outline.d.ts +44 -0
  71. package/dist/core/url-guard.d.ts +40 -0
  72. package/dist/core/utils.d.ts +23 -0
  73. package/dist/core/web-page/page.d.ts +58 -0
  74. package/dist/core/web-page/runtime.d.ts +13 -0
  75. package/dist/core/web-page/start.d.ts +1 -0
  76. package/dist/core/yaml-mini.d.ts +54 -0
  77. package/dist/index.d.ts +1 -0
  78. package/dist/index.js +1448 -0
  79. package/dist/index.js.map +17 -0
  80. package/dist/marked/index.d.ts +31 -0
  81. package/dist/marked/index.js +110 -0
  82. package/dist/marked/index.js.map +10 -0
  83. package/dist/react/index.d.ts +55 -0
  84. package/dist/react/index.js +352 -0
  85. package/dist/react/index.js.map +1 -0
  86. package/dist/web-page.d.ts +2 -0
  87. package/dist/web-page.js +130 -0
  88. package/llms-full.txt +2585 -0
  89. package/llms.txt +35 -0
  90. package/package.json +118 -4
  91. package/skills/orbit/SKILL.md +140 -0
  92. package/skills/orbit/references/editing.md +194 -0
  93. package/skills/orbit/references/extending.md +247 -0
  94. package/skills/orbit/references/format.md +303 -0
  95. package/skills/orbit/references/guide.md +522 -0
  96. package/skills/orbit/references/languages.md +159 -0
  97. package/skills/orbit/references/map-tools.md +188 -0
  98. package/skills/orbit/references/media.md +160 -0
  99. package/skills/orbit/references/recipes.md +227 -0
  100. package/skills/orbit/references/theming.md +184 -0
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Text broken into pieces and wrapped, for labels in exported SVGs and for
3
+ * planning where labels go. Without a font to measure with, widths are
4
+ * estimates from the kind of each character: CJK, kana, Hangul and emoji
5
+ * are about as wide as the font is tall, and other letters a little over
6
+ * half that.
7
+ */
8
+ import type { TextMeasure } from './engine/text-measure.js';
9
+ export interface TextLayout {
10
+ lines: string[];
11
+ truncated: boolean;
12
+ lineHeight: number;
13
+ totalHeight: number;
14
+ }
15
+ /** Average width of a narrow character, in ems. */
16
+ export declare const NARROW_EMS = 0.55;
17
+ /**
18
+ * Characters about as wide as the font is tall: Hangul jamo, CJK (radicals
19
+ * and punctuation through ideographs, kana, bopomofo and Yi), Hangul
20
+ * syllables, CJK compatibility and full-width forms, the ideographs past
21
+ * U+20000, and emoji.
22
+ */
23
+ export declare const WIDE_CHARACTER: RegExp;
24
+ /** The characters of `text` as people see them, so an emoji with its modifiers stays whole. */
25
+ export declare const graphemes: (text: string) => string[];
26
+ /** How many narrow and wide characters `text` has. */
27
+ export declare const characterWidths: (text: string) => {
28
+ narrow: number;
29
+ wide: number;
30
+ };
31
+ /** Estimated width of `text`, in ems. */
32
+ export declare const textEms: (text: string) => number;
33
+ /** A piece of text that stays on one line, and whether a space comes before it. */
34
+ export interface TextUnit {
35
+ text: string;
36
+ spaced: boolean;
37
+ }
38
+ /** Spaces a line may break at: every kind but the no-break ones, which keep their neighbors together. */
39
+ export declare const BREAKING_SPACE: RegExp;
40
+ /** A word cut where it may break onto another line. */
41
+ export declare const wordPieces: (word: string) => string[];
42
+ /**
43
+ * Where text may break: between words, inside long words where they read
44
+ * (`wordPieces`), and between the characters of scripts written without spaces.
45
+ */
46
+ export declare const breakUnits: (text: string) => TextUnit[];
47
+ /** Joins units back into text, with their spaces. */
48
+ export declare const joinUnits: (units: TextUnit[]) => string;
49
+ /**
50
+ * Wraps text into at most `maxLines` lines of `maxWidth` pixels, ending with
51
+ * an ellipsis when cut. Widths are estimates, unless `measure` measures them
52
+ * in the font the text is drawn with.
53
+ */
54
+ export declare const wrapText: (text: string, maxWidth: number, fontSize: number, maxLines?: number, measure?: Pick<TextMeasure, "ems">) => TextLayout;
@@ -0,0 +1,62 @@
1
+ import type { OrbitRendererTheme, OrbitThemePreset } from './types.js';
2
+ /**
3
+ * Theme tokens. Each token is a CSS custom property: set `--orbit-<token>` on
4
+ * the map or any ancestor to override it. Presets only provide defaults:
5
+ * internally every token resolves as `var(--orbit-<token>, <preset value>)`.
6
+ */
7
+ export declare const THEME_TOKENS: readonly ["sans-font", "serif-font", "mono-font", "font-family", "label-font", "display-font", "label-weight", "display-weight", "label-letter-spacing", "label-shadow", "surface", "surface-pattern", "text", "muted-text", "root-text", "node-text", "node-text-inverse", "color-root", "color-1", "color-2", "color-3", "color-4", "color-5", "color-6", "color-7", "shade-light", "shade-dark", "node-fill-opacity", "moon-opacity", "node-highlight", "node-terminator", "node-shading", "node-shade-circle", "node-stroke", "node-stroke-tint", "node-stroke-width", "badge-stroke", "node-shadow", "node-shadow-tint", "node-shadow-opacity", "node-shadow-offset", "node-shadow-size", "sun-shadow-opacity", "sun-shadow-size", "sun-halo", "sun-halo-tint", "sun-halo-opacity", "sun-halo-width", "sun-halo-dash", "sun-halo-size", "ring-stroke", "ring-tint", "ring-opacity", "ring-width", "ring-dash", "link-stroke", "link-tint", "link-opacity", "link-width", "link-dash", "focus-ring", "note-indicator", "control-background", "control-border", "control-text", "control-muted-text", "control-active-background", "control-active-text", "control-shadow", "control-blur", "tooltip-background", "tooltip-text", "action-background", "action-border", "action-text", "action-shadow", "sheet-background", "sheet-text", "sheet-muted-text", "sheet-border", "sheet-backdrop", "sheet-shadow", "sheet-blur", "chip-background", "chip-text", "link-text", "status-active", "status-done", "status-blocked", "status-todo", "status-neutral", "error-background", "error-border", "error-text"];
8
+ export type OrbitThemeToken = (typeof THEME_TOKENS)[number];
9
+ export type OrbitThemeTokens = Record<OrbitThemeToken, string>;
10
+ export type OrbitThemeName = 'paper' | 'night' | 'glass' | 'glass-night' | 'cosmos' | 'blueprint' | 'ink' | 'contrast' | 'flat' | 'flat-night' | 'material' | 'material-night' | 'liquid' | 'liquid-night';
11
+ export declare const ORBIT_THEME_PRESETS: Readonly<Record<OrbitThemeName, Readonly<OrbitThemeTokens>>>;
12
+ /** Whether `value` names a built-in theme: one of the presets or `auto`. */
13
+ export declare const isOrbitThemePreset: (value: unknown) => value is OrbitThemePreset;
14
+ /** The built-in theme a `theme` option starts from (registered names followed), `paper` when it names none. */
15
+ export declare const themeName: (theme: string | OrbitRendererTheme | undefined) => OrbitThemePreset;
16
+ /**
17
+ * Names a theme for every map, so `theme: 'brand'` works in options, in a
18
+ * document's frontmatter and on `<orbit-map theme="brand">`. It starts from
19
+ * `preset` (a built-in theme or another registered one) and sets its own
20
+ * tokens. Returns a function that removes it again.
21
+ */
22
+ export declare const registerTheme: (name: string, theme: OrbitRendererTheme) => () => void;
23
+ /** Whether `value` names a theme: a built-in one, `auto`, or a registered one. */
24
+ export declare const isThemeName: (value: unknown) => value is string;
25
+ /** Every theme name: the built-in ones, `auto`, then the registered ones. */
26
+ export declare const themeNames: () => string[];
27
+ /**
28
+ * A `theme` option with registered names replaced by what they stand for:
29
+ * `'brand'` becomes its `{ preset, tokens }`, and `{ preset: 'brand', tokens }`
30
+ * adds its own tokens on top of brand's.
31
+ */
32
+ export declare const expandTheme: (theme: string | OrbitRendererTheme | undefined) => string | OrbitRendererTheme | undefined;
33
+ /**
34
+ * Combines a `theme` option with one set before it, such as the document's
35
+ * `theme:`: a theme object without a `preset` builds on the earlier theme
36
+ * instead of replacing it.
37
+ */
38
+ export declare const mergeThemes: (base: string | OrbitRendererTheme | undefined, override: string | OrbitRendererTheme | undefined) => string | OrbitRendererTheme | undefined;
39
+ /** Concrete token values for a theme name, built in or registered, e.g. for exports outside a page. `auto` resolves to `paper`. */
40
+ export declare const themeTokens: (name: string | undefined) => OrbitThemeTokens;
41
+ /**
42
+ * Concrete values for every token: the preset's, then the theme object's,
43
+ * then any the page resolved (`page`, already concrete). A token that refers
44
+ * to another, such as the label font following `font-family`, follows it
45
+ * through all three.
46
+ */
47
+ export declare const resolveThemeTokens: (preset: OrbitThemePreset | undefined, theme?: OrbitRendererTheme, page?: Partial<Record<OrbitThemeToken, string>>) => OrbitThemeTokens;
48
+ /** CSS that gives `.orbit[data-orbit-theme="…"]` each preset's token defaults. */
49
+ export declare const themeStylesheet: () => string;
50
+ /** The token values a `theme` object sets. Unknown tokens and empty values are skipped. */
51
+ export declare const themeObjectTokens: (theme: OrbitRendererTheme | undefined) => Partial<OrbitThemeTokens>;
52
+ /**
53
+ * Custom properties to set inline on the map for a `theme` object. Each
54
+ * value replaces the preset's default but still yields to a `--orbit-*`
55
+ * property the page sets in its own CSS.
56
+ */
57
+ export declare const themeOverrides: (theme: OrbitRendererTheme | undefined) => Record<string, string>;
58
+ /**
59
+ * The colors nodes are painted with: the custom palette when given (first
60
+ * entry for the root), otherwise the theme's palette tokens.
61
+ */
62
+ export declare const resolvePalette: (palette: string[] | undefined) => string[];
@@ -0,0 +1,463 @@
1
+ /**
2
+ * Framework-agnostic types for Orbit.
3
+ */
4
+ import type { OrbitStrings } from './languages.js';
5
+ import type { OrbitDiagnostic } from './diagnostics.js';
6
+ import type { OrbitThemeName, OrbitThemeToken } from './themes.js';
7
+ import type { OrbitAction, OrbitNodeType, OrbitStatusStyle } from './extensions.js';
8
+ /** One node of a map, as the parsers produce it. */
9
+ export interface OrbitNode {
10
+ /** Unique within the map: a slug of the text (`Product roadmap` becomes `product-roadmap`), or the `id` attribute. */
11
+ id: string;
12
+ /** The node's label, without its icon. */
13
+ text: string;
14
+ /** Depth in the tree: 0 for the root. */
15
+ level: number;
16
+ /** Any CSS color. Without one, the node takes its branch's color from the theme or `palette`. */
17
+ color?: string;
18
+ /** An emoji (or any short symbol) shown before the text. */
19
+ icon?: string;
20
+ /** Hide the node's children until it is opened. */
21
+ collapsed?: boolean;
22
+ /**
23
+ * The node's type, such as `milestone`. A type defined in the `nodeTypes`
24
+ * option or with `registerNodeType` sets its look, content and actions.
25
+ */
26
+ type?: string;
27
+ /**
28
+ * The version of its type the node was written for, when the type has
29
+ * changed its fields since its first one: `type: task@2`. Not written
30
+ * means 1. See `OrbitNodeType.version`.
31
+ */
32
+ typeVersion?: number;
33
+ /**
34
+ * A URL the node links to, offered as a button when the node is in focus.
35
+ * `#id` links to another node of the map: the button flies there.
36
+ */
37
+ link?: string;
38
+ /** Longer text, shown in the detail sheet: markdown unless `noteFormat` is `plain`. */
39
+ note?: string;
40
+ noteFormat?: 'markdown' | 'plain';
41
+ tags?: string[];
42
+ /**
43
+ * Free text. Some words get a colored dot: `active` (also `doing`, `in progress`),
44
+ * `done` (`complete`, `shipped`), `blocked` (`stuck`, `at risk`), `todo` (`planned`, `next`).
45
+ */
46
+ status?: string;
47
+ priority?: number;
48
+ /** A picture shown inside the node and in the detail sheet. */
49
+ image?: {
50
+ src: string;
51
+ alt?: string;
52
+ caption?: string;
53
+ };
54
+ /** A video (YouTube, Vimeo or a file) played in the detail sheet. */
55
+ video?: {
56
+ src: string;
57
+ provider?: 'youtube' | 'vimeo' | 'native';
58
+ thumbnail?: string;
59
+ caption?: string;
60
+ };
61
+ /** A page shown in a frame in the detail sheet. */
62
+ embed?: {
63
+ src: string;
64
+ caption?: string;
65
+ };
66
+ /** Attributes Orbit doesn't use itself, kept for your own code (`<!-- orbit owner: Ana -->`). */
67
+ attrs?: Record<string, unknown>;
68
+ /** Where the node comes from in a markdown source. */
69
+ source?: {
70
+ line: number;
71
+ raw: string;
72
+ };
73
+ children: OrbitNode[];
74
+ /** The parent node. Set by the parsers as a non-enumerable property, so trees stay JSON-serializable. */
75
+ parent?: OrbitNode;
76
+ }
77
+ /** Orbit's own buttons for a node: its picture, video, embed, note, link, and its type's details. */
78
+ export type OrbitContentAction = 'image' | 'video' | 'embed' | 'note' | 'link' | 'details';
79
+ /** A button pressed under the focused node or in its detail sheet. */
80
+ export interface OrbitActionEvent {
81
+ node: OrbitNode;
82
+ /** One of Orbit's buttons, or the `id` of one of your actions. */
83
+ action: OrbitContentAction | (string & {});
84
+ sourceEvent: MouseEvent | KeyboardEvent;
85
+ }
86
+ /** The `action` event: call `preventDefault()` to skip what the button does (the detail sheet, the link, or your action's `run`). */
87
+ export interface OrbitActionDetail extends OrbitActionEvent {
88
+ preventDefault(): void;
89
+ readonly defaultPrevented: boolean;
90
+ }
91
+ /**
92
+ * What a map reports, by event name. Listen with `renderer.on(name, listener)`,
93
+ * or for `orbit-<name>` DOM events, which bubble from the map's container
94
+ * (and out of `<orbit-map>`).
95
+ */
96
+ export interface OrbitEventMap {
97
+ /** The focused node changed. `path` runs from the root to `node`. */
98
+ 'focus-change': {
99
+ node: OrbitNode;
100
+ path: OrbitNode[];
101
+ };
102
+ /** The map switched between focus mode and the overview. */
103
+ 'view-mode-change': {
104
+ mode: ViewMode;
105
+ };
106
+ /** A node was clicked or activated with the keyboard, before the map reacts. */
107
+ 'node-click': {
108
+ node: OrbitNode;
109
+ };
110
+ /** A content button under the focused node was pressed. */
111
+ action: OrbitActionDetail;
112
+ /** A spun orbit came to rest, with this planet on top. */
113
+ 'spin-settle': {
114
+ planet: OrbitNode;
115
+ };
116
+ /**
117
+ * A node was long-pressed, right-clicked, or chosen with the context menu
118
+ * key: the place for a menu of things to do with it. A DOM listener calls
119
+ * `preventDefault()` to take the press (see `onNodeContext`).
120
+ */
121
+ 'node-context': OrbitNodeContextEvent;
122
+ /** The map was edited with `addNode`, `updateNode`, `removeNode` or `moveNode`. */
123
+ edit: OrbitEdit;
124
+ /** The field for typing on the map opened: on a node, or in the orbit for a new idea. */
125
+ 'editor-open': OrbitEditorEvent;
126
+ /** The field for typing on the map closed. */
127
+ 'editor-close': OrbitEditorEvent;
128
+ /** A node is dragged somewhere else on an editable map: lifted, carried over a place, or let go (see `phase`). */
129
+ 'node-drag': OrbitNodeDragEvent;
130
+ /** The media viewer opened, or stepped to another picture or video. */
131
+ 'media-open': OrbitMediaEvent;
132
+ /** The media viewer closed. */
133
+ 'media-close': OrbitMediaEvent;
134
+ /** The video in the media viewer started, paused, moved on, ended or was muted; while it plays, its time a few times a second. */
135
+ 'media-state': OrbitMediaState;
136
+ }
137
+ /** A node's picture or video in the media viewer. */
138
+ export interface OrbitMediaEvent {
139
+ node: OrbitNode;
140
+ /** `image`, the node's picture, or `video`, its video. */
141
+ kind: 'image' | 'video';
142
+ /** Its place among the map's pictures and videos, in reading order, from 0. */
143
+ index: number;
144
+ /** How many pictures and videos the viewer steps through. */
145
+ total: number;
146
+ }
147
+ /** What `openMedia` shows. */
148
+ export interface OrbitMediaOptions {
149
+ /** For a node with a picture and a video: which to show. Default: the picture. */
150
+ kind?: 'image' | 'video';
151
+ /** Start a video playing as it opens. Default true. */
152
+ autoplay?: boolean;
153
+ /** Start a video this many seconds in. YouTube and Vimeo start at the whole second. Default 0. */
154
+ startAt?: number;
155
+ }
156
+ /** The video in the media viewer, as it plays (see the `media-state` event). */
157
+ export interface OrbitMediaState {
158
+ node: OrbitNode;
159
+ /** Playing, rather than paused, not started yet, or ended. */
160
+ playing: boolean;
161
+ /** Where it is, in seconds from the start. */
162
+ time: number;
163
+ /** How long it is, in seconds, once known. */
164
+ duration: number | null;
165
+ /** It played to the end. */
166
+ ended: boolean;
167
+ /**
168
+ * Its sound is off. Browsers let a video start with sound only once the
169
+ * reader has interacted with the page; a video started before that plays
170
+ * muted.
171
+ */
172
+ muted: boolean;
173
+ }
174
+ /**
175
+ * A node dragged somewhere else (see `editable`). `start` as it leaves its
176
+ * place under the finger, the moment to close a menu the long press opened;
177
+ * `over` whenever where it would go changes; `end` when it's let go, after
178
+ * the `edit` that moved it, if it moved.
179
+ */
180
+ export interface OrbitNodeDragEvent {
181
+ phase: 'start' | 'over' | 'end';
182
+ node: OrbitNode;
183
+ /**
184
+ * Where it would go, or (on `end`) went: into `parent`, at `index` among
185
+ * its children (null: after the last). On `start`, where it was; null over
186
+ * no place, and on an `end` that put it back.
187
+ */
188
+ parent: OrbitNode | null;
189
+ index: number | null;
190
+ }
191
+ /** The field for typing a node's text on the map (see `editable`, `editNode` and `editNewNode`). */
192
+ export interface OrbitEditorEvent {
193
+ /** The node whose text is typed, or null for a new idea. */
194
+ node: OrbitNode | null;
195
+ /** For a new idea, the node it goes under. */
196
+ parent: OrbitNode | null;
197
+ }
198
+ /** A long press, right click or context menu key on a node. */
199
+ export interface OrbitNodeContextEvent {
200
+ node: OrbitNode;
201
+ /** Where, in CSS pixels from the map's top left corner: the press, or the node's center for the keyboard. */
202
+ x: number;
203
+ y: number;
204
+ }
205
+ /** An edit to the map, as the `edit` event and `onEdit` report it. */
206
+ export interface OrbitEdit {
207
+ kind: 'add' | 'update' | 'remove' | 'move';
208
+ /** The node added, changed, removed or moved. */
209
+ node: OrbitNode;
210
+ /** The whole tree after the edit. `renderer.toMarkdown()` writes it as orbit-md. */
211
+ tree: OrbitNode;
212
+ }
213
+ /** What `addNode` and `updateNode` take: a node's text and attributes. */
214
+ export type OrbitNodeInput = Partial<Pick<OrbitNode, 'text' | 'icon' | 'color' | 'status' | 'priority' | 'tags' | 'collapsed' | 'link' | 'note' | 'noteFormat' | 'image' | 'video' | 'embed' | 'type' | 'typeVersion' | 'attrs'>>;
215
+ /** What `addNode` takes: a node's text and attributes, and the nodes to add under it, as many levels down as you like. */
216
+ export type OrbitNewNode = OrbitNodeInput & {
217
+ text: string;
218
+ children?: OrbitNewNode[];
219
+ };
220
+ export type OrbitEventName = keyof OrbitEventMap;
221
+ /** `focus`: one node at the center with its children around it. `all`: the overview of the whole tree. */
222
+ export type ViewMode = 'focus' | 'all';
223
+ /** A built-in theme, or `auto` for `paper` or `night` following the reader's light or dark preference. */
224
+ export type OrbitThemePreset = OrbitThemeName | 'auto';
225
+ export interface ContainerSize {
226
+ width: number;
227
+ height: number;
228
+ }
229
+ /** Options a document sets in its frontmatter (markdown) or top-level keys (YAML). */
230
+ export interface OrbitDocumentOptions {
231
+ /** The map's accessible name and SVG title. */
232
+ title?: string;
233
+ /** A theme name, as written (unknown names are reported and ignored). */
234
+ theme?: string;
235
+ /** Written `view:` in the document. */
236
+ viewMode?: ViewMode;
237
+ showRings?: boolean;
238
+ interactive?: boolean;
239
+ /** Written `animation:` in the document. */
240
+ orbitAnimation?: boolean;
241
+ /** Written `speed:` in the document: seconds per turn of the orbit's drift. */
242
+ orbitSpeed?: number;
243
+ palette?: string[];
244
+ /** Height in pixels, used by `<orbit-map>` elements and marked placeholders. */
245
+ height?: number;
246
+ maxDepth?: number;
247
+ className?: string;
248
+ baseUrl?: string;
249
+ /** The format version the document is written for. */
250
+ schemaVersion?: number;
251
+ }
252
+ /** A parsed map: its tree, its options and the problems the parser worked around. */
253
+ export interface OrbitDocument {
254
+ root: OrbitNode;
255
+ options: OrbitDocumentOptions;
256
+ /**
257
+ * Frontmatter or top-level YAML keys Orbit doesn't read (another app's,
258
+ * or a newer Orbit's), as written. Both serializers write them back, so
259
+ * nothing a document says is lost by reading and saving it.
260
+ */
261
+ extra?: Record<string, unknown>;
262
+ /** Problems the parser recovered from, one line each ("Line 4: …"). */
263
+ warnings: string[];
264
+ /** The same problems with a code, line and severity. Always set on parse results. */
265
+ diagnostics?: OrbitDiagnostic[];
266
+ }
267
+ /** A document as the parsers return it, with its diagnostics always set. */
268
+ export type ParsedOrbitDocument = OrbitDocument & {
269
+ diagnostics: OrbitDiagnostic[];
270
+ };
271
+ /**
272
+ * A theme with your own values: `{ preset: 'night', tokens: { surface: '#0b1020', 'ring-dash': 'none' } }`.
273
+ * Each token sets the matching `--orbit-*` CSS custom property on the map,
274
+ * so a value the page sets in its own CSS still wins.
275
+ */
276
+ export interface OrbitRendererTheme {
277
+ /** The theme to start from: a built-in one or one registered with `registerTheme`. Without one, the document's theme (or `paper`). */
278
+ preset?: OrbitThemePreset | (string & {});
279
+ /** Token values by name, as listed in `THEME_TOKENS` (`surface`, `color-1`, `ring-dash`, …). */
280
+ tokens?: Partial<Record<OrbitThemeToken, string>>;
281
+ }
282
+ /** How a flicked orbit spins in focus mode. */
283
+ export interface OrbitSpinOptions {
284
+ /** Seconds for a free spin to lose about two thirds of its speed. Default 1.4. */
285
+ decay?: number;
286
+ /** Fastest spin, in degrees per second. Default 1440 (four turns a second). */
287
+ maxSpeed?: number;
288
+ /** Bring the nearest planet to the top as a spin comes to rest. Off by default. */
289
+ snap?: 'planet' | false;
290
+ /** Vibrate briefly as planets pass the top, on devices that support it. Off by default. */
291
+ haptics?: boolean;
292
+ }
293
+ /** How the map responds to the wheel, trackpads and pinches. */
294
+ export interface OrbitZoomOptions {
295
+ /**
296
+ * `auto` (default): the wheel zooms freely when the map is the whole page
297
+ * and needs Ctrl or ⌘ when the page scrolls; `always`; `modifier`; or
298
+ * `false` to ignore the wheel.
299
+ */
300
+ wheel?: 'auto' | 'always' | 'modifier' | false;
301
+ /** Smallest zoom, relative to the fitted view. Default 0.4. */
302
+ minimum?: number;
303
+ /** Largest zoom, relative to the fitted view. Default 6. */
304
+ maximum?: number;
305
+ }
306
+ /**
307
+ * How a map looks and behaves. Every option is optional; options passed to
308
+ * the renderer win over the document's frontmatter.
309
+ */
310
+ /** Room the page's own controls take at the map's edges, in px (see `RendererOptions.insets`). */
311
+ export interface OrbitInsets {
312
+ top?: number;
313
+ right?: number;
314
+ bottom?: number;
315
+ left?: number;
316
+ }
317
+ export interface RendererOptions {
318
+ /** The first view: `focus` (default) or `all`, the overview. */
319
+ viewMode?: ViewMode;
320
+ /**
321
+ * The node in focus when the map first draws, by id: to open a map where
322
+ * the reader left it. Default: the root. Later renders keep the reader's place.
323
+ */
324
+ focus?: string;
325
+ /** Draw the dashed orbit rings. Default true. */
326
+ showRings?: boolean;
327
+ /** `false` draws a still picture: no clicks, drags, zoom or keyboard. Default true. */
328
+ interactive?: boolean;
329
+ /** Keep the orbit turning slowly on its own. */
330
+ orbitAnimation?: boolean;
331
+ /** Seconds per revolution of `orbitAnimation`. */
332
+ orbitSpeed?: number;
333
+ /** Levels below the root to render (1 = root + direct children). */
334
+ maxDepth?: number;
335
+ /** Node colors: the first for the root, then one per top-level branch (cycling). Default: the theme's. */
336
+ palette?: string[];
337
+ /**
338
+ * A theme name (`'night'`, `'cosmos'`, or one registered with
339
+ * `registerTheme`) or a theme object. An object without a `preset` keeps
340
+ * the document's theme and changes the tokens it names.
341
+ */
342
+ theme?: OrbitThemePreset | (string & {}) | OrbitRendererTheme;
343
+ /** The map's accessible name. Default: the document's `title`. */
344
+ ariaLabel?: string;
345
+ /**
346
+ * The language of the map's controls, sheets and announcements: a BCP 47
347
+ * tag such as `es` or `pt-BR`. Default: the language the map's element is
348
+ * in (the closest `lang` attribute), then English. Orbit speaks English and
349
+ * Spanish; `registerLanguage` adds others.
350
+ */
351
+ language?: string;
352
+ /** Words to change on this map only, over its language's: `{ zoomIn: 'Closer' }`. */
353
+ strings?: Partial<OrbitStrings>;
354
+ /** Breadcrumbs, the view switch, the list button and zoom buttons. Default true. */
355
+ showControls?: boolean;
356
+ /** How a flicked orbit spins. */
357
+ spin?: OrbitSpinOptions;
358
+ /** How the wheel, trackpads and pinches zoom. */
359
+ zoom?: OrbitZoomOptions;
360
+ /** Navigation flight length in milliseconds, or `auto` to scale with the distance travelled. */
361
+ transitionDuration?: 'auto' | number;
362
+ /** A node was clicked or activated with the keyboard, before the map reacts. */
363
+ onNodeClick?: (node: OrbitNode) => void;
364
+ onViewModeChange?: (mode: ViewMode) => void;
365
+ /** A button was pressed. Return `false` to skip what it does (the detail sheet, the link, or your action's `run`). */
366
+ onAction?: (event: OrbitActionEvent) => void | false;
367
+ /** A new node is in focus. */
368
+ onFocusChange?: (node: OrbitNode) => void;
369
+ /**
370
+ * A node was long-pressed, right-clicked or chosen with the context menu
371
+ * key: show a menu of things to do with it at (`x`, `y`). With this
372
+ * callback or a `node-context` listener, the press is yours: it doesn't
373
+ * open the node, and the browser's own menu stays closed.
374
+ */
375
+ onNodeContext?: (event: OrbitNodeContextEvent) => void;
376
+ /** The map was edited with `addNode`, `updateNode`, `removeNode` or `moveNode`; save `renderer.toMarkdown()` to keep it. */
377
+ onEdit?: (edit: OrbitEdit) => void;
378
+ /** The field for typing on the map opened. */
379
+ onEditorOpen?: (event: OrbitEditorEvent) => void;
380
+ /** The field for typing on the map closed. */
381
+ onEditorClose?: (event: OrbitEditorEvent) => void;
382
+ /** A node is dragged somewhere else (see `editable` and the `node-drag` event). */
383
+ onNodeDrag?: (event: OrbitNodeDragEvent) => void;
384
+ /**
385
+ * How long (ms) a finger or pen holds still on a node before it counts as
386
+ * a long press (see `onNodeContext`). Default 500; apps can pass their
387
+ * platform's own, such as Android's 400.
388
+ */
389
+ longPressDelay?: number;
390
+ /**
391
+ * The parts of the map the page covers with its own controls, such as a
392
+ * toolbar floating over its bottom edge, in px from each edge. Views are
393
+ * fitted into what's left, and the map still draws under the controls.
394
+ * Changing them glides a fitted view to its new place.
395
+ */
396
+ insets?: OrbitInsets;
397
+ /**
398
+ * Build the map on the map: a + in the orbit adds an idea, typed right
399
+ * in its new planet, and a long press, a right click or F2 edits a
400
+ * node's text where it is. A node held still, by a long press or the
401
+ * mouse, lifts: drag it onto another node to move it there, or to a place
402
+ * in the orbit to put it there. Default false.
403
+ */
404
+ editable?: boolean;
405
+ /**
406
+ * Keys for building an editable map at speed, as in mind-map apps. On a
407
+ * node with keyboard focus, Tab (or Insert) adds an idea under it,
408
+ * Shift+Enter adds one beside it, and Delete removes it. While typing,
409
+ * Tab keeps what was typed and goes on a level down, under it; with
410
+ * nothing typed, it moves the field under the idea before. Shift+Tab goes
411
+ * on a level up, beside the parent. Tab then stays in the map; Shift+Tab
412
+ * from a node still leaves it. Default false.
413
+ */
414
+ editingKeys?: boolean;
415
+ /** Called when a flicked orbit comes to rest, with the planet nearest the top. */
416
+ onSpinSettle?: (planet: OrbitNode) => void;
417
+ /** Buttons under the focused node for its note, media, link and actions. Default true. */
418
+ showActionButtons?: boolean;
419
+ /** Open the built-in detail sheet for notes, embeds and the details of a node's type. Default true. */
420
+ showDetailSheet?: boolean;
421
+ /**
422
+ * Show pictures and videos in the media viewer, over the whole window:
423
+ * "View image" and "Play video" open it, and so do the pictures and
424
+ * videos in the detail sheet. Default true. With `false`, those buttons
425
+ * open the detail sheet instead (unless `showDetailSheet` is `false` too).
426
+ * `openMedia` opens the viewer either way.
427
+ */
428
+ mediaViewer?: boolean;
429
+ /** The media viewer opened, or stepped to another picture or video. */
430
+ onMediaOpen?: (event: OrbitMediaEvent) => void;
431
+ /** The media viewer closed. */
432
+ onMediaClose?: (event: OrbitMediaEvent) => void;
433
+ /** The video in the media viewer started, paused, moved on, ended or was muted; while it plays, its time a few times a second. */
434
+ onMediaState?: (state: OrbitMediaState) => void;
435
+ /** Renders a note to HTML yourself. The HTML is used as-is: sanitize untrusted notes. */
436
+ noteRenderer?: (note: string, context: {
437
+ node: OrbitNode;
438
+ format: 'markdown' | 'plain';
439
+ }) => string;
440
+ /** Resolves relative image, video and link URLs. */
441
+ baseUrl?: string;
442
+ /**
443
+ * Node types by name: what nodes with `type: name` look like, draw inside
444
+ * them, show in the detail sheet and offer as actions. They come before the
445
+ * ones registered with `registerNodeType`.
446
+ */
447
+ nodeTypes?: Record<string, OrbitNodeType>;
448
+ /** Your own buttons under the focused node and in its detail sheet, before the registered ones. */
449
+ actions?: OrbitAction[];
450
+ /**
451
+ * Status words and how they look: a dot tone (`active`, `done`, `blocked`,
452
+ * `todo`, `neutral`) or any CSS color, as in `{ review: 'active', 'on hold': '#A855F7' }`.
453
+ */
454
+ statuses?: Record<string, OrbitStatusStyle>;
455
+ /**
456
+ * The type a node that names none is drawn as, for display only: as if it
457
+ * said `type: name`, with that type's look, content and actions. Orbit never
458
+ * writes it to the map, and asks again whenever it draws; return undefined
459
+ * to draw the node as it is. Called often: keep it quick.
460
+ */
461
+ nodeTypeFor?: (node: OrbitNode) => string | undefined;
462
+ }
463
+ export declare const DEFAULT_OPTIONS: Required<Pick<RendererOptions, 'viewMode' | 'showRings' | 'interactive' | 'orbitAnimation' | 'orbitSpeed' | 'showControls'>>;
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Buttons under the focused node: its type's details, its image, video,
3
+ * embed, note and link, then your own actions.
4
+ */
5
+ import type { OrbitContentAction, OrbitNode } from '../types.js';
6
+ import { OrbitWords } from '../languages.js';
7
+ import { type OrbitAction } from '../extensions.js';
8
+ export type ActionKind = OrbitContentAction;
9
+ /**
10
+ * Where a node's link goes: a page, another node of the map (with the
11
+ * button's label), or a node that isn't in the map, which gets no button.
12
+ */
13
+ export type LinkDescription = {
14
+ kind: 'page';
15
+ } | {
16
+ kind: 'node';
17
+ label: string;
18
+ } | {
19
+ kind: 'missing';
20
+ };
21
+ /** Orbit's buttons a node offers, in display order. A video replaces an embed. */
22
+ export declare const activeActions: (node: OrbitNode, hasDetails?: boolean) => ActionKind[];
23
+ /** What the bar asks the map about a node besides its content. */
24
+ export interface ActionBarContext {
25
+ /** Runs a button: one of Orbit's, or the `id` of one of your actions. */
26
+ onAction(node: OrbitNode, action: string, event: MouseEvent): void;
27
+ /** Where the node's link goes. */
28
+ describeLink(node: OrbitNode): LinkDescription;
29
+ /** Your actions the node offers. */
30
+ actions(node: OrbitNode): OrbitAction[];
31
+ /** Whether the node's type adds a section to the detail sheet. */
32
+ hasDetails(node: OrbitNode): boolean;
33
+ /** Puts keyboard focus back on the map's active node, the way closing the inline editor does. */
34
+ returnFocus?(): void;
35
+ /** The map's words, in its language. Default: English. */
36
+ words?(): OrbitWords;
37
+ }
38
+ /** How a row of buttons lays out in the width it's given: the buttons on each line, and the size of the whole. */
39
+ export interface ActionRows {
40
+ perLine: number;
41
+ width: number;
42
+ height: number;
43
+ }
44
+ /** How `count` buttons `size` px wide lay out in `width` px: on one line where they fit, else wrapped onto more. */
45
+ export declare const actionRows: (count: number, size: number, width?: number) => ActionRows;
46
+ export declare class ActionBar {
47
+ readonly element: HTMLDivElement;
48
+ private readonly context;
49
+ private node;
50
+ private visible;
51
+ /** Where the buttons were last put, so a bar that didn't move isn't touched: the map paints every frame while it moves. */
52
+ private transform;
53
+ /** The width they last wrapped at (0 for one line). */
54
+ private wrap;
55
+ /** The last node counted, and its count. */
56
+ private counted;
57
+ constructor(context: ActionBarContext);
58
+ /** How many buttons `node` gets: Orbit's, then your actions. The map asks every frame, so each node is counted once. */
59
+ count(node: OrbitNode): number;
60
+ /** How wide and tall each button is (px), known without laying them out. */
61
+ size(): number;
62
+ private kinds;
63
+ /**
64
+ * Shows the buttons of `node` (if it has any) with their top center at
65
+ * (`x`, `y`), wrapped onto lines `wrap` px wide (or on one line, with 0).
66
+ */
67
+ show(node: OrbitNode, x: number, y: number, wrap?: number): void;
68
+ hide(): void;
69
+ private words;
70
+ /** Forgets the buttons, so the next `show` rebuilds them. */
71
+ reset(): void;
72
+ private contentButton;
73
+ private actionButton;
74
+ private button;
75
+ }