@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.
- package/LICENSE +21 -0
- package/README.md +168 -2
- package/dist/bin/orbit.js +11666 -0
- package/dist/bin/orbit.js.map +60 -0
- package/dist/chunk-fkdfgtx9.js +17295 -0
- package/dist/chunk-fkdfgtx9.js.map +75 -0
- package/dist/chunk-y748hzcr.js +82 -0
- package/dist/chunk-y748hzcr.js.map +10 -0
- package/dist/chunk-zze4tc9n.js +408 -0
- package/dist/chunk-zze4tc9n.js.map +10 -0
- package/dist/core/auto-render.d.ts +85 -0
- package/dist/core/branch-colors.d.ts +57 -0
- package/dist/core/browser.d.ts +23 -0
- package/dist/core/create.d.ts +23 -0
- package/dist/core/diagnostics.d.ts +40 -0
- package/dist/core/dispatch.d.ts +23 -0
- package/dist/core/document-options.d.ts +18 -0
- package/dist/core/document-source.d.ts +128 -0
- package/dist/core/editing.d.ts +66 -0
- package/dist/core/engine/animation-clock.d.ts +40 -0
- package/dist/core/engine/camera.d.ts +70 -0
- package/dist/core/engine/colors.d.ts +51 -0
- package/dist/core/engine/display.d.ts +125 -0
- package/dist/core/engine/export.d.ts +32 -0
- package/dist/core/engine/glide.d.ts +34 -0
- package/dist/core/engine/labels.d.ts +106 -0
- package/dist/core/engine/node-drag.d.ts +49 -0
- package/dist/core/engine/scene.d.ts +160 -0
- package/dist/core/engine/spin.d.ts +62 -0
- package/dist/core/engine/surface-pattern.d.ts +20 -0
- package/dist/core/engine/text-measure.d.ts +116 -0
- package/dist/core/engine/views.d.ts +361 -0
- package/dist/core/extensions.d.ts +155 -0
- package/dist/core/format-upgrades.d.ts +33 -0
- package/dist/core/index.d.ts +46 -0
- package/dist/core/input-controller.d.ts +116 -0
- package/dist/core/languages.d.ts +201 -0
- package/dist/core/layout.d.ts +61 -0
- package/dist/core/map-tools/definitions.d.ts +71 -0
- package/dist/core/map-tools/input.d.ts +62 -0
- package/dist/core/map-tools/reading.d.ts +40 -0
- package/dist/core/map-tools/tools.d.ts +51 -0
- package/dist/core/markdown-writing.d.ts +87 -0
- package/dist/core/material.d.ts +25 -0
- package/dist/core/media.d.ts +42 -0
- package/dist/core/node-attributes.d.ts +31 -0
- package/dist/core/node-links.d.ts +25 -0
- package/dist/core/other-apps/freemind.d.ts +8 -0
- package/dist/core/other-apps/icons.d.ts +16 -0
- package/dist/core/other-apps/ideas.d.ts +76 -0
- package/dist/core/other-apps/import.d.ts +28 -0
- package/dist/core/other-apps/inflate.d.ts +22 -0
- package/dist/core/other-apps/markup.d.ts +51 -0
- package/dist/core/other-apps/notes.d.ts +80 -0
- package/dist/core/other-apps/opml.d.ts +26 -0
- package/dist/core/other-apps/reading.d.ts +36 -0
- package/dist/core/other-apps/xmind.d.ts +14 -0
- package/dist/core/other-apps/zip.d.ts +37 -0
- package/dist/core/parser-markdown.d.ts +42 -0
- package/dist/core/parser-yaml.d.ts +8 -0
- package/dist/core/print-layout.d.ts +70 -0
- package/dist/core/render-to-svg.d.ts +57 -0
- package/dist/core/renderer/content-painter.d.ts +30 -0
- package/dist/core/renderer/dom.d.ts +15 -0
- package/dist/core/renderer/families.d.ts +35 -0
- package/dist/core/renderer/label-painter.d.ts +93 -0
- package/dist/core/renderer/node-painter.d.ts +113 -0
- package/dist/core/renderer/numbers.d.ts +2 -0
- package/dist/core/renderer/options.d.ts +12 -0
- package/dist/core/renderer/rings-and-links.d.ts +23 -0
- package/dist/core/renderer/scene-helpers.d.ts +33 -0
- package/dist/core/renderer/trees.d.ts +22 -0
- package/dist/core/serializer-markdown.d.ts +18 -0
- package/dist/core/serializer-yaml.d.ts +2 -0
- package/dist/core/source-patch.d.ts +24 -0
- package/dist/core/source.d.ts +27 -0
- package/dist/core/styles.d.ts +6 -0
- package/dist/core/suggest.d.ts +8 -0
- package/dist/core/svg-renderer.d.ts +626 -0
- package/dist/core/text-layout.d.ts +54 -0
- package/dist/core/themes.d.ts +62 -0
- package/dist/core/types.d.ts +471 -0
- package/dist/core/ui/actions.d.ts +75 -0
- package/dist/core/ui/controls.d.ts +61 -0
- package/dist/core/ui/detail-sheet.d.ts +88 -0
- package/dist/core/ui/frames.d.ts +11 -0
- package/dist/core/ui/icons.d.ts +14 -0
- package/dist/core/ui/inline-editor.d.ts +79 -0
- package/dist/core/ui/media-players.d.ts +65 -0
- package/dist/core/ui/media-viewer.d.ts +169 -0
- package/dist/core/ui/media-zoom.d.ts +51 -0
- package/dist/core/ui/note-markdown.d.ts +19 -0
- package/dist/core/ui/outline.d.ts +44 -0
- package/dist/core/url-guard.d.ts +40 -0
- package/dist/core/utils.d.ts +23 -0
- package/dist/core/web-page/page.d.ts +59 -0
- package/dist/core/web-page/runtime.d.ts +13 -0
- package/dist/core/web-page/start.d.ts +1 -0
- package/dist/core/yaml-mini.d.ts +54 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4357 -0
- package/dist/index.js.map +29 -0
- package/dist/marked/index.d.ts +31 -0
- package/dist/marked/index.js +110 -0
- package/dist/marked/index.js.map +10 -0
- package/dist/react/index.d.ts +55 -0
- package/dist/react/index.js +352 -0
- package/dist/react/index.js.map +1 -0
- package/dist/web-page.d.ts +2 -0
- package/dist/web-page.js +130 -0
- package/llms-full.txt +2785 -0
- package/llms.txt +36 -0
- package/package.json +118 -4
- package/skills/orbit/SKILL.md +140 -0
- package/skills/orbit/references/editing.md +195 -0
- package/skills/orbit/references/extending.md +247 -0
- package/skills/orbit/references/format.md +331 -0
- package/skills/orbit/references/guide.md +546 -0
- package/skills/orbit/references/import-export.md +115 -0
- package/skills/orbit/references/languages.md +160 -0
- package/skills/orbit/references/map-tools.md +188 -0
- package/skills/orbit/references/media.md +160 -0
- package/skills/orbit/references/recipes.md +236 -0
- package/skills/orbit/references/theming.md +199 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/core/utils.ts", "../src/core/diagnostics.ts", "../src/core/themes.ts", "../src/core/suggest.ts", "../src/core/document-options.ts", "../src/core/format-upgrades.ts", "../src/core/yaml-mini.ts", "../src/core/url-guard.ts", "../src/core/media.ts", "../src/core/source.ts", "../src/core/branch-colors.ts", "../src/core/node-attributes.ts", "../src/core/node-links.ts", "../src/core/document-source.ts", "../src/core/parser-markdown.ts", "../src/core/parser-yaml.ts", "../src/core/dispatch.ts", "../src/core/markdown-writing.ts", "../src/core/source-patch.ts", "../src/core/serializer-markdown.ts", "../src/core/languages.ts", "../src/core/ui/note-markdown.ts", "../src/core/ui/icons.ts", "../src/core/ui/frames.ts", "../src/core/ui/detail-sheet.ts", "../src/core/extensions.ts", "../src/core/types.ts", "../src/core/editing.ts", "../src/core/styles/orbit.scss", "../src/core/styles/print.scss", "../src/core/styles.ts", "../src/core/input-controller.ts", "../src/core/engine/animation-clock.ts", "../src/core/engine/camera.ts", "../src/core/engine/spin.ts", "../src/core/engine/glide.ts", "../src/core/layout.ts", "../src/core/browser.ts", "../src/core/engine/scene.ts", "../src/core/engine/display.ts", "../src/core/text-layout.ts", "../src/core/engine/text-measure.ts", "../src/core/engine/views.ts", "../src/core/engine/node-drag.ts", "../src/core/engine/colors.ts", "../src/core/engine/labels.ts", "../src/core/engine/surface-pattern.ts", "../src/core/engine/export.ts", "../src/core/ui/controls.ts", "../src/core/ui/outline.ts", "../src/core/ui/media-players.ts", "../src/core/ui/media-zoom.ts", "../src/core/ui/media-viewer.ts", "../src/core/ui/actions.ts", "../src/core/ui/inline-editor.ts", "../src/core/renderer/numbers.ts", "../src/core/renderer/rings-and-links.ts", "../src/core/renderer/label-painter.ts", "../src/core/renderer/families.ts", "../src/core/renderer/node-painter.ts", "../src/core/renderer/content-painter.ts", "../src/core/renderer/options.ts", "../src/core/renderer/dom.ts", "../src/core/renderer/scene-helpers.ts", "../src/core/renderer/trees.ts", "../src/core/svg-renderer.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type { OrbitNode } from './types.js';\n\nexport const slugify = (value: string): string => {\n const slug = foldAccents(value)\n .toLowerCase()\n .trim()\n .replace(/[^\\p{L}\\p{N}]+/gu, '-')\n .replace(/^-+|-+$/g, '');\n\n return slug || 'node';\n};\n\n/**\n * Drops accents from Latin, Greek and Cyrillic letters (\"Investigación\" becomes\n * \"Investigacion\") and folds compatibility forms (full-width letters,\n * ligatures) while leaving other scripts intact, so ids stay readable in\n * any language.\n */\nconst foldAccents = (value: string): string => {\n return value\n .normalize('NFKD')\n .replace(/([\\p{Script=Latin}\\p{Script=Greek}\\p{Script=Cyrillic}])\\p{M}+/gu, '$1')\n .normalize('NFC');\n};\n\n/**\n * Slug used for auto-generated node ids in both parsers and for detecting\n * explicit ids in both serializers (`nodesWithExplicitIds`), which is why\n * it lives here.\n */\nexport const nodeSlug = (text: string): string => {\n return (\n Array.from(\n foldAccents(text)\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}\\s_-]/gu, '')\n .trim()\n .replace(/\\s+/g, '-'),\n )\n .slice(0, 64)\n .join('') || 'node'\n );\n};\n\n/**\n * Links a node to its parent. The link is non-enumerable so a parsed tree\n * stays a plain tree for `JSON.stringify`, spreads and structured clones.\n */\nexport const setParent = (node: OrbitNode, parent: OrbitNode | undefined): void => {\n Object.defineProperty(node, 'parent', { value: parent, writable: true, configurable: true, enumerable: false });\n};\n\n/**\n * Hands out node ids in document order, the way the parsers number them:\n * an id stays as it is the first time, and repeats become `id-2`, `id-3`….\n */\nconst nodeIdAllocator = (): { peek(base: string): string; take(base: string): string } => {\n const used = new Set<string>();\n const nextSuffix = new Map<string, number>();\n\n const candidate = (base: string): { id: string; suffix?: number } => {\n if (!used.has(base)) {\n return { id: base };\n }\n\n let suffix = nextSuffix.get(base) ?? 2;\n\n while (used.has(`${base}-${suffix}`)) {\n suffix += 1;\n }\n\n return { id: `${base}-${suffix}`, suffix };\n };\n\n return {\n peek: (base) => candidate(base).id,\n take: (base) => {\n const { id, suffix } = candidate(base);\n used.add(id);\n nextSuffix.set(base, suffix === undefined ? 2 : suffix + 1);\n return id;\n },\n };\n};\n\nexport const ensureUniqueNodeIds = (root: OrbitNode): void => {\n const ids = nodeIdAllocator();\n\n const walk = (node: OrbitNode): void => {\n node.id = ids.take(node.id.trim() || slugify(node.text));\n\n for (const child of node.children) {\n walk(child);\n }\n };\n\n walk(root);\n};\n\n/**\n * The nodes whose ids a serializer has to write: those the parsers wouldn't\n * give them from their text. A second \"Research\" reads back as\n * `research-2` on its own, so it needs no id attribute.\n */\nexport const nodesWithExplicitIds = (root: OrbitNode): Set<OrbitNode> => {\n const ids = nodeIdAllocator();\n const explicit = new Set<OrbitNode>();\n\n const walk = (node: OrbitNode): void => {\n const fromText = nodeSlug(node.text);\n\n if (ids.peek(fromText) === node.id) {\n ids.take(fromText);\n } else {\n explicit.add(node);\n ids.take(node.id);\n }\n\n for (const child of node.children) {\n walk(child);\n }\n };\n\n walk(root);\n return explicit;\n};\n\nexport const findNodeById = (root: OrbitNode, id: string): OrbitNode | null => {\n if (root.id === id) {\n return root;\n }\n\n for (const child of root.children) {\n const found = findNodeById(child, id);\n\n if (found) {\n return found;\n }\n }\n\n return null;\n};\n\nexport const getNodePath = (root: OrbitNode, id: string): OrbitNode[] => {\n const path: OrbitNode[] = [];\n\n const walk = (node: OrbitNode, current: OrbitNode[]): boolean => {\n const next = [...current, node];\n\n if (node.id === id) {\n path.push(...next);\n return true;\n }\n\n for (const child of node.children) {\n if (walk(child, next)) {\n return true;\n }\n }\n\n return false;\n };\n\n walk(root, []);\n return path;\n};\n\nexport const clamp = (value: number, min: number, max: number): number => {\n return Math.max(min, Math.min(max, value));\n};\n",
|
|
6
|
+
"/**\n * Parse diagnostics. Parsers are forgiving by default: a problem they can\n * recover from is recorded as a diagnostic and parsing continues. In strict\n * mode (`{ strict: true }`, used by `orbit validate`) the first such\n * problem throws an `OrbitParseError` instead.\n */\n\nimport type { OrbitDocument } from './types.js';\n\n/** Every kind of problem the parsers report. */\nexport const DIAGNOSTIC_CODES = [\n 'empty-document',\n 'no-structure',\n 'synthetic-root',\n 'invalid-frontmatter',\n 'unknown-frontmatter-key',\n 'unsupported-schema-version',\n 'format-upgraded',\n 'invalid-attributes',\n 'unknown-attribute',\n 'invalid-option-value',\n 'media-missing-source',\n 'unknown-content-type',\n 'caption-without-media',\n 'unknown-link-target',\n 'invalid-yaml',\n 'unknown-yaml-key',\n 'ignored-node-entry',\n 'misnamed-node-key',\n 'comment-without-orbit',\n 'attributes-after-list',\n] as const;\n\nexport type OrbitDiagnosticCode = (typeof DIAGNOSTIC_CODES)[number];\n\nexport type OrbitDiagnosticSeverity = 'error' | 'warning';\n\nexport interface OrbitDiagnostic {\n code: OrbitDiagnosticCode;\n message: string;\n\n /** 1-based line in the source passed to the parser, when known. */\n line?: number;\n\n severity: OrbitDiagnosticSeverity;\n}\n\nexport class OrbitParseError extends Error {\n readonly code: OrbitDiagnosticCode;\n readonly line: number;\n\n constructor(message: string, line: number, code: OrbitDiagnosticCode = 'invalid-yaml') {\n super(`${message} at line ${line}`);\n this.name = 'OrbitParseError';\n this.line = line;\n this.code = code;\n }\n}\n\nexport const formatDiagnostic = (diagnostic: OrbitDiagnostic): string => {\n return diagnostic.line === undefined ? diagnostic.message : `Line ${diagnostic.line}: ${diagnostic.message}`;\n};\n\n/**\n * Reports a parsed document's problems to the console, the same signal from\n * every entry point: each error as an error, then the other problems as one\n * warning. A document without diagnostics reports its warnings alone.\n */\nexport const reportParseDiagnostics = (doc: OrbitDocument): void => {\n if (typeof console === 'undefined') {\n return;\n }\n\n const diagnostics = doc.diagnostics;\n const warnings = diagnostics ? diagnostics.filter((diagnostic) => diagnostic.severity !== 'error').map(formatDiagnostic) : doc.warnings;\n\n for (const diagnostic of diagnostics ?? []) {\n if (diagnostic.severity === 'error') {\n console.error(`[orbit] ${formatDiagnostic(diagnostic)}`);\n }\n }\n\n if (warnings.length > 0) {\n console.warn(`[orbit] parse warnings:\\n- ${warnings.join('\\n- ')}`);\n }\n};\n\nexport class DiagnosticCollector {\n readonly diagnostics: OrbitDiagnostic[] = [];\n private readonly strict: boolean;\n\n constructor(strict: boolean) {\n this.strict = strict;\n }\n\n /** A problem the parser works around: thrown in strict mode, recorded otherwise. */\n recover(code: OrbitDiagnosticCode, message: string, line?: number, severity: OrbitDiagnosticSeverity = 'warning'): void {\n if (this.strict) {\n throw new OrbitParseError(message, line ?? 1, code);\n }\n\n this.diagnostics.push({ code, message, line, severity });\n }\n\n /** Worth knowing but never fatal, even in strict mode. */\n note(code: OrbitDiagnosticCode, message: string, line?: number): void {\n this.diagnostics.push({ code, message, line, severity: 'warning' });\n }\n\n get warnings(): string[] {\n return this.diagnostics.map(formatDiagnostic);\n }\n}\n",
|
|
7
|
+
"import type { OrbitRendererTheme, OrbitThemePreset } from './types.js';\n\n/**\n * Theme tokens. Each token is a CSS custom property: set `--orbit-<token>` on\n * the map or any ancestor to override it. Presets only provide defaults:\n * internally every token resolves as `var(--orbit-<token>, <preset value>)`.\n */\nexport const THEME_TOKENS = [\n 'sans-font', 'serif-font', 'mono-font',\n 'font-family', 'label-font', 'display-font', 'label-weight', 'display-weight', 'label-letter-spacing', 'label-shadow',\n 'surface', 'surface-pattern', 'text', 'muted-text',\n 'root-text', 'node-text', 'node-text-inverse',\n 'color-root', 'color-1', 'color-2', 'color-3', 'color-4', 'color-5', 'color-6', 'color-7',\n 'shade-light', 'shade-dark',\n 'node-fill-opacity', 'moon-opacity', 'node-highlight', 'node-terminator', 'node-shading', 'node-shade-circle',\n 'node-stroke', 'node-stroke-tint', 'node-stroke-width', 'badge-stroke',\n 'node-shadow', 'node-shadow-tint', 'node-shadow-opacity', 'node-shadow-offset', 'node-shadow-size',\n 'sun-shadow-opacity', 'sun-shadow-size',\n 'sun-halo', 'sun-halo-tint', 'sun-halo-opacity', 'sun-halo-width', 'sun-halo-dash', 'sun-halo-size',\n 'ring-stroke', 'ring-tint', 'ring-opacity', 'ring-width', 'ring-dash',\n 'link-stroke', 'link-tint', 'link-opacity', 'link-width', 'link-dash',\n 'focus-ring', 'note-indicator',\n 'control-background', 'control-border', 'control-text', 'control-muted-text',\n 'control-active-background', 'control-active-text', 'control-shadow', 'control-blur',\n 'tooltip-background', 'tooltip-text',\n 'action-background', 'action-border', 'action-text', 'action-shadow',\n 'sheet-background', 'sheet-text', 'sheet-muted-text', 'sheet-border', 'sheet-backdrop', 'sheet-shadow', 'sheet-blur',\n 'chip-background', 'chip-text', 'link-text',\n 'status-active', 'status-done', 'status-blocked', 'status-todo', 'status-neutral',\n 'error-background', 'error-border', 'error-text',\n] as const;\n\nexport type OrbitThemeToken = (typeof THEME_TOKENS)[number];\nexport type OrbitThemeTokens = Record<OrbitThemeToken, string>;\nexport type OrbitThemeName =\n | 'paper' | 'night' | 'glass' | 'glass-night' | 'cosmos' | 'blueprint' | 'ink' | 'contrast'\n | 'flat' | 'flat-night' | 'material' | 'material-night' | 'liquid' | 'liquid-night';\n\nconst SYSTEM_FONTS = 'ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif';\nconst SERIF_FONTS = 'ui-serif, \"Iowan Old Style\", \"Palatino Linotype\", Palatino, Georgia, Cambria, \"Times New Roman\", serif';\nconst MONOSPACE_FONTS = 'ui-monospace, \"SF Mono\", \"Cascadia Mono\", \"Roboto Mono\", Menlo, Consolas, \"Liberation Mono\", monospace';\n\n/** Pastel planets with a soft colored shadow and a fine rim of their own color, on the page's own background. */\nconst PAPER: OrbitThemeTokens = {\n // The page's fonts of each kind: set `--orbit-sans-font` to draw every sans-serif theme in your own.\n 'sans-font': SYSTEM_FONTS,\n 'serif-font': SERIF_FONTS,\n 'mono-font': MONOSPACE_FONTS,\n 'font-family': 'var(--_orbit-sans-font)',\n 'label-font': 'var(--_orbit-font-family)',\n 'display-font': 'var(--_orbit-font-family)',\n 'label-weight': '600',\n 'display-weight': '650',\n 'label-letter-spacing': '-0.005em',\n 'label-shadow': 'none',\n surface: 'transparent',\n 'surface-pattern': 'none',\n text: '#1F2733',\n 'muted-text': '#5B6474',\n 'root-text': '#1F2733',\n 'node-text': '#1F2733',\n 'node-text-inverse': '#FFFFFF',\n 'color-root': '#FAD86F',\n 'color-1': '#FEBAB6',\n 'color-2': '#99E0BA',\n 'color-3': '#9ED5FD',\n 'color-4': '#D6C2FE',\n 'color-5': '#F9C191',\n 'color-6': '#FCB6D6',\n 'color-7': '#82E1E0',\n 'shade-light': '#FFFFFF',\n 'shade-dark': '#1F2733',\n 'node-fill-opacity': '1',\n 'moon-opacity': '0.94',\n 'node-highlight': 'rgba(255, 255, 255, 0.55)',\n 'node-terminator': 'rgba(31, 39, 51, 0)',\n 'node-shading': 'rgba(31, 39, 51, 0.12)',\n 'node-shade-circle': '0.34 0.3 0.78',\n 'node-stroke': '#1F2733',\n 'node-stroke-tint': '78%',\n 'node-stroke-width': '1',\n 'badge-stroke': '#FFFFFF',\n 'node-shadow': '#1F2733',\n 'node-shadow-tint': '45%',\n 'node-shadow-opacity': '0.26',\n 'node-shadow-offset': '0.16',\n 'node-shadow-size': '0.96',\n 'sun-shadow-opacity': '0.3',\n 'sun-shadow-size': '0.98',\n 'sun-halo': '#1F2733',\n 'sun-halo-tint': '72%',\n 'sun-halo-opacity': '0.55',\n 'sun-halo-width': '1',\n 'sun-halo-dash': 'none',\n 'sun-halo-size': '1.15',\n 'ring-stroke': '#1F2733',\n 'ring-tint': '35%',\n 'ring-opacity': '0.4',\n 'ring-width': '1.5',\n 'ring-dash': '1 6',\n 'link-stroke': '#1F2733',\n 'link-tint': '60%',\n 'link-opacity': '0.45',\n 'link-width': '1.5',\n 'link-dash': 'none',\n 'focus-ring': '#2563EB',\n 'note-indicator': '#1F2733',\n 'control-background': 'rgba(255, 255, 255, 0.92)',\n 'control-border': 'rgba(31, 39, 51, 0.12)',\n 'control-text': '#1F2733',\n 'control-muted-text': '#5B6474',\n 'control-active-background': '#1F2733',\n 'control-active-text': '#FFFFFF',\n 'control-shadow': '0 6px 20px rgba(31, 39, 51, 0.12)',\n 'control-blur': '12px',\n 'tooltip-background': '#1F2733',\n 'tooltip-text': '#FFFFFF',\n 'action-background': '#FFFFFF',\n 'action-border': 'rgba(31, 39, 51, 0.16)',\n 'action-text': '#1F2733',\n 'action-shadow': '0 6px 16px rgba(31, 39, 51, 0.18)',\n 'sheet-background': '#FFFFFF',\n 'sheet-text': '#1F2733',\n 'sheet-muted-text': '#5B6474',\n 'sheet-border': 'rgba(31, 39, 51, 0.12)',\n 'sheet-backdrop': 'rgba(15, 23, 42, 0.45)',\n 'sheet-shadow': '0 24px 64px rgba(15, 23, 42, 0.28)',\n 'sheet-blur': '0px',\n 'chip-background': '#F1F5F9',\n 'chip-text': '#334155',\n 'link-text': '#2563EB',\n 'status-active': '#2563EB',\n 'status-done': '#16A34A',\n 'status-blocked': '#DC2626',\n 'status-todo': '#94A3B8',\n 'status-neutral': '#64748B',\n 'error-background': '#FFF6F5',\n 'error-border': '#E58A8A',\n 'error-text': '#7A1F1F',\n};\n\n/** Luminous planets that glow on a deep navy sky. */\nconst NIGHT: OrbitThemeTokens = {\n ...PAPER,\n surface: '#0B1120',\n 'surface-pattern': 'radial-gradient(120% 90% at 50% 42%, rgba(64, 84, 160, 0.26), transparent 70%)',\n text: '#E6EAF2',\n 'muted-text': '#97A3B6',\n 'root-text': '#0B1120',\n 'node-text': '#0B1120',\n 'color-root': '#FEDB6D',\n 'color-1': '#FFAAA7',\n 'color-2': '#80DAAC',\n 'color-3': '#86CDFF',\n 'color-4': '#CEB5FE',\n 'color-5': '#F8B478',\n 'color-6': '#FAA6CE',\n 'color-7': '#5EDADA',\n 'shade-dark': '#0B1120',\n 'node-highlight': 'rgba(255, 255, 255, 0.45)',\n 'node-terminator': 'rgba(11, 17, 32, 0)',\n 'node-shading': 'rgba(11, 17, 32, 0.2)',\n 'node-stroke': '#FFFFFF',\n 'node-stroke-tint': '55%',\n 'badge-stroke': '#0B1120',\n 'node-shadow': '#FFFFFF',\n 'node-shadow-tint': '100%',\n 'node-shadow-opacity': '0.42',\n 'node-shadow-offset': '0',\n 'node-shadow-size': '1.16',\n 'sun-shadow-opacity': '0.5',\n 'sun-shadow-size': '1.4',\n 'sun-halo-opacity': '0',\n 'ring-stroke': '#FFFFFF',\n 'ring-tint': '55%',\n 'ring-opacity': '0.34',\n 'link-stroke': '#FFFFFF',\n 'link-tint': '70%',\n 'link-opacity': '0.36',\n 'focus-ring': '#93C5FD',\n 'note-indicator': '#E6EAF2',\n 'control-background': 'rgba(20, 26, 44, 0.84)',\n 'control-border': 'rgba(148, 163, 184, 0.22)',\n 'control-text': '#E6EAF2',\n 'control-muted-text': '#97A3B6',\n 'control-active-background': '#E6EAF2',\n 'control-active-text': '#0B1120',\n 'control-shadow': '0 8px 24px rgba(0, 0, 0, 0.4)',\n 'tooltip-background': '#E6EAF2',\n 'tooltip-text': '#0B1120',\n 'action-background': '#1B2338',\n 'action-border': 'rgba(148, 163, 184, 0.3)',\n 'action-text': '#E6EAF2',\n 'action-shadow': '0 6px 16px rgba(0, 0, 0, 0.45)',\n 'sheet-background': '#131A2E',\n 'sheet-text': '#E6EAF2',\n 'sheet-muted-text': '#97A3B6',\n 'sheet-border': 'rgba(148, 163, 184, 0.2)',\n 'sheet-backdrop': 'rgba(2, 6, 23, 0.6)',\n 'sheet-shadow': '0 24px 64px rgba(0, 0, 0, 0.6)',\n 'chip-background': 'rgba(148, 163, 184, 0.16)',\n 'chip-text': '#E2E8F0',\n 'link-text': '#93C5FD',\n 'status-active': '#60A5FA',\n 'status-done': '#4ADE80',\n 'status-blocked': '#F87171',\n 'status-neutral': '#94A3B8',\n 'error-background': '#2A1215',\n 'error-border': '#F87171',\n 'error-text': '#FECACA',\n};\n\n/** Frosted, translucent planets with a bright rim, on a soft pastel backdrop of their own. */\nconst GLASS: OrbitThemeTokens = {\n ...PAPER,\n surface: '#E7EAF8',\n 'surface-pattern': [\n 'radial-gradient(60% 50% at 16% 18%, rgba(196, 181, 253, 0.75), transparent 70%)',\n 'radial-gradient(55% 48% at 86% 24%, rgba(251, 207, 232, 0.85), transparent 70%)',\n 'radial-gradient(65% 55% at 52% 96%, rgba(153, 246, 228, 0.7), transparent 70%)',\n 'radial-gradient(40% 40% at 90% 85%, rgba(191, 219, 254, 0.8), transparent 70%)',\n ].join(', '),\n text: '#16213A',\n 'muted-text': '#414C66',\n 'root-text': '#16213A',\n 'node-text': '#16213A',\n 'color-root': '#FEEEBD',\n 'color-1': '#FED6D4',\n 'color-2': '#B6F1D0',\n 'color-3': '#C7E6FD',\n 'color-4': '#E6DAFE',\n 'color-5': '#FDDABD',\n 'color-6': '#FFD3E6',\n 'color-7': '#A5F2F1',\n 'shade-dark': '#16213A',\n 'node-fill-opacity': '0.55',\n 'moon-opacity': '0.5',\n 'node-highlight': 'rgba(255, 255, 255, 0.85)',\n 'node-terminator': 'rgba(22, 33, 58, 0)',\n 'node-shading': 'rgba(22, 33, 58, 0.08)',\n 'node-stroke': 'rgba(255, 255, 255, 0.92)',\n 'node-stroke-tint': '0%',\n 'node-stroke-width': '1.5',\n 'node-shadow': '#16213A',\n 'node-shadow-tint': '25%',\n 'node-shadow-opacity': '0.18',\n 'node-shadow-offset': '0.18',\n 'node-shadow-size': '0.98',\n 'sun-shadow-opacity': '0.22',\n 'sun-shadow-size': '1',\n 'sun-halo': '#FFFFFF',\n 'sun-halo-tint': '0%',\n 'sun-halo-opacity': '0.7',\n 'sun-halo-width': '1.5',\n 'sun-halo-size': '1.13',\n 'ring-stroke': '#FFFFFF',\n 'ring-tint': '0%',\n 'ring-opacity': '0.85',\n 'link-stroke': '#FFFFFF',\n 'link-tint': '0%',\n 'link-opacity': '0.8',\n 'note-indicator': '#16213A',\n 'control-background': 'rgba(255, 255, 255, 0.42)',\n 'control-border': 'rgba(255, 255, 255, 0.62)',\n 'control-text': '#16213A',\n 'control-muted-text': '#414C66',\n 'control-active-background': 'rgba(255, 255, 255, 0.78)',\n 'control-active-text': '#16213A',\n 'control-shadow': '0 8px 28px rgba(28, 44, 72, 0.18)',\n 'control-blur': '18px',\n 'tooltip-background': 'rgba(255, 255, 255, 0.86)',\n 'tooltip-text': '#16213A',\n 'action-background': 'rgba(255, 255, 255, 0.62)',\n 'action-border': 'rgba(255, 255, 255, 0.78)',\n 'action-text': '#16213A',\n 'action-shadow': '0 6px 18px rgba(28, 44, 72, 0.2)',\n 'sheet-background': 'rgba(255, 255, 255, 0.8)',\n 'sheet-text': '#16213A',\n 'sheet-muted-text': '#414C66',\n 'sheet-border': 'rgba(255, 255, 255, 0.7)',\n 'sheet-backdrop': 'rgba(18, 28, 45, 0.32)',\n 'sheet-shadow': '0 24px 70px rgba(28, 44, 72, 0.3)',\n 'sheet-blur': '24px',\n 'chip-background': 'rgba(255, 255, 255, 0.6)',\n};\n\n/** The glass look at night: tinted glass planets that glow over an aurora. */\nconst GLASS_NIGHT: OrbitThemeTokens = {\n ...NIGHT,\n surface: '#0E1326',\n 'surface-pattern': [\n 'radial-gradient(60% 50% at 18% 16%, rgba(99, 102, 241, 0.42), transparent 70%)',\n 'radial-gradient(55% 50% at 86% 78%, rgba(219, 39, 119, 0.3), transparent 70%)',\n 'radial-gradient(45% 40% at 74% 12%, rgba(20, 184, 166, 0.26), transparent 70%)',\n ].join(', '),\n 'label-shadow': '0 1px 3px rgba(5, 8, 20, 0.55)',\n text: '#F4F6FF',\n 'muted-text': '#A9B2D0',\n // Light labels on every planet: the glass lets the dark sky through.\n 'root-text': '#F4F6FF',\n 'node-text': '#F4F6FF',\n 'node-text-inverse': '#F4F6FF',\n 'color-root': '#F8DC86',\n 'color-1': '#FFAAA7',\n 'color-2': '#6FDEA7',\n 'color-3': '#86CDFF',\n 'color-4': '#CEB5FE',\n 'color-5': '#FEB16B',\n 'color-6': '#FFA3CF',\n 'color-7': '#36DEDE',\n 'shade-dark': '#0E1326',\n 'node-fill-opacity': '0.16',\n 'moon-opacity': '0.14',\n 'node-highlight': 'rgba(255, 255, 255, 0.1)',\n 'node-terminator': 'rgba(14, 19, 38, 0)',\n 'node-shading': 'rgba(14, 19, 38, 0.18)',\n 'node-stroke': 'rgba(255, 255, 255, 0.6)',\n 'node-stroke-tint': '45%',\n 'node-stroke-width': '1.5',\n 'node-shadow-opacity': '0.3',\n 'node-shadow-size': '1.14',\n 'sun-shadow-opacity': '0.38',\n 'sun-shadow-size': '1.35',\n 'ring-tint': '20%',\n 'ring-opacity': '0.32',\n 'link-tint': '30%',\n 'link-opacity': '0.32',\n 'note-indicator': '#F4F6FF',\n 'control-background': 'rgba(30, 38, 64, 0.5)',\n 'control-border': 'rgba(255, 255, 255, 0.16)',\n 'control-text': '#F4F6FF',\n 'control-muted-text': '#A9B2D0',\n 'control-active-background': '#F4F6FF',\n 'control-active-text': '#0E1326',\n 'control-blur': '18px',\n 'tooltip-background': 'rgba(244, 246, 255, 0.92)',\n 'tooltip-text': '#0E1326',\n 'action-background': 'rgba(30, 38, 64, 0.62)',\n 'action-border': 'rgba(255, 255, 255, 0.2)',\n 'action-text': '#F4F6FF',\n 'sheet-background': 'rgba(24, 32, 56, 0.78)',\n 'sheet-text': '#F4F6FF',\n 'sheet-muted-text': '#A9B2D0',\n 'sheet-border': 'rgba(255, 255, 255, 0.14)',\n 'sheet-blur': '24px',\n};\n\n/** Stars for `cosmos`, scattered at random over a 640 px tile: each `M x y h0` is a dot (a zero-length, round-capped stroke). */\nconst STARS = [\n { width: 1.1, color: '#fff', opacity: 0.45, points: 'M462 375h0M252 311h0M202 477h0M298 443h0M208 600h0M167 216h0M541 306h0M47 605h0M401 38h0M101 610h0M620 113h0M189 63h0M293 536h0M199 606h0M241 266h0M82 304h0M52 6h0M50 137h0M104 532h0M103 368h0M278 199h0M245 328h0M51 59h0M194 68h0M37 219h0M322 310h0M339 230h0M552 48h0M576 155h0M612 480h0' },\n { width: 1.5, color: '#e3e9ff', opacity: 0.75, points: 'M568 195h0M633 111h0M342 180h0M527 323h0M532 283h0M623 494h0M123 125h0M310 588h0M127 394h0M36 377h0M297 418h0M306 11h0M244 382h0M153 210h0M173 288h0M104 454h0' },\n { width: 2.1, color: '#fff', opacity: 0.95, points: 'M221 502h0M523 249h0M489 393h0M633 604h0M173 467h0M218 505h0' },\n { width: 1.5, color: '#ffe7c7', opacity: 0.8, points: 'M382 480h0M367 90h0M103 79h0M497 64h0M339 614h0M541 446h0' },\n];\n\n/** The star tile as a CSS background layer. */\nconst starfield = (): string => {\n const paths = STARS.map((stars) => `<path d='${stars.points}' stroke='${stars.color}' stroke-opacity='${stars.opacity}' stroke-width='${stars.width}' stroke-linecap='round'/>`);\n const svg = `<svg xmlns='http://www.w3.org/2000/svg' width='640' height='640'>${paths.join('')}</svg>`;\n return `url(\"data:image/svg+xml,${svg.replace(/</g, '%3C').replace(/>/g, '%3E').replace(/#/g, '%23')}\") 0 0 / 640px 640px`;\n};\n\n/** Jewel-toned planets lit from one side, a star with a corona, and a field of stars. */\nconst COSMOS: OrbitThemeTokens = {\n ...NIGHT,\n surface: '#05060E',\n 'surface-pattern': [\n starfield(),\n 'radial-gradient(80% 60% at 78% 16%, rgba(98, 70, 214, 0.26), transparent 70%)',\n 'radial-gradient(70% 55% at 14% 88%, rgba(16, 150, 160, 0.16), transparent 70%)',\n ].join(', '),\n 'label-shadow': '0 1px 2px rgba(0, 0, 0, 0.45)',\n text: '#E7E9F7',\n 'muted-text': '#9CA3C4',\n 'root-text': '#1A1206',\n 'node-text': '#14102B',\n 'node-text-inverse': '#FFFFFF',\n 'color-root': '#FFC75A',\n 'color-1': '#285CC2',\n 'color-2': '#863CA4',\n 'color-3': '#A42C71',\n 'color-4': '#017272',\n 'color-5': '#0B7643',\n 'color-6': '#A14206',\n 'color-7': '#5D4DBE',\n 'shade-light': '#4B4F7A',\n 'shade-dark': '#05060E',\n 'moon-opacity': '1',\n 'node-highlight': 'rgba(255, 244, 214, 0.1)',\n 'node-terminator': 'rgba(5, 6, 14, 0.28)',\n 'node-shading': 'rgba(5, 6, 14, 0.6)',\n 'node-stroke': 'rgba(255, 255, 255, 0.6)',\n 'node-stroke-tint': '50%',\n 'badge-stroke': '#05060E',\n 'node-shadow-opacity': '0.4',\n 'node-shadow-size': '1.12',\n 'sun-shadow-opacity': '0.7',\n 'sun-shadow-size': '1.55',\n 'ring-stroke': '#8EA2FF',\n 'ring-tint': '20%',\n 'ring-opacity': '0.32',\n 'ring-width': '1',\n 'ring-dash': 'none',\n 'link-stroke': '#8EA2FF',\n 'link-tint': '45%',\n 'link-opacity': '0.4',\n 'link-width': '1',\n 'focus-ring': '#A5B4FF',\n 'note-indicator': '#E7E9F7',\n 'control-background': 'rgba(14, 16, 32, 0.8)',\n 'control-border': 'rgba(142, 162, 255, 0.2)',\n 'control-text': '#E7E9F7',\n 'control-muted-text': '#9CA3C4',\n 'control-active-background': '#E7E9F7',\n 'control-active-text': '#05060E',\n 'control-shadow': '0 8px 24px rgba(0, 0, 0, 0.5)',\n 'control-blur': '14px',\n 'tooltip-background': '#E7E9F7',\n 'tooltip-text': '#05060E',\n 'action-background': '#14172B',\n 'action-border': 'rgba(142, 162, 255, 0.28)',\n 'action-text': '#E7E9F7',\n 'action-shadow': '0 6px 16px rgba(0, 0, 0, 0.5)',\n 'sheet-background': '#0D0F1E',\n 'sheet-text': '#E7E9F7',\n 'sheet-muted-text': '#9CA3C4',\n 'sheet-border': 'rgba(142, 162, 255, 0.16)',\n 'sheet-backdrop': 'rgba(2, 3, 10, 0.65)',\n 'sheet-shadow': '0 24px 64px rgba(0, 0, 0, 0.65)',\n 'chip-background': 'rgba(142, 162, 255, 0.14)',\n 'chip-text': '#DDE3FF',\n 'link-text': '#A5B4FF',\n};\n\n/** A technical drawing: outlined planets, construction lines and monospaced labels on a gridded blue sheet. */\nconst BLUEPRINT: OrbitThemeTokens = {\n ...NIGHT,\n 'font-family': 'var(--_orbit-mono-font)',\n 'label-weight': '500',\n 'display-weight': '600',\n // Monospaced letters, set a little tighter so names stay compact.\n 'label-letter-spacing': '-0.02em',\n 'label-shadow': 'none',\n surface: '#123A7A',\n 'surface-pattern': [\n 'linear-gradient(rgba(255, 255, 255, 0.12) 1px, transparent 1px) 0 0 / 120px 120px',\n 'linear-gradient(90deg, rgba(255, 255, 255, 0.12) 1px, transparent 1px) 0 0 / 120px 120px',\n 'linear-gradient(rgba(255, 255, 255, 0.06) 1px, transparent 1px) 0 0 / 24px 24px',\n 'linear-gradient(90deg, rgba(255, 255, 255, 0.06) 1px, transparent 1px) 0 0 / 24px 24px',\n ].join(', '),\n text: '#FFFFFF',\n 'muted-text': 'rgba(255, 255, 255, 0.72)',\n // White lines and lettering throughout, as on a print.\n 'root-text': '#FFFFFF',\n 'node-text': '#FFFFFF',\n 'node-text-inverse': '#FFFFFF',\n 'color-root': '#FFFFFF',\n 'color-1': '#C2F3F5',\n 'color-2': '#CCF3DD',\n 'color-3': '#D4ECFD',\n 'color-4': '#EBE3FC',\n 'color-5': '#FFE2CA',\n 'color-6': '#FEDEEC',\n 'color-7': '#C2F3F2',\n 'shade-light': '#FFFFFF',\n 'shade-dark': '#123A7A',\n 'node-fill-opacity': '0.12',\n 'moon-opacity': '0.12',\n 'node-highlight': 'rgba(255, 255, 255, 0)',\n 'node-terminator': 'rgba(18, 58, 122, 0)',\n 'node-shading': 'rgba(18, 58, 122, 0)',\n 'node-stroke': '#FFFFFF',\n 'node-stroke-tint': '30%',\n 'node-stroke-width': '1.5',\n 'badge-stroke': '#123A7A',\n 'node-shadow-opacity': '0',\n 'sun-shadow-opacity': '0',\n 'sun-halo': '#FFFFFF',\n 'sun-halo-tint': '0%',\n 'sun-halo-opacity': '0.7',\n 'sun-halo-width': '1',\n 'sun-halo-dash': '4 4',\n 'sun-halo-size': '1.2',\n 'ring-stroke': '#FFFFFF',\n 'ring-tint': '0%',\n 'ring-opacity': '0.5',\n 'ring-width': '1',\n 'ring-dash': '7 5',\n 'link-stroke': '#FFFFFF',\n 'link-tint': '0%',\n 'link-opacity': '0.55',\n 'link-width': '1',\n 'focus-ring': '#FFD166',\n 'note-indicator': '#FFFFFF',\n 'control-background': 'rgba(14, 45, 99, 0.9)',\n 'control-border': 'rgba(255, 255, 255, 0.32)',\n 'control-text': '#FFFFFF',\n 'control-muted-text': 'rgba(255, 255, 255, 0.72)',\n 'control-active-background': '#FFFFFF',\n 'control-active-text': '#123A7A',\n 'control-shadow': 'none',\n 'control-blur': '0px',\n 'tooltip-background': '#FFFFFF',\n 'tooltip-text': '#123A7A',\n 'action-background': '#123A7A',\n 'action-border': 'rgba(255, 255, 255, 0.6)',\n 'action-text': '#FFFFFF',\n 'action-shadow': 'none',\n 'sheet-background': '#0F3470',\n 'sheet-text': '#FFFFFF',\n 'sheet-muted-text': 'rgba(255, 255, 255, 0.75)',\n 'sheet-border': 'rgba(255, 255, 255, 0.25)',\n 'sheet-backdrop': 'rgba(5, 18, 42, 0.6)',\n 'sheet-shadow': '0 24px 64px rgba(0, 0, 0, 0.45)',\n 'chip-background': 'rgba(255, 255, 255, 0.12)',\n 'chip-text': '#FFFFFF',\n 'link-text': '#BFE3FF',\n 'status-active': '#7CC4FF',\n 'status-done': '#7EE2A8',\n 'status-blocked': '#FF8A8A',\n 'status-todo': 'rgba(255, 255, 255, 0.6)',\n 'status-neutral': 'rgba(255, 255, 255, 0.75)',\n 'error-background': '#3A1622',\n 'error-border': '#FF8A8A',\n 'error-text': '#FFD7D7',\n};\n\n/** Black line art on the page's own background: outlined planets, a black sun and serif lettering. */\nconst INK: OrbitThemeTokens = {\n ...PAPER,\n 'label-font': 'var(--_orbit-serif-font)',\n 'display-font': 'var(--_orbit-serif-font)',\n 'label-weight': '600',\n 'display-weight': '600',\n 'label-letter-spacing': '0',\n text: '#111111',\n 'muted-text': '#55555F',\n 'root-text': '#111111',\n 'node-text': '#111111',\n 'color-root': '#111111',\n 'color-1': '#FFFFFF',\n 'color-2': '#F7F4EE',\n 'color-3': '#EEF2F6',\n 'color-4': '#F4F0F7',\n 'color-5': '#F1F5EF',\n 'color-6': '#F8F1EF',\n 'color-7': '#EFF4F4',\n 'shade-dark': '#111111',\n 'moon-opacity': '1',\n 'node-highlight': 'rgba(255, 255, 255, 0)',\n 'node-terminator': 'rgba(17, 17, 17, 0)',\n 'node-shading': 'rgba(17, 17, 17, 0)',\n 'node-stroke': '#111111',\n 'node-stroke-tint': '0%',\n 'node-stroke-width': '1.5',\n 'node-shadow-opacity': '0',\n 'sun-shadow-opacity': '0',\n 'sun-halo': '#111111',\n 'sun-halo-tint': '0%',\n 'sun-halo-opacity': '1',\n 'sun-halo-width': '1',\n 'sun-halo-size': '1.12',\n 'ring-stroke': '#111111',\n 'ring-tint': '0%',\n 'ring-opacity': '0.6',\n 'ring-width': '1.5',\n 'ring-dash': '0.5 5',\n 'link-stroke': '#111111',\n 'link-tint': '0%',\n 'link-opacity': '0.7',\n 'link-width': '1',\n 'focus-ring': '#C81E1E',\n 'note-indicator': '#C81E1E',\n 'control-background': 'rgba(255, 255, 255, 0.95)',\n 'control-border': '#111111',\n 'control-text': '#111111',\n 'control-muted-text': '#55555F',\n 'control-active-background': '#111111',\n 'control-active-text': '#FFFFFF',\n 'control-shadow': '2px 2px 0 #111111',\n 'control-blur': '0px',\n 'tooltip-background': '#111111',\n 'tooltip-text': '#FFFFFF',\n 'action-background': '#FFFFFF',\n 'action-border': '#111111',\n 'action-text': '#111111',\n 'action-shadow': '2px 2px 0 #111111',\n 'sheet-background': '#FFFFFF',\n 'sheet-text': '#111111',\n 'sheet-muted-text': '#55555F',\n 'sheet-border': '#111111',\n 'sheet-backdrop': 'rgba(17, 17, 17, 0.35)',\n 'sheet-shadow': '6px 6px 0 #111111',\n 'chip-background': '#F3F1EC',\n 'chip-text': '#111111',\n 'link-text': '#C81E1E',\n 'status-active': '#1D4ED8',\n 'status-done': '#15803D',\n 'status-blocked': '#C81E1E',\n 'status-todo': '#9CA3AF',\n 'status-neutral': '#6B7280',\n 'error-background': '#FFF5F5',\n 'error-border': '#C81E1E',\n 'error-text': '#7A1414',\n};\n\n/** Maximum legibility: black text and outlines, solid colors and bold labels on white. */\nconst CONTRAST: OrbitThemeTokens = {\n ...PAPER,\n 'label-weight': '700',\n 'display-weight': '800',\n 'label-letter-spacing': '0',\n surface: '#FFFFFF',\n text: '#000000',\n 'muted-text': '#3D3D3D',\n 'root-text': '#000000',\n 'node-text': '#000000',\n 'color-root': '#FFE066',\n 'color-1': '#FFA8A8',\n 'color-2': '#8CE99A',\n 'color-3': '#74C0FC',\n 'color-4': '#B197FC',\n 'color-5': '#FFC078',\n 'color-6': '#F783AC',\n 'color-7': '#63E6BE',\n // Deeper nodes only get lighter, so black text stays well above AAA.\n 'shade-dark': '#FFFFFF',\n 'moon-opacity': '1',\n 'node-highlight': 'rgba(255, 255, 255, 0)',\n 'node-terminator': 'rgba(0, 0, 0, 0)',\n 'node-shading': 'rgba(0, 0, 0, 0)',\n 'node-stroke': '#000000',\n 'node-stroke-tint': '0%',\n 'node-stroke-width': '2',\n 'node-shadow-opacity': '0',\n 'sun-shadow-opacity': '0',\n 'sun-halo-opacity': '0',\n 'ring-stroke': '#000000',\n 'ring-tint': '0%',\n 'ring-opacity': '0.7',\n 'ring-width': '1.5',\n 'ring-dash': '3 5',\n 'link-stroke': '#000000',\n 'link-tint': '0%',\n 'link-opacity': '0.8',\n 'link-width': '2',\n 'focus-ring': '#0040DD',\n 'note-indicator': '#000000',\n 'control-background': '#FFFFFF',\n 'control-border': '#000000',\n 'control-text': '#000000',\n 'control-muted-text': '#3D3D3D',\n 'control-active-background': '#000000',\n 'control-active-text': '#FFFFFF',\n 'control-shadow': 'none',\n 'control-blur': '0px',\n 'tooltip-background': '#000000',\n 'tooltip-text': '#FFFFFF',\n 'action-background': '#FFFFFF',\n 'action-border': '#000000',\n 'action-text': '#000000',\n 'action-shadow': 'none',\n 'sheet-background': '#FFFFFF',\n 'sheet-text': '#000000',\n 'sheet-muted-text': '#3D3D3D',\n 'sheet-border': '#000000',\n 'sheet-backdrop': 'rgba(0, 0, 0, 0.6)',\n 'sheet-shadow': 'none',\n 'chip-background': '#F0F0F0',\n 'chip-text': '#000000',\n 'link-text': '#0040DD',\n 'status-active': '#0040DD',\n 'status-done': '#007A33',\n 'status-blocked': '#C00000',\n 'status-todo': '#595959',\n 'status-neutral': '#3D3D3D',\n 'error-background': '#FFFFFF',\n 'error-border': '#C00000',\n 'error-text': '#7A0000',\n};\n\n/** Solid, saturated planets with white lettering: no shading, shadows or glow, and a white edge where bodies overlap. */\nconst FLAT: OrbitThemeTokens = {\n ...PAPER,\n 'label-weight': '650',\n 'display-weight': '750',\n 'label-letter-spacing': '0',\n text: '#111827',\n 'muted-text': '#4B5563',\n 'root-text': '#111827',\n 'node-text': '#111827',\n 'node-text-inverse': '#FFFFFF',\n 'color-root': '#FFC233',\n 'color-1': '#C82F2C',\n 'color-2': '#007B3D',\n 'color-3': '#0C66D7',\n 'color-4': '#844DCC',\n 'color-5': '#AD5000',\n 'color-6': '#BE307D',\n 'color-7': '#007777',\n 'shade-dark': '#111827',\n 'moon-opacity': '1',\n 'node-highlight': 'rgba(255, 255, 255, 0)',\n 'node-terminator': 'rgba(17, 24, 39, 0)',\n 'node-shading': 'rgba(17, 24, 39, 0)',\n 'node-stroke': '#FFFFFF',\n 'node-stroke-tint': '0%',\n 'node-stroke-width': '2',\n 'node-shadow-opacity': '0',\n 'sun-shadow-opacity': '0',\n 'sun-halo': '#111827',\n 'sun-halo-tint': '100%',\n 'sun-halo-opacity': '0.3',\n 'sun-halo-width': '6',\n 'sun-halo-dash': 'none',\n 'sun-halo-size': '1.14',\n 'ring-stroke': '#111827',\n 'ring-tint': '0%',\n 'ring-opacity': '0.14',\n 'ring-width': '1.5',\n 'ring-dash': 'none',\n 'link-stroke': '#111827',\n 'link-tint': '100%',\n 'link-opacity': '0.55',\n 'link-width': '2',\n 'link-dash': 'none',\n 'focus-ring': '#0C66D7',\n 'note-indicator': '#111827',\n 'control-background': '#FFFFFF',\n 'control-border': '#E5E7EB',\n 'control-text': '#111827',\n 'control-muted-text': '#4B5563',\n 'control-active-background': '#111827',\n 'control-active-text': '#FFFFFF',\n 'control-shadow': 'none',\n 'control-blur': '0px',\n 'tooltip-background': '#111827',\n 'tooltip-text': '#FFFFFF',\n 'action-background': '#FFFFFF',\n 'action-border': '#E5E7EB',\n 'action-text': '#111827',\n 'action-shadow': 'none',\n 'sheet-background': '#FFFFFF',\n 'sheet-text': '#111827',\n 'sheet-muted-text': '#4B5563',\n 'sheet-border': '#E5E7EB',\n 'sheet-backdrop': 'rgba(17, 24, 39, 0.5)',\n 'sheet-shadow': 'none',\n 'chip-background': '#F3F4F6',\n 'chip-text': '#111827',\n 'link-text': '#0C66D7',\n 'status-active': '#0C66D7',\n 'status-done': '#007B3D',\n 'status-blocked': '#C82F2C',\n 'status-todo': '#9CA3AF',\n 'status-neutral': '#6B7280',\n 'error-background': '#FEF2F2',\n 'error-border': '#C82F2C',\n 'error-text': '#7F1D1D',\n};\n\n/** The flat look at night: bright solid planets with dark lettering, cut out from a near-black page. */\nconst FLAT_NIGHT: OrbitThemeTokens = {\n ...FLAT,\n surface: '#121418',\n text: '#F3F4F6',\n 'muted-text': '#9CA3AF',\n 'root-text': '#0B0D12',\n 'node-text': '#0B0D12',\n 'node-text-inverse': '#F3F4F6',\n 'color-root': '#FFD25A',\n 'color-1': '#FF9287',\n 'color-2': '#3EC873',\n 'color-3': '#7EB2FF',\n 'color-4': '#C29FFF',\n 'color-5': '#FF9657',\n 'color-6': '#FF8BC1',\n 'color-7': '#00C4C5',\n 'shade-dark': '#121418',\n 'node-stroke': '#121418',\n 'badge-stroke': '#121418',\n 'sun-halo': '#FFFFFF',\n 'sun-halo-opacity': '0.55',\n 'sun-halo-width': '4',\n 'ring-stroke': '#FFFFFF',\n 'link-stroke': '#FFFFFF',\n 'link-opacity': '0.6',\n 'focus-ring': '#7EB2FF',\n 'note-indicator': '#F3F4F6',\n 'control-background': '#1C1F26',\n 'control-border': '#2D3139',\n 'control-text': '#F3F4F6',\n 'control-muted-text': '#9CA3AF',\n 'control-active-background': '#F3F4F6',\n 'control-active-text': '#121418',\n 'tooltip-background': '#F3F4F6',\n 'tooltip-text': '#121418',\n 'action-background': '#1C1F26',\n 'action-border': '#2D3139',\n 'action-text': '#F3F4F6',\n 'sheet-background': '#1A1D23',\n 'sheet-text': '#F3F4F6',\n 'sheet-muted-text': '#9CA3AF',\n 'sheet-border': '#2D3139',\n 'sheet-backdrop': 'rgba(0, 0, 0, 0.6)',\n 'chip-background': '#262A32',\n 'chip-text': '#E5E7EB',\n 'link-text': '#7EB2FF',\n 'status-active': '#7EB2FF',\n 'status-done': '#3EC873',\n 'status-blocked': '#FF9287',\n 'status-todo': '#6B7280',\n 'status-neutral': '#9CA3AF',\n 'error-background': '#2A1517',\n 'error-border': '#FF9287',\n 'error-text': '#FECACA',\n};\n\n/** What Material themes share whatever their color: flat tonal surfaces, no rims or shadows on planets, raised controls. */\nconst MATERIAL_LOOK: Partial<OrbitThemeTokens> = {\n 'label-weight': '550',\n 'display-weight': '650',\n 'label-letter-spacing': '0',\n 'surface-pattern': 'none',\n 'node-fill-opacity': '1',\n 'moon-opacity': '1',\n 'node-highlight': 'rgba(255, 255, 255, 0)',\n 'node-terminator': 'rgba(0, 0, 0, 0)',\n 'node-shading': 'rgba(0, 0, 0, 0)',\n 'node-stroke-tint': '0%',\n 'node-stroke-width': '0',\n 'node-shadow-opacity': '0',\n 'sun-shadow-opacity': '0',\n 'sun-halo-tint': '0%',\n 'sun-halo-opacity': '0.18',\n 'sun-halo-width': '8',\n 'sun-halo-dash': 'none',\n 'sun-halo-size': '1.16',\n 'ring-tint': '0%',\n 'ring-opacity': '1',\n 'ring-width': '1',\n 'ring-dash': 'none',\n 'link-tint': '0%',\n 'link-opacity': '0.7',\n 'link-width': '1.5',\n 'link-dash': 'none',\n 'control-border': 'transparent',\n 'control-shadow': '0 1px 2px rgba(0, 0, 0, 0.3), 0 2px 6px 2px rgba(0, 0, 0, 0.15)',\n 'control-blur': '0px',\n 'action-border': 'transparent',\n 'action-shadow': '0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 3px 1px rgba(0, 0, 0, 0.15)',\n 'sheet-backdrop': 'rgba(0, 0, 0, 0.32)',\n 'sheet-shadow': '0 1px 3px rgba(0, 0, 0, 0.3), 0 4px 8px 3px rgba(0, 0, 0, 0.15)',\n 'sheet-blur': '0px',\n};\n\n/**\n * Material 3: tonal containers in hues spread around the wheel from\n * Material's baseline purple, the sun in its primary color, on a tonal\n * surface. `materialTheme(color)` builds the same look from any color; these\n * values are what it gives for Material's baseline color (`MATERIAL_SEED`).\n */\nconst MATERIAL: OrbitThemeTokens = {\n ...PAPER,\n ...MATERIAL_LOOK,\n surface: '#FAF9FF',\n text: '#1C1B21',\n 'muted-text': '#484553',\n 'root-text': '#1C1B21',\n 'node-text': '#1C1B21',\n 'node-text-inverse': '#FFFFFF',\n 'color-root': '#6750A4',\n 'color-1': '#DFD8FF',\n 'color-2': '#FBD985',\n 'color-3': '#BCE1FF',\n 'color-4': '#FFD3C7',\n 'color-5': '#76F0EA',\n 'color-6': '#FFD0E9',\n 'color-7': '#B3EBA5',\n 'shade-light': '#C7C4D6',\n 'shade-dark': '#787585',\n 'node-stroke': '#C7C4D6',\n 'badge-stroke': '#FAF9FF',\n 'sun-halo': '#6750A4',\n 'ring-stroke': '#C7C4D6',\n 'link-stroke': '#787585',\n 'focus-ring': '#6750A4',\n 'note-indicator': '#6750A4',\n 'control-background': '#EEEDF6',\n 'control-text': '#1C1B21',\n 'control-muted-text': '#484553',\n 'control-active-background': '#E4DFFF',\n 'control-active-text': '#1D182F',\n 'tooltip-background': '#313036',\n 'tooltip-text': '#F1F0F9',\n 'action-background': '#E9E7F0',\n 'action-text': '#1C1B21',\n 'sheet-background': '#F4F2FB',\n 'sheet-text': '#1C1B21',\n 'sheet-muted-text': '#484553',\n 'sheet-border': '#C7C4D6',\n 'chip-background': '#E4DFFF',\n 'chip-text': '#1D182F',\n 'link-text': '#6750A4',\n 'status-active': '#6750A4',\n 'status-done': '#1C6D26',\n 'status-blocked': '#B91B25',\n 'status-todo': '#928F9F',\n 'status-neutral': '#787585',\n 'error-background': '#FFDAD6',\n 'error-border': '#B91B25',\n 'error-text': '#410004',\n};\n\n/** Material 3's dark scheme: deep tonal containers with light lettering, the sun in the light primary. */\nconst MATERIAL_NIGHT: OrbitThemeTokens = {\n ...NIGHT,\n ...MATERIAL_LOOK,\n 'control-shadow': '0 1px 3px rgba(0, 0, 0, 0.3), 0 4px 8px 3px rgba(0, 0, 0, 0.15)',\n surface: '#141318',\n text: '#E3E1EA',\n 'muted-text': '#C7C4D6',\n 'root-text': '#1C1B21',\n 'node-text': '#1C1B21',\n 'node-text-inverse': '#E3E1EA',\n 'color-root': '#CBBEFF',\n 'color-1': '#524084',\n 'color-2': '#5F4800',\n 'color-3': '#004F7B',\n 'color-4': '#7F341F',\n 'color-5': '#005552',\n 'color-6': '#78335D',\n 'color-7': '#245615',\n 'shade-light': '#5F5D65',\n 'shade-dark': '#201F25',\n 'node-stroke': '#484553',\n 'badge-stroke': '#141318',\n 'sun-halo': '#CBBEFF',\n 'ring-stroke': '#484553',\n 'link-stroke': '#928F9F',\n 'focus-ring': '#CBBEFF',\n 'note-indicator': '#CBBEFF',\n 'control-background': '#201F25',\n 'control-text': '#E3E1EA',\n 'control-muted-text': '#C7C4D6',\n 'control-active-background': '#49435D',\n 'control-active-text': '#E4DFFF',\n 'tooltip-background': '#E3E1EA',\n 'tooltip-text': '#313036',\n 'action-background': '#2A2930',\n 'action-text': '#E3E1EA',\n 'sheet-background': '#1C1B21',\n 'sheet-text': '#E3E1EA',\n 'sheet-muted-text': '#C7C4D6',\n 'sheet-border': '#484553',\n 'chip-background': '#49435D',\n 'chip-text': '#E4DFFF',\n 'link-text': '#CBBEFF',\n 'status-active': '#CBBEFF',\n 'status-done': '#8AD88D',\n 'status-blocked': '#FFB3AD',\n 'status-todo': '#928F9F',\n 'status-neutral': '#ACA9BA',\n 'error-background': '#930014',\n 'error-border': '#FFB3AD',\n 'error-text': '#FFDAD6',\n};\n\n/**\n * Liquid glass: clear planets with a bright specular highlight, a white\n * rim and light caught along the far edge, over a vivid wallpaper of their\n * own that the glass lets through.\n */\nconst LIQUID: OrbitThemeTokens = {\n ...PAPER,\n 'label-letter-spacing': '-0.01em',\n surface: '#E9EEF8',\n 'surface-pattern': [\n 'radial-gradient(70% 55% at 12% 14%, rgba(90, 140, 255, 0.55), transparent 70%)',\n 'radial-gradient(60% 50% at 88% 20%, rgba(255, 120, 190, 0.5), transparent 70%)',\n 'radial-gradient(70% 60% at 30% 92%, rgba(60, 220, 200, 0.45), transparent 72%)',\n 'radial-gradient(55% 45% at 92% 88%, rgba(255, 190, 90, 0.55), transparent 70%)',\n ].join(', '),\n text: '#0F1630',\n 'muted-text': '#3B4560',\n // Dark labels on every planet: the glass lets the light wallpaper through.\n 'root-text': '#0F1630',\n 'node-text': '#0F1630',\n 'node-text-inverse': '#0F1630',\n 'color-root': '#FFC83D',\n 'color-1': '#FF6B7A',\n 'color-2': '#2FD08A',\n 'color-3': '#4DA3FF',\n 'color-4': '#9B7BFF',\n 'color-5': '#FF9A3D',\n 'color-6': '#FF6FB5',\n 'color-7': '#22C7D6',\n 'shade-dark': '#0F1630',\n 'node-fill-opacity': '0.32',\n 'moon-opacity': '0.28',\n // Clear in the middle, with a lens edge: the shading's circle sits a little\n // to the bottom right, so light catches the rim all around, most at the top\n // left, just past a faint darker band where the glass bends the light.\n 'node-highlight': 'rgba(255, 255, 255, 0)',\n 'node-terminator': 'rgba(16, 24, 60, 0.07)',\n 'node-shading': 'rgba(255, 255, 255, 0.95)',\n 'node-shade-circle': '0.53 0.55 0.56',\n 'node-stroke': '#FFFFFF',\n 'node-stroke-tint': '0%',\n 'node-stroke-width': '1.25',\n 'node-shadow': '#1B2550',\n 'node-shadow-tint': '0%',\n 'node-shadow-opacity': '0.16',\n 'node-shadow-offset': '0.14',\n 'node-shadow-size': '1',\n 'sun-shadow-opacity': '0.2',\n 'sun-shadow-size': '1.02',\n 'sun-halo': '#FFFFFF',\n 'sun-halo-tint': '0%',\n 'sun-halo-opacity': '0.9',\n 'sun-halo-width': '1.5',\n 'sun-halo-dash': 'none',\n 'sun-halo-size': '1.1',\n 'ring-stroke': '#FFFFFF',\n 'ring-tint': '0%',\n 'ring-opacity': '0.7',\n 'ring-width': '1.25',\n 'ring-dash': 'none',\n 'link-stroke': '#FFFFFF',\n 'link-tint': '0%',\n 'link-opacity': '0.75',\n 'link-dash': 'none',\n 'note-indicator': '#0F1630',\n 'control-background': 'rgba(255, 255, 255, 0.38)',\n 'control-border': 'rgba(255, 255, 255, 0.75)',\n 'control-text': '#0F1630',\n 'control-muted-text': '#3B4560',\n 'control-active-background': 'rgba(255, 255, 255, 0.85)',\n 'control-active-text': '#0F1630',\n 'control-shadow': '0 10px 30px rgba(20, 30, 70, 0.18), inset 0 1px 0 rgba(255, 255, 255, 0.9)',\n 'control-blur': '24px',\n 'tooltip-background': 'rgba(255, 255, 255, 0.88)',\n 'tooltip-text': '#0F1630',\n 'action-background': 'rgba(255, 255, 255, 0.55)',\n 'action-border': 'rgba(255, 255, 255, 0.85)',\n 'action-text': '#0F1630',\n 'action-shadow': '0 6px 18px rgba(20, 30, 70, 0.18), inset 0 1px 0 rgba(255, 255, 255, 0.9)',\n 'sheet-background': 'rgba(255, 255, 255, 0.7)',\n 'sheet-text': '#0F1630',\n 'sheet-muted-text': '#3B4560',\n 'sheet-border': 'rgba(255, 255, 255, 0.8)',\n 'sheet-backdrop': 'rgba(15, 22, 48, 0.25)',\n 'sheet-shadow': '0 30px 80px rgba(20, 30, 70, 0.3)',\n 'sheet-blur': '30px',\n 'chip-background': 'rgba(255, 255, 255, 0.6)',\n 'chip-text': '#1E293B',\n 'link-text': '#1D4ED8',\n};\n\n/** Liquid glass at night: clear planets that glow in their own color over a deep, vivid wallpaper. */\nconst LIQUID_NIGHT: OrbitThemeTokens = {\n ...NIGHT,\n 'label-letter-spacing': '-0.01em',\n 'label-shadow': '0 1px 3px rgba(3, 6, 20, 0.6)',\n surface: '#070B1A',\n 'surface-pattern': [\n 'radial-gradient(70% 55% at 14% 12%, rgba(79, 70, 229, 0.55), transparent 70%)',\n 'radial-gradient(60% 50% at 88% 22%, rgba(219, 39, 119, 0.42), transparent 70%)',\n 'radial-gradient(70% 60% at 26% 94%, rgba(6, 182, 212, 0.36), transparent 72%)',\n 'radial-gradient(55% 45% at 92% 90%, rgba(249, 115, 22, 0.32), transparent 70%)',\n ].join(', '),\n text: '#F5F7FF',\n 'muted-text': '#B4BDD8',\n // Light labels on every planet: the glass lets the dark wallpaper through.\n 'root-text': '#F8FAFF',\n 'node-text': '#F8FAFF',\n 'node-text-inverse': '#F8FAFF',\n 'color-root': '#FFD66B',\n 'color-1': '#FF6B8B',\n 'color-2': '#34D399',\n 'color-3': '#60A5FA',\n 'color-4': '#A78BFA',\n 'color-5': '#FB923C',\n 'color-6': '#F472B6',\n 'color-7': '#22D3EE',\n 'shade-dark': '#070B1A',\n 'node-fill-opacity': '0.2',\n 'moon-opacity': '0.16',\n 'node-highlight': 'rgba(255, 255, 255, 0)',\n 'node-terminator': 'rgba(255, 255, 255, 0.04)',\n 'node-shading': 'rgba(255, 255, 255, 0.7)',\n 'node-shade-circle': '0.53 0.55 0.56',\n 'node-stroke': 'rgba(255, 255, 255, 0.75)',\n 'node-stroke-tint': '0%',\n 'node-stroke-width': '1.25',\n 'badge-stroke': '#070B1A',\n 'node-shadow-opacity': '0.3',\n 'node-shadow-size': '1.1',\n 'sun-shadow-opacity': '0.45',\n 'sun-shadow-size': '1.3',\n 'sun-halo': '#FFFFFF',\n 'sun-halo-tint': '0%',\n 'sun-halo-opacity': '0.6',\n 'sun-halo-width': '1.5',\n 'sun-halo-dash': 'none',\n 'sun-halo-size': '1.1',\n 'ring-tint': '0%',\n 'ring-opacity': '0.28',\n 'ring-width': '1.25',\n 'ring-dash': 'none',\n 'link-tint': '0%',\n 'link-opacity': '0.35',\n 'link-dash': 'none',\n 'note-indicator': '#F5F7FF',\n 'control-background': 'rgba(255, 255, 255, 0.1)',\n 'control-border': 'rgba(255, 255, 255, 0.22)',\n 'control-text': '#F5F7FF',\n 'control-muted-text': '#B4BDD8',\n 'control-active-background': 'rgba(255, 255, 255, 0.9)',\n 'control-active-text': '#070B1A',\n 'control-shadow': '0 10px 30px rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.25)',\n 'control-blur': '24px',\n 'tooltip-background': 'rgba(245, 247, 255, 0.92)',\n 'tooltip-text': '#070B1A',\n 'action-background': 'rgba(255, 255, 255, 0.12)',\n 'action-border': 'rgba(255, 255, 255, 0.28)',\n 'action-text': '#F5F7FF',\n 'action-shadow': '0 6px 18px rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.25)',\n 'sheet-background': 'rgba(22, 28, 52, 0.72)',\n 'sheet-text': '#F5F7FF',\n 'sheet-muted-text': '#B4BDD8',\n 'sheet-border': 'rgba(255, 255, 255, 0.18)',\n 'sheet-backdrop': 'rgba(2, 4, 14, 0.5)',\n 'sheet-shadow': '0 30px 80px rgba(0, 0, 0, 0.6)',\n 'sheet-blur': '30px',\n 'chip-background': 'rgba(255, 255, 255, 0.12)',\n 'chip-text': '#E8ECFF',\n};\n\nexport const ORBIT_THEME_PRESETS: Readonly<Record<OrbitThemeName, Readonly<OrbitThemeTokens>>> = {\n paper: PAPER,\n night: NIGHT,\n glass: GLASS,\n 'glass-night': GLASS_NIGHT,\n cosmos: COSMOS,\n blueprint: BLUEPRINT,\n ink: INK,\n contrast: CONTRAST,\n flat: FLAT,\n 'flat-night': FLAT_NIGHT,\n material: MATERIAL,\n 'material-night': MATERIAL_NIGHT,\n liquid: LIQUID,\n 'liquid-night': LIQUID_NIGHT,\n};\n\n/** Themes drawn on a dark background, so the browser's own widgets (scrollbars, form controls) match. */\nconst DARK_THEMES = new Set<OrbitThemeName>(['night', 'glass-night', 'cosmos', 'blueprint', 'flat-night', 'material-night', 'liquid-night']);\n\n/** Whether `value` names a built-in theme: one of the presets or `auto`. */\nexport const isOrbitThemePreset = (value: unknown): value is OrbitThemePreset => {\n return typeof value === 'string' && (value === 'auto' || Object.prototype.hasOwnProperty.call(ORBIT_THEME_PRESETS, value));\n};\n\n/** The built-in theme a `theme` option starts from (registered names followed), `paper` when it names none. */\nexport const themeName = (theme: string | OrbitRendererTheme | undefined): OrbitThemePreset => {\n const expanded = expandTheme(theme);\n const preset = typeof expanded === 'string' ? expanded : expanded?.preset;\n return isOrbitThemePreset(preset) ? preset : 'paper';\n};\n\nconst registeredThemes = new Map<string, OrbitRendererTheme>();\n\n/**\n * Names a theme for every map, so `theme: 'brand'` works in options, in a\n * document's frontmatter and on `<orbit-map theme=\"brand\">`. It starts from\n * `preset` (a built-in theme or another registered one) and sets its own\n * tokens. Returns a function that removes it again.\n */\nexport const registerTheme = (name: string, theme: OrbitRendererTheme): () => void => {\n if (isOrbitThemePreset(name)) {\n throw new Error(`\"${name}\" is one of Orbit's own themes; give yours another name.`);\n }\n\n if (!/^[\\w-]+$/.test(name)) {\n throw new Error(`Theme names use letters, digits, \"-\" and \"_\", so they work in attributes and frontmatter: \"${name}\".`);\n }\n\n const definition: OrbitRendererTheme = { preset: theme.preset, tokens: { ...theme.tokens } };\n registeredThemes.set(name, definition);\n\n return () => {\n if (registeredThemes.get(name) === definition) {\n registeredThemes.delete(name);\n }\n };\n};\n\n/** Whether `value` names a theme: a built-in one, `auto`, or a registered one. */\nexport const isThemeName = (value: unknown): value is string => {\n return isOrbitThemePreset(value) || (typeof value === 'string' && registeredThemes.has(value));\n};\n\n/** Every theme name: the built-in ones, `auto`, then the registered ones. */\nexport const themeNames = (): string[] => {\n return [...Object.keys(ORBIT_THEME_PRESETS), 'auto', ...registeredThemes.keys()];\n};\n\n/**\n * A `theme` option with registered names replaced by what they stand for:\n * `'brand'` becomes its `{ preset, tokens }`, and `{ preset: 'brand', tokens }`\n * adds its own tokens on top of brand's.\n */\nexport const expandTheme = (theme: string | OrbitRendererTheme | undefined): string | OrbitRendererTheme | undefined => {\n let expanded = theme;\n\n // A registered theme may start from another; a few steps cover any sensible chain.\n for (let depth = 0; depth < 4; depth += 1) {\n const name = typeof expanded === 'string' ? expanded : expanded?.preset;\n const registered = name === undefined ? undefined : registeredThemes.get(name);\n\n if (!registered) {\n break;\n }\n\n expanded = typeof expanded === 'string' ? registered : { preset: registered.preset, tokens: { ...registered.tokens, ...expanded?.tokens } };\n }\n\n return expanded;\n};\n\n/**\n * Combines a `theme` option with one set before it, such as the document's\n * `theme:`: a theme object without a `preset` builds on the earlier theme\n * instead of replacing it.\n */\nexport const mergeThemes = (\n base: string | OrbitRendererTheme | undefined,\n override: string | OrbitRendererTheme | undefined,\n): string | OrbitRendererTheme | undefined => {\n if (override === undefined || typeof override === 'string' || override.preset !== undefined || base === undefined) {\n return override ?? base;\n }\n\n const preset = typeof base === 'string' ? base : base.preset;\n return preset === undefined ? override : { ...override, preset };\n};\n\n/** Concrete token values for a theme name, built in or registered, e.g. for exports outside a page. `auto` resolves to `paper`. */\nexport const themeTokens = (name: string | undefined): OrbitThemeTokens => {\n const expanded = expandTheme(name);\n return resolveThemeTokens(themeName(expanded), typeof expanded === 'object' ? expanded : undefined);\n};\n\n/** A preset's values as written, where a token may refer to another (`var(--_orbit-font-family)`). */\nconst presetTokens = (preset: OrbitThemePreset | undefined): OrbitThemeTokens => {\n const name = preset ?? 'paper';\n return { ...ORBIT_THEME_PRESETS[name === 'auto' ? 'paper' : name] };\n};\n\n/**\n * Concrete values for every token: the preset's, then the theme object's,\n * then any the page resolved (`page`, already concrete). A token that refers\n * to another, such as the label font following `font-family`, follows it\n * through all three.\n */\nexport const resolveThemeTokens = (\n preset: OrbitThemePreset | undefined,\n theme?: OrbitRendererTheme,\n page: Partial<Record<OrbitThemeToken, string>> = {},\n): OrbitThemeTokens => {\n return resolveTokenReferences({ ...presetTokens(preset), ...themeObjectTokens(theme), ...page }) as OrbitThemeTokens;\n};\n\nconst resolveTokenReferences = (tokens: Record<string, string>): Record<string, string> => {\n const resolved: Record<string, string> = {};\n\n const resolve = (value: string, depth: number): string => {\n if (depth > 4 || !value.includes('var(')) {\n return value;\n }\n\n const substituted = value.replace(/var\\(--_?orbit-([a-z0-9-]+)(?:\\s*,\\s*([^()]+))?\\)/gi, (whole, token: string, fallback?: string) => {\n return tokens[token] ?? fallback?.trim() ?? whole;\n });\n\n return substituted === value ? value : resolve(substituted, depth + 1);\n };\n\n for (const [token, value] of Object.entries(tokens)) {\n resolved[token] = resolve(value, 0);\n }\n\n return resolved;\n};\n\nconst tokenDeclarations = (tokens: OrbitThemeTokens): string => {\n return THEME_TOKENS.map((token) => `--_orbit-${token}:var(--orbit-${token},${tokens[token]});`).join('');\n};\n\n/**\n * Where the stylesheet mixes a node's own color into a theme color, with\n * `color-mix()`: what it paints, the theme color, the tint (how much of the\n * node's own color goes in) and the node's own color.\n */\ninterface ColorMix {\n paints: string;\n base: OrbitThemeToken;\n tint: OrbitThemeToken;\n own: string;\n}\n\nconst MIXES: readonly ColorMix[] = [\n { paints: '.orbit-node__shade{stroke:', base: 'node-stroke', tint: 'node-stroke-tint', own: 'var(--orbit-node-color,var(--_orbit-node-stroke))' },\n { paints: '.orbit-node__shadow{fill:', base: 'node-shadow', tint: 'node-shadow-tint', own: 'var(--orbit-node-color)' },\n { paints: '.orbit-node__halo{stroke:', base: 'sun-halo', tint: 'sun-halo-tint', own: 'var(--orbit-node-color)' },\n { paints: '.orbit-ring{stroke:', base: 'ring-stroke', tint: 'ring-tint', own: 'var(--orbit-ring-color,var(--_orbit-ring-stroke))' },\n { paints: '.orbit-link{stroke:', base: 'link-stroke', tint: 'link-tint', own: 'var(--orbit-link-color,var(--_orbit-link-stroke))' },\n];\n\n/**\n * For browsers without `color-mix()`: each mix of a theme as one of its two\n * colors. The node's own only where the mix is mostly that: even a quarter\n * of the theme's color is what makes a sun's halo show on a light page.\n */\nconst plainMixes = (selector: string, tokens: OrbitThemeTokens): string => {\n return MIXES.map((mix) => `${selector} ${mix.paints}${parseFloat(tokens[mix.tint]) >= 75 ? mix.own : `var(--_orbit-${mix.base})`}}`).join('');\n};\n\n/** CSS that gives `.orbit[data-orbit-theme=\"…\"]` each preset's token defaults. */\nexport const themeStylesheet = (): string => {\n const names = Object.keys(ORBIT_THEME_PRESETS) as OrbitThemeName[];\n const presets = names\n .map((name) => `.orbit[data-orbit-theme=\"${name}\"]{${tokenDeclarations(ORBIT_THEME_PRESETS[name])}color-scheme:${DARK_THEMES.has(name) ? 'dark' : 'light'};}`)\n .join('');\n const automatic = `.orbit[data-orbit-theme=\"auto\"]{${tokenDeclarations(PAPER)}color-scheme:light;}`\n + `@media (prefers-color-scheme: dark){.orbit[data-orbit-theme=\"auto\"]{${tokenDeclarations(NIGHT)}color-scheme:dark;}}`;\n const plain = names.map((name) => plainMixes(`.orbit[data-orbit-theme=\"${name}\"]`, ORBIT_THEME_PRESETS[name])).join('')\n + plainMixes('.orbit[data-orbit-theme=\"auto\"]', PAPER)\n + `@media (prefers-color-scheme: dark){${plainMixes('.orbit[data-orbit-theme=\"auto\"]', NIGHT)}}`;\n return presets + automatic + `@supports not (color: color-mix(in srgb, red, blue)){${plain}}`;\n};\n\nconst PALETTE_TOKENS: OrbitThemeToken[] = ['color-root', 'color-1', 'color-2', 'color-3', 'color-4', 'color-5', 'color-6', 'color-7'];\n\nconst KNOWN_TOKENS = new Set<string>(THEME_TOKENS);\n\n/** The token values a `theme` object sets. Unknown tokens and empty values are skipped. */\nexport const themeObjectTokens = (theme: OrbitRendererTheme | undefined): Partial<OrbitThemeTokens> => {\n const tokens: Partial<OrbitThemeTokens> = {};\n\n for (const [token, value] of Object.entries(theme?.tokens ?? {})) {\n if (KNOWN_TOKENS.has(token) && typeof value === 'string' && value !== '') {\n tokens[token as OrbitThemeToken] = value;\n }\n }\n\n return tokens;\n};\n\n/**\n * Custom properties to set inline on the map for a `theme` object. Each\n * value replaces the preset's default but still yields to a `--orbit-*`\n * property the page sets in its own CSS.\n */\nexport const themeOverrides = (theme: OrbitRendererTheme | undefined): Record<string, string> => {\n const properties: Record<string, string> = {};\n\n for (const [token, value] of Object.entries(themeObjectTokens(theme))) {\n properties[`--_orbit-${token}`] = `var(--orbit-${token}, ${value})`;\n }\n\n return properties;\n};\n\n/**\n * The colors nodes are painted with: the custom palette when given (first\n * entry for the root), otherwise the theme's palette tokens.\n */\nexport const resolvePalette = (palette: string[] | undefined): string[] => {\n if (palette && palette.length > 0) {\n return [...palette];\n }\n\n return PALETTE_TOKENS.map((token) => `var(--_orbit-${token})`);\n};\n",
|
|
8
|
+
"/**\n * \"Did you mean …?\" for keys and values a document misspells: a known\n * synonym (`colour` for `color`, `dark` for `night`), or the closest known name\n * within a couple of typos, ignoring case.\n */\nexport const suggest = (input: string, candidates: readonly string[], synonyms: Readonly<Record<string, string>> = {}): string | undefined => {\n const lowered = input.toLowerCase();\n const synonym = Object.entries(synonyms).find(([word]) => word.toLowerCase() === lowered)?.[1];\n\n if (synonym !== undefined) {\n return synonym;\n }\n\n const allowed = Math.min(2, Math.max(1, Math.floor(input.length / 3)));\n let best: string | undefined;\n let bestDistance = Infinity;\n\n for (const candidate of candidates) {\n const distance = editDistance(lowered, candidate.toLowerCase());\n\n if (distance <= allowed && distance < bestDistance) {\n best = candidate;\n bestDistance = distance;\n }\n }\n\n return best;\n};\n\n/** \" Did you mean \"x\"?\" when there is a suggestion, otherwise nothing. */\nexport const didYouMean = (input: string, candidates: readonly string[], synonyms?: Readonly<Record<string, string>>): string => {\n const suggestion = suggest(input, candidates, synonyms);\n return suggestion === undefined ? '' : ` Did you mean \"${suggestion}\"?`;\n};\n\n/** Edits (insertions, deletions, substitutions and swaps of neighbors) between two words. */\nconst editDistance = (first: string, second: string): number => {\n const rows = first.length + 1;\n const columns = second.length + 1;\n const table: number[][] = Array.from({ length: rows }, (_, row) => Array.from({ length: columns }, (_, column) => (row === 0 ? column : column === 0 ? row : 0)));\n\n for (let row = 1; row < rows; row += 1) {\n for (let column = 1; column < columns; column += 1) {\n const cost = first[row - 1] === second[column - 1] ? 0 : 1;\n table[row][column] = Math.min(table[row - 1][column] + 1, table[row][column - 1] + 1, table[row - 1][column - 1] + cost);\n\n if (row > 1 && column > 1 && first[row - 1] === second[column - 2] && first[row - 2] === second[column - 1]) {\n table[row][column] = Math.min(table[row][column], table[row - 2][column - 2] + 1);\n }\n }\n }\n\n return table[first.length][second.length];\n};\n",
|
|
9
|
+
"import type { OrbitDocumentOptions, RendererOptions } from './types.js';\nimport { isThemeName, themeNames } from './themes.js';\nimport { didYouMean } from './suggest.js';\n\n/** Document-level options accepted in markdown frontmatter and as YAML top-level keys. */\nexport const DOCUMENT_OPTION_KEYS = new Set([\n 'title', 'theme', 'view', 'showRings', 'interactive',\n 'animation', 'speed', 'palette', 'height', 'maxDepth',\n 'className', 'baseUrl', 'schemaVersion', 'flavor',\n]);\n\n/** Keys people (and agents) reach for instead of a document option's name. */\nconst OPTION_SYNONYMS: Record<string, string> = {\n viewMode: 'view',\n mode: 'view',\n rings: 'showRings',\n depth: 'maxDepth',\n colors: 'palette',\n name: 'title',\n orbitAnimation: 'animation',\n orbitSpeed: 'speed',\n class: 'className',\n};\n\n/** Words people (and agents) reach for instead of a theme's name. */\nexport const THEME_SYNONYMS: Record<string, string> = {\n dark: 'night',\n light: 'paper',\n default: 'paper',\n frosted: 'glass',\n 'glass-dark': 'glass-night',\n 'dark-glass': 'glass-night',\n space: 'cosmos',\n stars: 'cosmos',\n 'high-contrast': 'contrast',\n monochrome: 'ink',\n sketch: 'ink',\n solid: 'flat',\n 'flat-dark': 'flat-night',\n 'dark-flat': 'flat-night',\n 'material-you': 'material',\n 'material-dark': 'material-night',\n 'dark-material': 'material-night',\n 'liquid-glass': 'liquid',\n 'liquid-dark': 'liquid-night',\n 'dark-liquid': 'liquid-night',\n 'liquid-glass-night': 'liquid-night',\n};\n\n\n/** The message for a key that isn't a document option, with the option it probably means. */\nexport const unknownOptionMessage = (key: string, place: 'frontmatter' | 'top-level'): string => {\n const known = place === 'top-level' ? [...DOCUMENT_OPTION_KEYS, 'nodes'] : [...DOCUMENT_OPTION_KEYS];\n return `Unknown ${place} key \"${key}\" (ignored).${didYouMean(key, known, place === 'top-level' ? { ...OPTION_SYNONYMS, ...NODES_SYNONYMS } : OPTION_SYNONYMS)}`;\n};\n\n/** Keys people (and agents) reach for instead of a YAML map's `nodes`. */\nconst NODES_SYNONYMS: Record<string, string> = {\n root: 'nodes',\n tree: 'nodes',\n map: 'nodes',\n children: 'nodes',\n items: 'nodes',\n};\n\n/** `true`, `false` and their usual spellings in YAML (`yes`, `off`, `1`, …). */\nconst readFlag = (value: unknown): boolean | undefined => {\n if (typeof value === 'boolean') {\n return value;\n }\n\n const word = String(value).trim().toLowerCase();\n\n if (['true', 'yes', 'on', '1'].includes(word)) {\n return true;\n }\n\n if (['false', 'no', 'off', '0'].includes(word)) {\n return false;\n }\n\n return undefined;\n};\n\n/**\n * Sets one document option from its frontmatter (or YAML top-level) value.\n * A value that can't be used is left out and described to `report`.\n */\nexport const applyDocumentOption = (\n options: OrbitDocumentOptions,\n key: string,\n value: unknown,\n report: (message: string) => void = () => undefined,\n): void => {\n const positiveNumber = (minimum: number): number | undefined => {\n const number = typeof value === 'number' ? value : Number(String(value).trim());\n\n if (Number.isFinite(number) && number >= minimum && String(value).trim() !== '') {\n return number;\n }\n\n report(`${key} must be a number${minimum > 0 ? ' above 0' : ' of 0 or more'}, got \"${String(value)}\".`);\n return undefined;\n };\n\n switch (key) {\n case 'view':\n if (value === 'focus' || value === 'all') {\n options.viewMode = value;\n } else {\n report(`view must be \"focus\" or \"all\" (the overview), got \"${String(value)}\".${didYouMean(String(value), ['focus', 'all'], { overview: 'all', tree: 'all', full: 'all' })}`);\n }\n\n return;\n case 'palette':\n if (Array.isArray(value)) {\n options.palette = value.map(String);\n } else if (typeof value === 'string' && value.trim() !== '') {\n options.palette = value.split(',').map((color) => color.trim()).filter(Boolean);\n } else {\n report('palette must be a list of colors, such as [\"#F8D978\", \"#F5A3A8\"].');\n }\n\n return;\n case 'showRings':\n case 'interactive':\n case 'animation': {\n const flag = readFlag(value);\n\n if (flag === undefined) {\n report(`${key} must be true or false, got \"${String(value)}\".`);\n return;\n }\n\n if (key === 'animation') {\n options.orbitAnimation = flag;\n } else if (key === 'interactive') {\n options.interactive = flag;\n } else {\n options.showRings = flag;\n }\n\n return;\n }\n case 'speed':\n case 'height':\n case 'schemaVersion': {\n const number = positiveNumber(Number.MIN_VALUE);\n\n if (number !== undefined) {\n options[key === 'speed' ? 'orbitSpeed' : key] = number;\n }\n\n return;\n }\n case 'maxDepth': {\n const number = positiveNumber(0);\n\n if (number !== undefined) {\n options.maxDepth = number;\n }\n\n return;\n }\n case 'theme':\n options.theme = String(value);\n\n if (!isThemeName(options.theme)) {\n report(`Unknown theme \"${options.theme}\". Themes: ${themeNames().join(', ')}.${didYouMean(options.theme, themeNames(), THEME_SYNONYMS)}`);\n }\n\n return;\n case 'title':\n case 'className':\n case 'baseUrl':\n if (value !== null && value !== undefined) {\n options[key] = String(value);\n }\n\n return;\n case 'flavor':\n // Read by the dispatcher, not stored.\n if (value !== 'markdown' && value !== 'yaml') {\n report(`flavor must be \"markdown\" or \"yaml\", got \"${String(value)}\".`);\n }\n\n return;\n default:\n return;\n }\n};\n\n/**\n * The renderer options a document asks for in its frontmatter (or YAML\n * top-level keys). `title` becomes the map's accessible label. Container\n * concerns (`height`, `className`) are left to the caller.\n */\nexport const documentToRendererOptions = (options: OrbitDocumentOptions): RendererOptions => {\n const result: RendererOptions = {};\n\n if (options.viewMode) {\n result.viewMode = options.viewMode;\n }\n\n if (options.showRings !== undefined) {\n result.showRings = options.showRings;\n }\n\n if (options.interactive !== undefined) {\n result.interactive = options.interactive;\n }\n\n if (options.orbitAnimation !== undefined) {\n result.orbitAnimation = options.orbitAnimation;\n }\n\n if (Number.isFinite(options.orbitSpeed)) {\n result.orbitSpeed = options.orbitSpeed;\n }\n\n if (Number.isFinite(options.maxDepth)) {\n result.maxDepth = options.maxDepth;\n }\n\n if (options.palette && options.palette.length > 0) {\n result.palette = options.palette;\n }\n\n if (isThemeName(options.theme)) {\n result.theme = options.theme;\n }\n\n if (options.title) {\n result.ariaLabel = options.title;\n }\n\n if (options.baseUrl) {\n result.baseUrl = options.baseUrl;\n }\n\n return result;\n};\n",
|
|
10
|
+
"/**\n * The format's versions. A document says which version it's written for\n * with `schemaVersion` (none means 1). When the format changes, the change\n * goes here with a step that brings older documents up to date, and\n * `SUPPORTED_SCHEMA_VERSION` goes up: documents are upgraded as they're\n * read, and the next save writes them in the new format, changing only\n * what the upgrade changed.\n *\n * A document written for a newer version than this one is read as well as\n * it can be, and reported (`unsupported-schema-version`, an error), so apps\n * can open it without editing it: everything it says is kept on save, but\n * what this version doesn't know of it isn't understood.\n */\n\nimport type { OrbitDocument } from './types.js';\nimport type { DiagnosticCollector } from './diagnostics.js';\n\n/** A change to the format: how a document written for version `from` becomes one for `from + 1`. */\nexport interface FormatUpgrade {\n from: number;\n\n /** Changes the document in place: its options, and its nodes' fields. */\n upgrade: (document: OrbitDocument) => void;\n}\n\n/**\n * The format's changes, oldest first. Empty while the format is at its\n * first version; tests check it ends at `SUPPORTED_SCHEMA_VERSION`.\n */\nexport const FORMAT_UPGRADES: FormatUpgrade[] = [];\n\n/** The newest `schemaVersion` this version of Orbit reads and writes. */\nexport const SUPPORTED_SCHEMA_VERSION = 1;\n\n/**\n * Upgrades a document written for an older version of the format, one step\n * at a time, and says so. A document for a newer version is reported.\n */\nexport const upgradeFormat = (document: OrbitDocument, diagnostics: DiagnosticCollector, line: number | undefined, upgrades: readonly FormatUpgrade[] = FORMAT_UPGRADES): void => {\n const written = document.options.schemaVersion ?? 1;\n const supported = Math.max(SUPPORTED_SCHEMA_VERSION, ...upgrades.map((step) => step.from + 1));\n\n if (written > supported) {\n diagnostics.recover(\n 'unsupported-schema-version',\n `This map is written for version ${written} of the format, and this version of Orbit reads up to ${supported}. Everything in it is kept, but open it with a newer Orbit to change it.`,\n line,\n 'error',\n );\n return;\n }\n\n let version = written;\n\n for (const step of upgrades) {\n if (step.from === version) {\n step.upgrade(document);\n version += 1;\n }\n }\n\n if (version !== written) {\n document.options.schemaVersion = version;\n diagnostics.note('format-upgraded', `Upgraded from version ${written} of the format to ${version}; saving writes it as version ${version}.`, line);\n }\n};\n",
|
|
11
|
+
"/**\n * Tiny YAML subset parser + emitter for Orbit, with no dependencies.\n * Reads what maps and the frontmatter of other apps (Obsidian, static site\n * generators) write: maps, block lists (indented under their key or not),\n * flow lists and maps (`[a, b]`, `{name: Ana}`), strings, numbers,\n * booleans and null, block scalars (`|` literal, `>` folded), plain and\n * quoted strings over several lines, comments, anchors, aliases and merge\n * keys (`&base`, `*base`, `<<: *base`). Not read: tags (`!!str`) and\n * complex keys (`? key`).\n *\n * One leniency on purpose: a value that starts with `#` is text, not a\n * comment, so `color: #FF6B6B` reads as the color people mean.\n */\n\nexport class YamlMiniError extends Error {\n /** 1-based line of the problem in the text given to the parser. */\n line: number;\n\n /** The problem, without where it is. */\n reason: string;\n\n constructor(reason: string, line: number) {\n super(`${reason} at line ${line}`);\n this.name = 'YamlMiniError';\n this.line = line;\n this.reason = reason;\n }\n}\n\nexport type YamlValue = string | number | boolean | null | YamlValue[] | { [k: string]: YamlValue };\n\n/** Values named with `&name` while a document is read, for `*name` to repeat. */\nlet anchors = new Map<string, YamlValue>();\n\n/** Where each key of a block map was written: 1-based lines of the text given to the parser. */\nconst keyLines = new WeakMap<object, Map<string, number>>();\n/** Where each item of a block list starts. */\nconst itemLines = new WeakMap<object, number[]>();\n\nconst noteKeyLine = (map: object, key: string, line: number): void => {\n let lines = keyLines.get(map);\n\n if (!lines) {\n lines = new Map();\n keyLines.set(map, lines);\n }\n\n lines.set(key, line);\n};\n\n/**\n * The line `key` was written on in a map the last `parseYaml` read, or the\n * map's first key's line without one: for problems that point at a node of\n * a YAML document. Flow maps (`{ … }`) have none.\n */\nexport const yamlLineOf = (map: object, key?: string): number | undefined => {\n const lines = keyLines.get(map);\n\n if (!lines) {\n return undefined;\n }\n\n return key === undefined ? lines.values().next().value : lines.get(key);\n};\n\n/** The line item `index` of a block list starts on. */\nexport const yamlItemLine = (list: object, index: number): number | undefined => {\n return itemLines.get(list)?.[index];\n};\n\nexport const parseYaml = (input: string): YamlValue => {\n const lines = normalizeInput(input);\n const previous = anchors;\n anchors = new Map();\n\n try {\n const [value] = parseBlock(lines, 0, 0);\n return value;\n } finally {\n anchors = previous;\n }\n};\n\n/** Lines, without a document's `---` start and `...` end markers. */\nconst normalizeInput = (input: string): string[] => {\n const lines = input.replace(/\\r\\n?/g, '\\n').split('\\n');\n const first = lines.findIndex((line) => line.trim() !== '' && !line.trimStart().startsWith('#'));\n\n if (first !== -1 && /^---\\s*$/.test(lines[first])) {\n lines[first] = '';\n }\n\n let last = lines.length - 1;\n\n while (last >= 0 && lines[last].trim() === '') {\n last--;\n }\n\n if (last !== -1 && /^\\.\\.\\.\\s*$/.test(lines[last])) {\n lines[last] = '';\n }\n\n return lines;\n};\n\nconst parseBlock = (lines: string[], start: number, indent: number): [YamlValue, number] => {\n // Detect: is this block a list (lines start with `- `) or a map?\n const firstContent = nextContentLine(lines, start);\n\n if (firstContent !== -1) {\n const raw = lines[firstContent];\n const lineIndent = leadingSpaces(raw);\n\n if (lineIndent === indent && isListItem(raw, indent)) {\n return parseList(lines, start, indent);\n }\n }\n\n return parseMap(lines, start, indent);\n};\n\n/** Whether the line is a list item at `indent`: `- value`, or a lone `-`. */\nconst isListItem = (raw: string, indent: number): boolean => {\n return raw.slice(indent, indent + 2) === '- ' || raw.slice(indent).trimEnd() === '-';\n};\n\n/** A key as written: unquoted, when it's quoted. */\nconst readKey = (key: string, line: number): string => {\n return key.startsWith('\"') || key.startsWith(\"'\") ? String(parseScalar(key, line)) : key;\n};\n\n/**\n * Sets `obj[key]`, even when `key` is `__proto__`: a plain assignment would\n * then change the object's prototype and lose the key, so it becomes an own\n * enumerable data property.\n */\nexport const assignKey = (obj: Record<string, unknown>, key: string, value: unknown): void => {\n if (key === '__proto__') {\n Object.defineProperty(obj, key, { value, writable: true, enumerable: true, configurable: true });\n } else {\n obj[key] = value;\n }\n};\n\nconst parseMap = (lines: string[], start: number, indent: number): [Record<string, YamlValue>, number] => {\n const obj: Record<string, YamlValue> = {};\n const merged: YamlValue[] = [];\n let i = start;\n\n while (i < lines.length) {\n const raw = lines[i];\n\n if (raw.trim() === '' || raw.trimStart().startsWith('#')) {\n i++;\n continue;\n }\n\n const lineIndent = leadingSpaces(raw);\n\n if (lineIndent < indent) {\n break;\n }\n\n if (lineIndent > indent) {\n throw new YamlMiniError('Unexpected indentation', i + 1);\n }\n\n // A list item here belongs to the key above it (`tags:` then `- a`), which has read it already.\n if (isListItem(raw, indent)) {\n throw new YamlMiniError('Expected \"key: value\"', i + 1);\n }\n\n const content = raw.slice(indent);\n const colonIdx = findUnquotedColon(content);\n\n if (colonIdx < 0) {\n throw new YamlMiniError('Expected \"key: value\"', i + 1);\n }\n\n const key = readKey(content.slice(0, colonIdx).trim(), i + 1);\n const rest = content.slice(colonIdx + 1).trim();\n\n const { value, nextIndex } = parseValueForKey(rest, lines, i, indent);\n\n if (key === '<<') {\n merged.push(value);\n } else {\n assignKey(obj, key, value);\n noteKeyLine(obj, key, i + 1);\n }\n\n i = nextIndex;\n }\n\n // `<<: *base` adds the keys of `base` this map doesn't set itself (its own\n // keys only: `in` would also see `constructor` and `toString` on every object).\n for (const source of merged.flatMap((value) => (Array.isArray(value) ? value : [value]))) {\n if (source && typeof source === 'object' && !Array.isArray(source)) {\n for (const [key, value] of Object.entries(source)) {\n if (!Object.prototype.hasOwnProperty.call(obj, key)) {\n assignKey(obj, key, value);\n }\n }\n }\n }\n\n return [obj, i];\n};\n\nconst parseList = (lines: string[], start: number, indent: number): [YamlValue[], number] => {\n const list: YamlValue[] = [];\n const starts: number[] = [];\n itemLines.set(list, starts);\n let i = start;\n\n while (i < lines.length) {\n const raw = lines[i];\n\n if (raw.trim() === '' || raw.trimStart().startsWith('#')) {\n i++;\n continue;\n }\n\n const lineIndent = leadingSpaces(raw);\n\n if (lineIndent < indent) {\n break;\n }\n\n if (lineIndent > indent || !isListItem(raw, indent)) {\n break;\n }\n\n const itemContent = raw.slice(indent + 2);\n const colonIdx = findUnquotedColon(itemContent);\n const startsValue = /^[&*\"'[{|>]/.test(itemContent.trim());\n starts.push(i + 1);\n\n if (colonIdx >= 0 && !startsValue) {\n const itemMap: Record<string, YamlValue> = {};\n const key = readKey(itemContent.slice(0, colonIdx).trim(), i + 1);\n const rest = itemContent.slice(colonIdx + 1).trim();\n const { value: firstVal, nextIndex: firstNext } = parseValueForKey(rest, lines, i, indent + 2);\n assignKey(itemMap, key, firstVal);\n noteKeyLine(itemMap, key, i + 1);\n i = firstNext;\n\n while (i < lines.length) {\n const r2 = lines[i];\n\n if (r2.trim() === '' || r2.trimStart().startsWith('#')) {\n i++;\n continue;\n }\n\n const ind2 = leadingSpaces(r2);\n\n if (ind2 !== indent + 2) {\n break;\n }\n\n const c2 = r2.slice(indent + 2);\n\n if (isListItem(c2, 0)) {\n break;\n } // next list item, not a continuation key\n\n const k2idx = findUnquotedColon(c2);\n\n if (k2idx < 0) {\n throw new YamlMiniError('Expected \"key: value\"', i + 1);\n }\n\n const key2 = readKey(c2.slice(0, k2idx).trim(), i + 1);\n const rest2 = c2.slice(k2idx + 1).trim();\n const { value: contVal, nextIndex: contNext } = parseValueForKey(rest2, lines, i, indent + 2);\n assignKey(itemMap, key2, contVal);\n noteKeyLine(itemMap, key2, i + 1);\n i = contNext;\n }\n\n list.push(itemMap);\n } else {\n // A scalar, flow value, anchor, alias or block scalar item.\n const { value, nextIndex } = parseValueForKey(itemContent.trim(), lines, i, indent);\n list.push(value);\n i = nextIndex;\n }\n }\n\n return [list, i];\n};\n\n/** A value with its trailing comment taken off: ` # …` outside quotes and brackets, but not at the start. */\nconst stripComment = (text: string): string => {\n let quote: '\"' | \"'\" | null = null;\n\n for (let i = 0; i < text.length; i++) {\n const c = text[i];\n\n if (quote) {\n if (c === '\\\\' && quote === '\"') {\n i++;\n } else if (c === quote) {\n if (quote === \"'\" && text[i + 1] === \"'\") {\n i++;\n } else {\n quote = null;\n }\n }\n\n continue;\n }\n\n // A quote only opens a quoted value at its start or inside a flow value: \"it's\" is plain text.\n if ((c === '\"' || c === \"'\") && (i === 0 || /[\\s[{,:]/.test(text[i - 1]))) {\n quote = c;\n } else if (c === '#' && i > 0 && /\\s/.test(text[i - 1])) {\n return text.slice(0, i).trimEnd();\n }\n }\n\n return text;\n};\n\nconst parseValueForKey = (\n written: string,\n lines: string[],\n i: number,\n parentIndent: number,\n): { value: YamlValue; nextIndex: number } => {\n let rest = stripComment(written);\n // `&name value`: remembered for `*name`.\n const anchor = /^&([^\\s,[\\]{}]+)\\s*/.exec(rest);\n\n if (anchor) {\n rest = rest.slice(anchor[0].length);\n const parsed = parseValueForKey(rest, lines, i, parentIndent);\n anchors.set(anchor[1], parsed.value);\n return parsed;\n }\n\n const alias = /^\\*([^\\s,[\\]{}]+)$/.exec(rest);\n\n if (alias) {\n return { value: aliasValue(alias[1], i + 1), nextIndex: i + 1 };\n }\n\n if (rest === '|' || rest === '>' || /^[|>][-+]?\\d?$/.test(rest)) {\n const fold = rest.startsWith('>');\n // Inside a block scalar there are no YAML comments: a first line like\n // \"### heading\" is content and must anchor the child indent.\n const childIndent = detectChildIndent(lines, i + 1, parentIndent, false);\n\n if (childIndent === null) {\n return { value: '', nextIndex: i + 1 };\n }\n\n const collected: string[] = [];\n let j = i + 1;\n\n while (j < lines.length) {\n const r = lines[j];\n\n if (r.trim() === '') {\n collected.push('');\n j++;\n continue;\n }\n\n const ind = leadingSpaces(r);\n\n if (ind < childIndent) {\n break;\n }\n\n collected.push(r.slice(childIndent));\n j++;\n }\n\n while (collected.length && collected[collected.length - 1] === '') {\n collected.pop();\n }\n\n if (fold) {\n return { value: foldLines(collected), nextIndex: j };\n }\n\n return { value: collected.join('\\n'), nextIndex: j };\n }\n\n if (rest === '') {\n // A list right under its key, at the key's own indentation: `tags:` then `- a`.\n const next = nextContentLine(lines, i + 1);\n\n if (next !== -1 && leadingSpaces(lines[next]) === parentIndent && isListItem(lines[next], parentIndent)) {\n const [val, nextIndex] = parseList(lines, i + 1, parentIndent);\n return { value: val, nextIndex };\n }\n\n const childIndent = detectChildIndent(lines, i + 1, parentIndent);\n\n if (childIndent === null) {\n return { value: null, nextIndex: i + 1 };\n }\n\n const [val, nextLine] = parseBlock(lines, i + 1, childIndent);\n return { value: val, nextIndex: nextLine };\n }\n\n // A quoted string, or a flow list or map, may go on over the next lines.\n const opening = rest[0];\n\n if ((opening === '\"' || opening === \"'\" || opening === '[' || opening === '{') && !closes(rest)) {\n let joined = rest;\n let j = i + 1;\n\n while (j < lines.length && !closes(joined)) {\n const line = lines[j].trim();\n joined += opening === '\"' || opening === \"'\" ? (line === '' ? '\\n' : ` ${line}`) : ` ${line}`;\n j++;\n }\n\n return { value: parseScalar(stripComment(joined.replace(/ \\n /g, '\\n')), i + 1), nextIndex: j };\n }\n\n // A plain value may go on over lines indented under its key.\n const continuation: string[] = [];\n let j = i + 1;\n\n while (j < lines.length) {\n const line = lines[j];\n\n if (line.trim() === '') {\n continuation.push('');\n j++;\n continue;\n }\n\n if (leadingSpaces(line) <= parentIndent || line.trimStart().startsWith('#')) {\n break;\n }\n\n if (findUnquotedColon(line.trim()) >= 0 || isListItem(line, leadingSpaces(line))) {\n throw new YamlMiniError('Unexpected indentation', j + 1);\n }\n\n continuation.push(stripComment(line.trim()));\n j++;\n }\n\n while (continuation.length && continuation[continuation.length - 1] === '') {\n continuation.pop();\n j--;\n }\n\n if (continuation.length > 0) {\n // Trailing blank lines belong to what follows, so they're read again.\n while (j > i + 1 && lines[j - 1].trim() === '') {\n j--;\n }\n\n return { value: foldLines([rest, ...continuation]), nextIndex: j };\n }\n\n return { value: parseScalar(rest, i + 1), nextIndex: i + 1 };\n};\n\n/** Folded lines: a line break between paragraphs, a space within one. */\nconst foldLines = (collected: string[]): string => {\n let out = '';\n let prevBlank = false;\n\n for (let k = 0; k < collected.length; k++) {\n const line = collected[k];\n\n if (line === '') {\n prevBlank = true;\n continue;\n }\n\n if (k === 0) {\n out = line;\n } else if (prevBlank) {\n out += '\\n' + line;\n } else {\n out += ' ' + line;\n }\n\n prevBlank = false;\n }\n\n return out;\n};\n\n/** Whether a quoted string or flow value is closed: its quotes and brackets end in the text. */\nconst closes = (text: string): boolean => {\n const opening = text[0];\n\n if (opening === '\"' || opening === \"'\") {\n for (let i = 1; i < text.length; i++) {\n if (opening === '\"' && text[i] === '\\\\') {\n i++;\n } else if (text[i] === opening) {\n if (opening === \"'\" && text[i + 1] === \"'\") {\n i++;\n } else {\n return true;\n }\n }\n }\n\n return false;\n }\n\n let depth = 0;\n let quote: string | null = null;\n\n for (let i = 0; i < text.length; i++) {\n const c = text[i];\n\n if (quote) {\n if (c === '\\\\' && quote === '\"') {\n i++;\n } else if (c === quote) {\n quote = null;\n }\n } else if (c === '\"' || c === \"'\") {\n quote = c;\n } else if (c === '[' || c === '{') {\n depth++;\n } else if (c === ']' || c === '}') {\n depth--;\n\n if (depth === 0) {\n return true;\n }\n }\n }\n\n return false;\n};\n\nconst aliasValue = (name: string, line: number): YamlValue => {\n if (!anchors.has(name)) {\n throw new YamlMiniError(`Unknown alias *${name}`, line);\n }\n\n return JSON.parse(JSON.stringify(anchors.get(name))) as YamlValue;\n};\n\nconst detectChildIndent = (lines: string[], start: number, parentIndent: number, skipComments = true): number | null => {\n for (let i = start; i < lines.length; i++) {\n const raw = lines[i];\n\n if (raw.trim() === '') {\n continue;\n }\n\n if (skipComments && raw.trimStart().startsWith('#')) {\n continue;\n }\n\n const ind = leadingSpaces(raw);\n\n if (ind <= parentIndent) {\n return null;\n }\n\n return ind;\n }\n\n return null;\n};\n\nconst nextContentLine = (lines: string[], start: number): number => {\n for (let i = start; i < lines.length; i++) {\n const raw = lines[i];\n\n if (raw.trim() !== '' && !raw.trimStart().startsWith('#')) {\n return i;\n }\n }\n\n return -1;\n};\n\nconst leadingSpaces = (line: string): number => {\n let n = 0;\n\n while (n < line.length && line[n] === ' ') {\n n++;\n }\n\n return n;\n};\n\nconst findUnquotedColon = (s: string): number => {\n let inQ: '\"' | \"'\" | null = null;\n let depth = 0;\n\n for (let i = 0; i < s.length; i++) {\n const c = s[i];\n\n if (inQ) {\n if (c === '\\\\' && inQ === '\"') {\n i++;\n continue;\n }\n\n if (c === inQ) {\n inQ = null;\n }\n } else {\n if ((c === '\"' || c === \"'\") && (i === 0 || /[\\s[{,]/.test(s[i - 1]))) {\n inQ = c;\n } else if (c === '[' || c === '{') {\n depth++;\n } else if (c === ']' || c === '}') {\n depth--;\n } else if (c === ':' && depth === 0 && (i + 1 >= s.length || s[i + 1] === ' ' || s[i + 1] === '\\t')) {\n return i;\n }\n }\n }\n\n return -1;\n};\n\nconst parseScalar = (raw: string, line: number): YamlValue => {\n if (raw === '' || raw === '~' || raw === 'null') {\n return null;\n }\n\n if (raw === 'true') {\n return true;\n }\n\n if (raw === 'false') {\n return false;\n }\n\n if (/^-?\\d+$/.test(raw)) {\n return parseInt(raw, 10);\n }\n\n if (/^-?\\d*\\.\\d+$/.test(raw)) {\n return parseFloat(raw);\n }\n\n // Exponents, as YAML 1.2's core schema has them: `1e3`, `1.5E-2`.\n if (/^-?(?:\\d+\\.?\\d*|\\.\\d+)[eE][-+]?\\d+$/.test(raw)) {\n return parseFloat(raw);\n }\n\n if (raw.startsWith('\"')) {\n return parseDoubleQuoted(raw, line);\n }\n\n if (raw.startsWith(\"'\")) {\n return parseSingleQuoted(raw, line);\n }\n\n if (raw.startsWith('[') || raw.startsWith('{')) {\n return parseFlow(raw, line);\n }\n\n if (/^\\*[^\\s,[\\]{}]+$/.test(raw)) {\n return aliasValue(raw.slice(1), line);\n }\n\n return raw;\n};\n\n/** A flow value: `[a, b]`, `{name: Ana}`, and any mix of them. */\nconst parseFlow = (raw: string, line: number): YamlValue => {\n const reader = { text: raw, at: 0 };\n const value = readFlow(reader, line);\n skipFlowSpace(reader);\n\n if (reader.at < raw.length) {\n throw new YamlMiniError(raw[0] === '[' ? 'Unterminated flow array' : 'Unexpected text after a flow value', line);\n }\n\n return value;\n};\n\ninterface FlowReader {\n text: string;\n at: number;\n}\n\nconst skipFlowSpace = (reader: FlowReader): void => {\n while (reader.at < reader.text.length && /\\s/.test(reader.text[reader.at])) {\n reader.at++;\n }\n};\n\nconst readFlow = (reader: FlowReader, line: number): YamlValue => {\n skipFlowSpace(reader);\n const c = reader.text[reader.at];\n\n if (c === '[') {\n reader.at++;\n const items: YamlValue[] = [];\n\n for (;;) {\n skipFlowSpace(reader);\n\n if (reader.at >= reader.text.length) {\n throw new YamlMiniError('Unterminated flow array', line);\n }\n\n if (reader.text[reader.at] === ']') {\n reader.at++;\n return items;\n }\n\n items.push(readFlow(reader, line));\n skipFlowSpace(reader);\n\n if (reader.text[reader.at] === ',') {\n reader.at++;\n } else if (reader.text[reader.at] !== ']') {\n throw new YamlMiniError('Unterminated flow array', line);\n }\n }\n }\n\n if (c === '{') {\n reader.at++;\n const map: Record<string, YamlValue> = {};\n\n for (;;) {\n skipFlowSpace(reader);\n\n if (reader.at >= reader.text.length) {\n throw new YamlMiniError('Unterminated flow map', line);\n }\n\n if (reader.text[reader.at] === '}') {\n reader.at++;\n return map;\n }\n\n const key = readFlowScalar(reader, line, true);\n skipFlowSpace(reader);\n let value: YamlValue = null;\n\n if (reader.text[reader.at] === ':') {\n reader.at++;\n skipFlowSpace(reader);\n value = reader.text[reader.at] === ',' || reader.text[reader.at] === '}' ? null : readFlow(reader, line);\n }\n\n assignKey(map, String(key), value);\n skipFlowSpace(reader);\n\n if (reader.text[reader.at] === ',') {\n reader.at++;\n } else if (reader.text[reader.at] !== '}') {\n throw new YamlMiniError('Unterminated flow map', line);\n }\n }\n }\n\n return readFlowScalar(reader, line, false);\n};\n\n/** A scalar inside a flow value: quoted, or plain up to `,` `]` `}` (and, for a key, `: `). */\nconst readFlowScalar = (reader: FlowReader, line: number, key: boolean): YamlValue => {\n const { text } = reader;\n const start = reader.at;\n const c = text[start];\n\n if (c === '\"' || c === \"'\") {\n let end = start + 1;\n\n while (end < text.length) {\n if (c === '\"' && text[end] === '\\\\') {\n end += 2;\n continue;\n }\n\n if (text[end] === c) {\n if (c === \"'\" && text[end + 1] === \"'\") {\n end += 2;\n continue;\n }\n\n break;\n }\n\n end++;\n }\n\n reader.at = end + 1;\n return parseScalar(text.slice(start, end + 1), line);\n }\n\n let end = start;\n\n while (end < text.length) {\n const here = text[end];\n\n if (here === ',' || here === ']' || here === '}') {\n break;\n }\n\n if (key && here === ':' && (end + 1 >= text.length || /[\\s,}\\]]/.test(text[end + 1]))) {\n break;\n }\n\n end++;\n }\n\n reader.at = end;\n const plain = text.slice(start, end).trim();\n return key ? plain : parseScalar(plain, line);\n};\n\nconst DOUBLE_QUOTE_ESCAPES: Record<string, string> = {\n '\"': '\"', '\\\\': '\\\\', '/': '/', b: '\\b', f: '\\f', n: '\\n', r: '\\r', t: '\\t', '0': '\\0',\n};\n\nconst parseDoubleQuoted = (raw: string, line: number): string => {\n if (!raw.endsWith('\"') || raw.length < 2) {\n throw new YamlMiniError('Unterminated string', line);\n }\n\n const body = raw.slice(1, -1);\n let out = '';\n\n for (let i = 0; i < body.length; i++) {\n const c = body[i];\n\n if (c !== '\\\\') {\n out += c;\n continue;\n }\n\n const next = body[++i];\n\n if (next === undefined) {\n throw new YamlMiniError('Dangling escape in string', line);\n }\n\n if (next === 'u') {\n const hex = body.slice(i + 1, i + 5);\n\n if (!/^[0-9a-fA-F]{4}$/.test(hex)) {\n throw new YamlMiniError('Invalid \\\\u escape', line);\n }\n\n out += String.fromCharCode(parseInt(hex, 16));\n i += 4;\n continue;\n }\n\n out += DOUBLE_QUOTE_ESCAPES[next] ?? next;\n }\n\n return out;\n};\n\nconst parseSingleQuoted = (raw: string, line: number): string => {\n if (!raw.endsWith(\"'\") || raw.length < 2) {\n throw new YamlMiniError('Unterminated string', line);\n }\n\n return raw.slice(1, -1).replace(/''/g, \"'\");\n};\n\n// Emitter\n\nexport const emitYaml = (value: YamlValue): string => {\n return emit(value, 0).trimEnd() + '\\n';\n};\n\nconst emit = (value: YamlValue, indent: number): string => {\n if (value === null) {\n return 'null\\n';\n }\n\n if (typeof value === 'boolean') {\n return `${value}\\n`;\n }\n\n if (typeof value === 'number') {\n return `${value}\\n`;\n }\n\n if (typeof value === 'string') {\n return emitString(value, indent);\n }\n\n if (Array.isArray(value)) {\n return emitArray(value, indent);\n }\n\n return emitMap(value, indent);\n};\n\n/**\n * A string can be emitted as a `|` literal block only when the parser will\n * reconstruct it exactly: the first content line anchors the block's child\n * indent (so it must not start with whitespace), whitespace-only lines and\n * trailing blank lines are normalized away by the parser, and `\\r` would be\n * normalized to `\\n`. Anything else must be JSON-quoted.\n */\nconst blockScalarSafe = (s: string): boolean => {\n // \"-->\" would end the HTML comment the YAML is written in; quoted, it can be escaped.\n if (s.includes('\\r') || /--!?>/.test(s)) {\n return false;\n }\n\n const lines = s.split('\\n');\n\n if (lines[lines.length - 1].trim() === '') {\n return false;\n }\n\n const firstContent = lines.find((l) => l.trim() !== '');\n\n if (firstContent === undefined || /^[ \\t]/.test(firstContent)) {\n return false;\n }\n\n // A content line that trims to `---` would close the markdown frontmatter\n // around the YAML early: findFrontmatter compares trimmed lines.\n if (lines.some((line) => line.trim() === '---')) {\n return false;\n }\n\n return !lines.some((l) => /^[ \\t]+$/.test(l));\n};\n\nconst emitMultiline = (v: string, keyPrefix: string, blockIndent: number): string => {\n if (blockScalarSafe(v)) {\n const pad = ' '.repeat(blockIndent);\n let out = `${keyPrefix} |\\n`;\n\n for (const line of v.split('\\n')) {\n out += `${pad}${line}\\n`;\n }\n\n return out;\n }\n\n return `${keyPrefix} ${JSON.stringify(v)}\\n`;\n};\n\nconst emitMap = (obj: { [k: string]: YamlValue }, indent: number): string => {\n const pad = ' '.repeat(indent);\n let out = '';\n\n for (const [key, v] of Object.entries(obj)) {\n if (v === undefined) {\n continue;\n } // treat like JSON.stringify: key is absent\n\n const writtenKey = formatKey(key);\n\n if (v === null) {\n out += `${pad}${writtenKey}: null\\n`;\n continue;\n }\n\n if (typeof v === 'string') {\n if (v.includes('\\n')) {\n out += emitMultiline(v, `${pad}${writtenKey}:`, indent + 2);\n } else {\n out += `${pad}${writtenKey}: ${needsQuotes(v) ? JSON.stringify(v) : v}\\n`;\n }\n } else if (typeof v === 'number' || typeof v === 'boolean') {\n out += `${pad}${writtenKey}: ${v}\\n`;\n } else if (Array.isArray(v)) {\n if (v.length === 0) {\n out += `${pad}${writtenKey}: []\\n`;\n continue;\n }\n\n const allScalar = v.every((x) => typeof x === 'string' || typeof x === 'number' || typeof x === 'boolean');\n\n if (allScalar && v.every((x) => typeof x !== 'string' || !needsQuotes(x as string))) {\n out += `${pad}${writtenKey}: [${v.map((x) => formatScalar(x as YamlValue)).join(', ')}]\\n`;\n } else {\n out += `${pad}${writtenKey}:\\n${emitArray(v, indent + 2)}`;\n }\n } else if (Object.values(v).some((item) => item !== undefined)) {\n out += `${pad}${writtenKey}:\\n${emit(v, indent + 2)}`;\n } else {\n // An empty map: written as a flow value, or it would read back as null.\n out += `${pad}${writtenKey}: {}\\n`;\n }\n }\n\n return out;\n};\n\nconst emitArray = (arr: YamlValue[], indent: number): string => {\n const pad = ' '.repeat(indent);\n let out = '';\n\n for (const item of arr) {\n if (item !== null && typeof item === 'object' && !Array.isArray(item)) {\n const entries = Object.entries(item).filter(([, v]) => v !== undefined);\n\n if (entries.length === 0) {\n out += `${pad}- {}\\n`;\n continue;\n }\n\n const [firstKey, firstVal] = entries[0];\n\n if (keyNeedsQuotes(firstKey)) {\n // A quoted key can't start the `- ` line: it would read as a scalar item.\n out += `${pad}-\\n${emitMap(item, indent + 2)}`;\n continue;\n }\n\n if (firstVal !== null && typeof firstVal === 'object') {\n const flow = emptyCollection(firstVal);\n out += flow === null ? `${pad}- ${firstKey}:\\n${emit(firstVal, indent + 4)}` : `${pad}- ${firstKey}: ${flow}\\n`;\n } else if (typeof firstVal === 'string' && firstVal.includes('\\n')) {\n out += emitMultiline(firstVal, `${pad}- ${firstKey}:`, indent + 4);\n } else {\n out += `${pad}- ${firstKey}: ${formatScalar(firstVal)}\\n`;\n }\n\n for (const [k, v] of entries.slice(1)) {\n const writtenKey = formatKey(k);\n\n if (v !== null && typeof v === 'object' && !Array.isArray(v)) {\n const flow = emptyCollection(v);\n out += flow === null ? `${pad} ${writtenKey}:\\n${emit(v, indent + 4)}` : `${pad} ${writtenKey}: ${flow}\\n`;\n } else if (Array.isArray(v)) {\n if (v.length === 0) {\n out += `${pad} ${writtenKey}: []\\n`;\n }\n else {\n const allScalar = v.every((x) => typeof x !== 'object' || x === null);\n\n if (allScalar) {\n out += `${pad} ${writtenKey}: [${v.map((x) => formatScalar(x as YamlValue)).join(', ')}]\\n`;\n }\n else {\n out += `${pad} ${writtenKey}:\\n${emitArray(v, indent + 4)}`;\n }\n }\n } else if (typeof v === 'string' && v.includes('\\n')) {\n out += emitMultiline(v, `${pad} ${writtenKey}:`, indent + 4);\n } else {\n out += `${pad} ${writtenKey}: ${formatScalar(v)}\\n`;\n }\n }\n } else {\n out += `${pad}- ${formatScalar(item)}\\n`;\n }\n }\n\n return out;\n};\n\n/** A map or list with nothing in it, written as a flow value so it doesn't read back as null. */\nconst emptyCollection = (value: YamlValue): string | null => {\n if (Array.isArray(value)) {\n return value.length === 0 ? '[]' : null;\n }\n\n if (typeof value !== 'object' || value === null) {\n return null;\n }\n\n return Object.values(value).some((item) => item !== undefined) ? null : '{}';\n};\n\n/**\n * A key as written: plain when the parser hands it back unchanged, quoted\n * when it wouldn't (`a: b`, ` padded `, `- item`, a quote of its own first).\n */\nconst formatKey = (key: string): string => {\n return keyNeedsQuotes(key) ? JSON.stringify(key) : key;\n};\n\nconst keyNeedsQuotes = (key: string): boolean => {\n if (key === '' || key !== key.trim() || /^[\"']/.test(key) || /^-(\\s|$)/.test(key)) {\n return true;\n }\n\n // Control characters survive only via double-quote escapes.\n // eslint-disable-next-line no-control-regex\n if (/[\\u0000-\\u001F\\u007F]/.test(key)) {\n return true;\n }\n\n // The parser must find the colon that ends the key, not one inside it.\n return findUnquotedColon(`${key}: x`) !== key.length;\n};\n\nconst emitString = (s: string, indent: number): string => {\n if (s.includes('\\n')) {\n if (!blockScalarSafe(s)) {\n return `${JSON.stringify(s)}\\n`;\n }\n\n const pad = ' '.repeat(indent);\n return '|\\n' + s.split('\\n').map((l) => pad + l).join('\\n') + '\\n';\n }\n\n return needsQuotes(s) ? `${JSON.stringify(s)}\\n` : `${s}\\n`;\n};\n\nconst formatScalar = (v: YamlValue): string => {\n if (v === null) {\n return 'null';\n }\n\n if (typeof v === 'string') {\n return needsQuotes(v) ? JSON.stringify(v) : v;\n }\n\n return String(v);\n};\n\n/**\n * Words and numbers other YAML readers take for something besides text:\n * YAML 1.1 booleans (`yes`, `On`), nulls, and numbers in any notation.\n */\nconst NOT_TEXT_ELSEWHERE = /^(?:y|n|yes|no|on|off|true|false|null|~)$|^[-+]?(?:\\.?\\d|\\.(?:inf|nan)$)|^0[xob]/i;\n\n/**\n * Whether a string written plain would read back as itself: no when other\n * YAML readers would take it for a number or boolean, and no when this\n * parser itself would hand back something else. Used by the emitter.\n */\nexport const needsQuotes = (s: string): boolean => {\n if (s === '' || NOT_TEXT_ELSEWHERE.test(s)) {\n return true;\n }\n\n // Anything this reader wouldn't hand back as the same text, written plain.\n try {\n if (parseScalar(s, 0) !== s) {\n return true;\n }\n } catch {\n return true;\n }\n\n if (/[:,#[{}&*!|>'\"%@`]/.test(s)) {\n return true;\n }\n\n if (/^[ ]|[ ]$/.test(s)) {\n return true;\n }\n\n // Control characters (\\r, \\t, ...) survive only via double-quote escapes.\n // eslint-disable-next-line no-control-regex\n if (/[\\u0000-\\u001F\\u007F]/.test(s)) {\n return true;\n }\n\n return false;\n};\n\n/**\n * Whether a one-line value written plain after `key:` reads back as the same\n * string through this parser: no anchors (`&a`), aliases (`*a`), block-scalar\n * starts (`|`, `>+`), comments (` #`), or scalars read as something else\n * (`~`, `.5`). Unlike `needsQuotes` this ignores what *other* YAML readers\n * would do; markdown-writing uses it for values inside `<!-- orbit … -->`\n * comments, which only Orbit reads.\n */\nexport const plainScalarReadsBack = (s: string): boolean => {\n if (s === '' || s !== s.trim()) {\n return false;\n }\n\n if (stripComment(s) !== s) {\n return false;\n }\n\n if (/^&[^\\s,[\\]{}]+/.test(s) || /^\\*[^\\s,[\\]{}]+$/.test(s) || /^[|>][-+]?\\d?$/.test(s)) {\n return false;\n }\n\n try {\n return parseScalar(s, 0) === s;\n } catch {\n return false;\n }\n};\n",
|
|
12
|
+
"/**\n * URL guard for Orbit. Validates the scheme per render surface, lets\n * relative URLs through unchanged, and resolves them against an optional\n * baseUrl.\n */\n\nexport type UrlSurface = 'image' | 'video' | 'embed' | 'link';\n\nconst warned = new Set<string>();\nconst WARN_LIMIT = 500;\n\n/**\n * A URL as browsers read it: without the control characters and spaces at\n * its ends, and without tabs and line breaks anywhere. The URL standard drops\n * them before it reads the scheme, so \" javascript:\" and \"java\\tscript:\"\n * are both \"javascript:\" to a browser.\n */\nexport const normalizeUrl = (url: string): string => {\n // eslint-disable-next-line no-control-regex\n return url.replace(/^[\\u0000-\\u0020]+|[\\u0000-\\u0020]+$/g, '').replace(/[\\t\\n\\r]/g, '');\n};\n\n/**\n * The URL to use on `surface`, or null when its scheme isn't allowed there.\n * Checks the URL the way a browser will read it, and returns it in that form.\n * A blocked URL is reported on the console, unless `report` is false: for\n * checking one before it goes into a map.\n */\nexport const guardUrl = (input: string, surface: UrlSurface, report = true): string | null => {\n const warn = report ? warnOnce : () => undefined;\n const url = normalizeUrl(input);\n\n // Protocol-relative URLs (//host/path) are absolute on a base; route through the allowlist.\n if (url.startsWith('//')) {\n const probe = `https:${url}`;\n let parsed: URL;\n\n try {\n parsed = new URL(probe);\n } catch {\n warn(url, 'unparseable URL');\n return null;\n }\n\n if (!schemeAllowed('https', surface, parsed)) {\n warn(url, `surface \"${surface}\" forbidden`);\n return null;\n }\n\n return url;\n }\n\n if (!hasScheme(url)) {\n return url;\n }\n\n let parsed: URL;\n\n try {\n parsed = new URL(url);\n } catch {\n warn(url, 'unparseable URL');\n return null;\n }\n\n const scheme = parsed.protocol.replace(/:$/, '');\n\n if (!schemeAllowed(scheme, surface, parsed)) {\n warn(url, `surface \"${surface}\" forbidden`);\n return null;\n }\n\n return url;\n};\n\nconst hasScheme = (url: string): boolean => {\n return /^[a-z][a-z0-9+.-]*:/i.test(url);\n};\n\nconst schemeAllowed = (scheme: string, surface: UrlSurface, parsed: URL): boolean => {\n if (scheme === 'http' || scheme === 'https') {\n return true;\n }\n\n if (scheme === 'data' && surface === 'image') {\n return /^data:image\\/(png|jpeg|jpg|gif|webp|avif|bmp|ico);/i.test(parsed.href);\n }\n\n if (scheme === 'blob') {\n return surface === 'image' || surface === 'video';\n }\n\n if (scheme === 'mailto' || scheme === 'tel' || scheme === 'sms') {\n return surface === 'link';\n }\n\n return false;\n};\n\nconst warnOnce = (url: string, why: string): void => {\n if (warned.has(url)) {\n return;\n }\n\n if (warned.size >= WARN_LIMIT) {\n return;\n }\n\n warned.add(url);\n\n if (typeof console !== 'undefined') {\n console.warn(`[orbit] blocked URL (${why}): ${url}`);\n }\n};\n\n/**\n * Resolve a baseUrl string to its canonical absolute href.\n *\n * - Absolute baseUrls (`https://example.com/assets/`) are returned as `URL().href`.\n * - Relative baseUrls (`/assets/`, `./foo/`) are resolved against `document.baseURI` in browsers.\n * - Throws if baseUrl is relative and no `document.baseURI` is available (Node/SSR).\n */\nexport const resolveBaseUrl = (baseUrl: string): string => {\n try {\n return new URL(baseUrl).href;\n } catch {\n if (typeof document !== 'undefined' && document.baseURI) {\n return new URL(baseUrl, document.baseURI).href;\n }\n\n throw new Error(\n `RendererOptions.baseUrl is relative (\"${baseUrl}\") and no document.baseURI is available. ` +\n `Provide an absolute baseUrl when running outside a browser document context.`,\n );\n }\n};\n\n/**\n * Resolve `url` against `baseUrl` if relative; pass through if absolute or no baseUrl.\n *\n * - Absolute URLs (https://, http://, etc.) pass through unchanged.\n * - Protocol-relative URLs (//host/path) are treated as already-absolute (resolved by the browser at fetch time).\n * - Relative URLs (foo.jpg, ./x, /assets/y) are resolved against `baseUrl`.\n *\n * For directory-relative resolution, `baseUrl` should end with `/`.\n * Per WHATWG URL spec, `new URL('foo.jpg', 'https://x/dir')` yields `https://x/foo.jpg`\n * (the trailing path segment is consumed); `new URL('foo.jpg', 'https://x/dir/')` yields `https://x/dir/foo.jpg`.\n */\nexport const resolveUrl = (url: string, baseUrl: string | undefined): string => {\n if (!baseUrl) {\n return url;\n }\n\n if (url.startsWith('//')) {\n return url;\n }\n\n try {\n new URL(url);\n return url; // already absolute\n } catch {\n const base = resolveBaseUrl(baseUrl);\n return new URL(url, base).href;\n }\n};\n",
|
|
13
|
+
"/**\n * Video provider helpers shared by the parser (provider detection), the\n * renderer (thumbnail derivation), and the detail sheet and media viewer\n * (embed URL conversion, and links to a video's page on its site).\n *\n * YouTube and Vimeo forbid framing their watch pages (X-Frame-Options /\n * frame-ancestors); only the dedicated embed endpoints may be iframed, so\n * anything that puts a video URL into an <iframe> must go through\n * `toVideoEmbedUrl` first.\n */\n\nimport { normalizeUrl } from './url-guard.js';\n\nexport type VideoProvider = 'youtube' | 'vimeo' | 'native';\n\nconst YOUTUBE_HOSTS = new Set(['youtube.com', 'www.youtube.com', 'm.youtube.com', 'music.youtube.com', 'youtube-nocookie.com', 'www.youtube-nocookie.com', 'youtu.be']);\nconst VIMEO_HOSTS = new Set(['vimeo.com', 'www.vimeo.com', 'player.vimeo.com']);\nconst NATIVE_VIDEO = /\\.(mp4|webm|mov)(?:[?#]|$)/i;\n/** A YouTube or Vimeo address written without its scheme, such as `youtu.be/…`. */\nconst BARE_HOST = /^(?:(?:www|m|music|player)\\.)?(?:youtube\\.com|youtube-nocookie\\.com|youtu\\.be|vimeo\\.com)\\//i;\nconst YOUTUBE_ID = /^[A-Za-z0-9_-]{6,}$/;\n\n/** A web address, by its parts; null for relative URLs and other schemes. */\nconst webUrl = (url: string): URL | null => {\n const text = normalizeUrl(url);\n const absolute = text.startsWith('//') ? `https:${text}` : BARE_HOST.test(text) ? `https://${text}` : text;\n\n try {\n const parsed = new URL(absolute);\n return parsed.protocol === 'https:' || parsed.protocol === 'http:' ? parsed : null;\n } catch {\n return null;\n }\n};\n\n/** Which player a video URL needs, by the site it is on; null when it isn't a video. */\nexport const detectVideoProvider = (url: string): VideoProvider | null => {\n const parsed = webUrl(url);\n const host = parsed?.hostname.toLowerCase();\n\n if (host && YOUTUBE_HOSTS.has(host)) {\n return 'youtube';\n }\n\n if (host && VIMEO_HOSTS.has(host)) {\n return 'vimeo';\n }\n\n if (NATIVE_VIDEO.test(parsed ? parsed.pathname : url)) {\n return 'native';\n }\n\n return null;\n};\n\nexport const isNativeVideoUrl = (url: string): boolean => {\n return NATIVE_VIDEO.test(url);\n};\n\n/** The video id in any of YouTube's URL shapes: watch pages, youtu.be, embeds, Shorts and lives. */\nexport const youtubeVideoId = (url: string): string | null => {\n const parsed = webUrl(url);\n const host = parsed?.hostname.toLowerCase();\n\n if (!parsed || !host || !YOUTUBE_HOSTS.has(host)) {\n return null;\n }\n\n const segments = parsed.pathname.split('/').filter(Boolean);\n let id: string | null | undefined;\n\n if (host === 'youtu.be') {\n id = segments[0];\n } else if (segments[0] === 'watch') {\n id = parsed.searchParams.get('v');\n } else if (['embed', 'shorts', 'live', 'v'].includes(segments[0])) {\n id = segments[1];\n }\n\n return id && YOUTUBE_ID.test(id) ? id : null;\n};\n\n/**\n * A Vimeo video's id, and the hash an unlisted video needs, from its page\n * (`vimeo.com/123`, `/123/abc`, channels, groups, showcases) or its player.\n */\nexport const vimeoVideo = (url: string): { id: string; hash?: string } | null => {\n const parsed = webUrl(url);\n const host = parsed?.hostname.toLowerCase();\n\n if (!parsed || !host || !VIMEO_HOSTS.has(host)) {\n return null;\n }\n\n const segments = parsed.pathname.split('/').filter(Boolean);\n const hash = (value: string | null | undefined) => (value && /^[0-9a-f]{6,}$/i.test(value) ? value : undefined);\n\n if (host === 'player.vimeo.com') {\n return segments[0] === 'video' && /^\\d+$/.test(segments[1] ?? '') ? { id: segments[1], hash: hash(parsed.searchParams.get('h')) } : null;\n }\n\n if (/^\\d+$/.test(segments[0] ?? '')) {\n return { id: segments[0], hash: hash(segments[1]) };\n }\n\n let index = -1;\n\n if (segments[0] === 'video') {\n index = 1;\n } else if (segments[0] === 'channels') {\n index = 2;\n } else if (segments[0] === 'groups' && segments[2] === 'videos') {\n index = 3;\n } else if ((segments[0] === 'album' || segments[0] === 'showcase') && segments[2] === 'video') {\n index = 3;\n }\n\n const id = index > 0 ? segments[index] : undefined;\n return id && /^\\d+$/.test(id) ? { id, hash: hash(segments[index + 1]) } : null;\n};\n\n/** The numeric id of a Vimeo video. */\nexport const vimeoVideoId = (url: string): string | null => {\n return vimeoVideo(url)?.id ?? null;\n};\n\n/**\n * Convert a video URL to a frameable embed URL. Returns null when no\n * conversion is known (callers fall back to the original URL).\n */\nexport const toVideoEmbedUrl = (url: string, provider?: string): string | null => {\n const kind = provider === 'youtube' || provider === 'vimeo' ? provider : detectVideoProvider(url);\n\n if (kind === 'youtube') {\n const id = youtubeVideoId(url);\n return id ? `https://www.youtube-nocookie.com/embed/${id}` : null;\n }\n\n if (kind === 'vimeo') {\n const video = vimeoVideo(url);\n return video ? `https://player.vimeo.com/video/${video.id}${video.hash ? `?h=${video.hash}` : ''}` : null;\n }\n\n return null;\n};\n\n/** Whether a YouTube URL is a Short, a video that plays upright. */\nexport const isYouTubeShort = (url: string): boolean => {\n const parsed = webUrl(url);\n return parsed !== null && YOUTUBE_HOSTS.has(parsed.hostname.toLowerCase()) && parsed.pathname.split('/').filter(Boolean)[0] === 'shorts';\n};\n\n/** Where a video is watched on its site: its YouTube or Vimeo page, or the URL itself. */\nexport const videoPageUrl = (url: string, provider?: string): string => {\n const kind = provider === 'youtube' || provider === 'vimeo' ? provider : detectVideoProvider(url);\n\n if (kind === 'youtube') {\n const id = youtubeVideoId(url);\n\n if (id) {\n return isYouTubeShort(url) ? `https://www.youtube.com/shorts/${id}` : `https://www.youtube.com/watch?v=${id}`;\n }\n }\n\n if (kind === 'vimeo') {\n const video = vimeoVideo(url);\n\n if (video) {\n return `https://vimeo.com/${video.id}${video.hash ? `/${video.hash}` : ''}`;\n }\n }\n\n return url;\n};\n\nexport const youtubeThumbnailUrl = (url: string): string | null => {\n const id = youtubeVideoId(url);\n return id ? `https://img.youtube.com/vi/${id}/hqdefault.jpg` : null;\n};\n\n/** True when an image, video or embed value has a usable `src`. */\nexport const hasMediaSource = (media: { src?: unknown } | undefined | null): media is { src: string } => {\n return Boolean(media) && typeof media!.src === 'string' && media!.src.trim() !== '';\n};\n",
|
|
14
|
+
"/**\n * Source text helpers shared by the dispatcher and both parsers. Normalizing\n * never adds or removes lines, so diagnostics keep pointing at the line the\n * author wrote.\n */\n\n/**\n * Strips a byte-order mark, converts CRLF/CR line endings to LF, and removes\n * indentation shared by every non-blank line, so markdown indented inside\n * HTML or a template literal parses like flush-left markdown.\n */\nexport const normalizeSource = (input: string): string => {\n // Only a byte-order mark at the start: U+FEFF inside the text is a zero-width no-break space, and kept.\n const text = input.replace(/^\\uFEFF/, '').replace(/\\r\\n?/g, '\\n');\n return dedent(text);\n};\n\n/** The indentation every non-blank line shares, which `normalizeSource` removes. */\nexport const sharedIndentation = (text: string): string => {\n let common: string | null = null;\n\n for (const line of text.split('\\n')) {\n if (line.trim() === '') {\n continue;\n }\n\n const indent = /^[ \\t]*/.exec(line)![0];\n\n if (common === null) {\n common = indent;\n continue;\n }\n\n let length = 0;\n\n while (length < common.length && length < indent.length && common[length] === indent[length]) {\n length += 1;\n }\n\n common = common.slice(0, length);\n\n if (common === '') {\n return '';\n }\n }\n\n return common ?? '';\n};\n\nexport const dedent = (text: string): string => {\n const lines = text.split('\\n');\n let common: string | null = null;\n\n for (const line of lines) {\n if (line.trim() === '') {\n continue;\n }\n\n const indent = /^[ \\t]*/.exec(line)![0];\n\n if (common === null) {\n common = indent;\n continue;\n }\n\n let length = 0;\n\n while (length < common.length && length < indent.length && common[length] === indent[length]) {\n length += 1;\n }\n\n common = common.slice(0, length);\n\n if (common === '') {\n return text;\n }\n }\n\n if (!common) {\n return text;\n }\n\n const prefix = common;\n return lines\n .map((line) => {\n if (line.startsWith(prefix)) {\n return line.slice(prefix.length);\n }\n\n // Only a blank line can miss the shared indent (a shorter one): drop\n // just the part they share, so saving can put the rest back.\n let shared = 0;\n\n while (shared < line.length && line[shared] === prefix[shared]) {\n shared += 1;\n }\n\n return line.slice(shared);\n })\n .join('\\n');\n};\n\nexport const firstContentLineIndex = (lines: string[]): number => {\n return lines.findIndex((line) => line.trim() !== '');\n};\n\nexport interface FrontmatterBlock {\n /** The YAML between the fences. */\n yaml: string;\n\n /** 0-based index of the opening `---` line. */\n openIndex: number;\n\n /** 0-based index of the closing `---` line. */\n closeIndex: number;\n}\n\n/** Frontmatter is a `---` fenced block starting on the first non-blank line. */\nexport const findFrontmatter = (lines: string[]): FrontmatterBlock | null => {\n const openIndex = firstContentLineIndex(lines);\n\n if (openIndex === -1 || lines[openIndex].trim() !== '---') {\n return null;\n }\n\n for (let index = openIndex + 1; index < lines.length; index += 1) {\n if (lines[index].trim() === '---') {\n return { yaml: lines.slice(openIndex + 1, index).join('\\n'), openIndex, closeIndex: index };\n }\n }\n\n return null;\n};\n\n/** 1-based line of the first `key:` entry inside a frontmatter or YAML block. */\nexport const lineOfKey = (lines: string[], key: string, fromIndex = 0, toIndex = lines.length): number | undefined => {\n const pattern = new RegExp(`^${key.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\s*:`);\n\n for (let index = fromIndex; index < toIndex; index += 1) {\n if (pattern.test(lines[index])) {\n return index + 1;\n }\n }\n\n return undefined;\n};\n",
|
|
15
|
+
"/**\n * Which of the palette's colors each top-level node takes, and how edits\n * keep them. The root takes the palette's first color, and top-level nodes\n * take the others in turn, cycling. A node with a `paletteColor` takes that\n * one instead and gives up its turn, so the nodes after it keep theirs.\n * Edits write a `paletteColor` where a node's turn would change, so adding,\n * moving or removing a node never gives the others new colors.\n */\n\nimport type { OrbitNode } from './types.js';\n\n/** A node's own color, or its type's: what it shows instead of the palette's. */\nexport type OwnColor = (node: OrbitNode) => string | undefined;\n\n/** What an edit needs to keep top-level nodes' colors. */\nexport interface BranchColorRules {\n /** How many colors top-level nodes take turns with: the palette's, after the root's (see `branchPalette`). */\n count: number;\n\n /** A node's own color or its type's, which it shows instead of the palette's. Default: its `color`. */\n ownColor?: OwnColor;\n}\n\n/** Each top-level node's palette number before an edit, from `branchColorsBefore`. */\nexport type BranchColors = Map<OrbitNode, number>;\n\n/** The node an edit was about, for `keepBranchColors`. */\nexport interface EditedBranch {\n node: OrbitNode;\n\n /** Whether the node keeps the color it had (a move), rather than taking one no other top-level node has (a new node). */\n keepsColor: boolean;\n}\n\n/** The colors top-level nodes take turns with: every palette color after the root's, or the only one. */\nexport const branchPalette = (palette: readonly string[]): string[] => {\n return palette.length > 1 ? palette.slice(1) : [...palette];\n};\n\n/** Whether a value is a palette number: a whole number from 1. */\nexport const isPaletteNumber = (value: unknown): value is number => {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 1;\n};\n\n/** The color a palette number names among `colors` (from `branchPalette`), cycling. */\nexport const paletteColorOf = (colors: readonly string[], paletteNumber: number): string => {\n return colors[(paletteNumber - 1) % colors.length];\n};\n\n/** A palette number brought into 1 to `count`, cycling. */\nconst wrapped = (paletteNumber: number, count: number): number => {\n return ((paletteNumber - 1) % count) + 1;\n};\n\n/**\n * The palette number each of `branches` takes its color from: its\n * `paletteColor`, or else the next number in turn that none of them has as\n * its `paletteColor`. Nodes with a color or type of their own take a turn\n * too, so the nodes after them have the colors they'd have without one.\n */\nexport const branchNumbers = (branches: readonly OrbitNode[], count: number): Map<OrbitNode, number> => {\n const numbers = new Map<OrbitNode, number>();\n const taken = new Set<number>();\n\n for (const branch of branches) {\n if (isPaletteNumber(branch.paletteColor)) {\n taken.add(wrapped(branch.paletteColor, count));\n }\n }\n\n const all = Array.from({ length: count }, (_, index) => index + 1);\n const free = all.filter((paletteNumber) => !taken.has(paletteNumber));\n // With every color taken, turns go round all of them again.\n const turns = free.length > 0 ? free : all;\n let turn = 0;\n\n for (const branch of branches) {\n if (isPaletteNumber(branch.paletteColor)) {\n numbers.set(branch, wrapped(branch.paletteColor, count));\n } else {\n numbers.set(branch, turns[turn % turns.length]);\n turn += 1;\n }\n }\n\n return numbers;\n};\n\n/** Each top-level node's palette number, to keep through an edit with `keepBranchColors`. */\nexport const branchColorsBefore = (root: OrbitNode, rules: BranchColorRules): BranchColors => {\n return branchNumbers(root.children, rules.count);\n};\n\n/**\n * After an edit, gives every top-level node that was there before the color\n * it had, writing its palette number as its `paletteColor` where its turn\n * changed. The node the edit was about keeps its color when it moved within\n * the top level, takes one no other top-level node has when it's new there\n * (while there is one), and drops its `paletteColor` when it left the top\n * level, to take its new branch's color. Nodes showing a color or type of\n * their own are left as they are, and a `paletteColor` is written only where\n * a color would change otherwise.\n *\n * An edit that would write more numbers than the palette has colors writes\n * none: that happens only where the top level has more nodes than colors,\n * which repeat there anyway, and a big orbit's every node would get one.\n * Returns the nodes it changed.\n */\nexport const keepBranchColors = (root: OrbitNode, before: BranchColors, rules: BranchColorRules, edited?: EditedBranch): OrbitNode[] => {\n const ownColor = rules.ownColor ?? ((node: OrbitNode) => node.color);\n const branches = root.children;\n const subject = edited?.node;\n const showsPalette = (node: OrbitNode): boolean => ownColor(node) === undefined;\n // The `paletteColor` each pinned node had, to put back.\n const pinned = new Map<OrbitNode, number | undefined>();\n const changed: OrbitNode[] = [];\n\n const pin = (node: OrbitNode, paletteNumber: number): void => {\n if (!pinned.has(node)) {\n pinned.set(node, node.paletteColor);\n }\n\n node.paletteColor = paletteNumber;\n };\n\n // A top-level node whose color would change: one that was there before, isn't the edited one, and shows the palette's color.\n const moving = (numbers: Map<OrbitNode, number>): OrbitNode | undefined => {\n return branches.find((node) => node !== subject && before.has(node) && showsPalette(node) && numbers.get(node) !== before.get(node));\n };\n\n if (subject && before.has(subject) && !branches.includes(subject) && subject.paletteColor !== undefined) {\n delete subject.paletteColor;\n changed.push(subject);\n }\n\n if (subject && branches.includes(subject) && showsPalette(subject) && !isPaletteNumber(subject.paletteColor)) {\n const numbers = branchNumbers(branches, rules.count);\n const kept = edited?.keepsColor ? before.get(subject) : undefined;\n\n if (kept !== undefined) {\n if (numbers.get(subject) !== kept || moving(numbers)) {\n pin(subject, kept);\n }\n } else {\n const others = branches.filter((node) => node !== subject);\n const shared = others.some((node) => showsPalette(node) && numbers.get(node) === numbers.get(subject));\n\n if (shared || moving(numbers)) {\n // A number none of the others has, alone or in turn, so taking it moves none of them.\n const used = new Set(branchNumbers(others, rules.count).values());\n const unused = Array.from({ length: rules.count }, (_, index) => index + 1).find((paletteNumber) => !used.has(paletteNumber));\n\n if (unused !== undefined) {\n pin(subject, unused);\n }\n }\n }\n }\n\n // Each round keeps one more node's color, the first that would change, so the nodes after it often keep theirs without one.\n for (let round = 0; round < branches.length && pinned.size <= rules.count; round += 1) {\n const node = moving(branchNumbers(branches, rules.count));\n\n if (!node) {\n break;\n }\n\n pin(node, before.get(node) as number);\n }\n\n if (pinned.size > rules.count) {\n for (const [node, paletteNumber] of pinned) {\n if (paletteNumber === undefined) {\n delete node.paletteColor;\n } else {\n node.paletteColor = paletteNumber;\n }\n }\n\n return changed;\n }\n\n return [...changed, ...pinned.keys()];\n};\n",
|
|
16
|
+
"import type { DiagnosticCollector } from './diagnostics.js';\nimport type { OrbitNode } from './types.js';\nimport { isPaletteNumber } from './branch-colors.js';\nimport { didYouMean } from './suggest.js';\nimport { assignKey } from './yaml-mini.js';\n\ntype ImageMedia = NonNullable<OrbitNode['image']>;\ntype VideoMedia = NonNullable<OrbitNode['video']>;\ntype EmbedMedia = NonNullable<OrbitNode['embed']>;\n\nconst VIDEO_PROVIDERS = new Set(['youtube', 'vimeo', 'native']);\nconst TRUE_VALUES = new Set(['true', 'yes', 'on', '1']);\nconst FALSE_VALUES = new Set(['false', 'no', 'off', '0']);\n\n/** Fields of a picture, video or embed that Orbit doesn't read, kept to be written back. */\nconst MEDIA_EXTRAS = new WeakMap<object, Record<string, unknown>>();\n\n/**\n * The fields a picture, video or embed was written with that Orbit doesn't\n * read (a `width`, a provider it doesn't know): kept so saving writes them\n * back, for a newer version or another app that reads them.\n */\nexport const mediaExtras = (media: object | undefined): Record<string, unknown> | undefined => {\n return media ? MEDIA_EXTRAS.get(media) : undefined;\n};\n\n/** A copy of a picture, video or embed, with the fields Orbit doesn't read. */\nexport const copyMedia = <Media extends object>(media: Media): Media => {\n const copy = JSON.parse(JSON.stringify(media)) as Media;\n const extras = MEDIA_EXTRAS.get(media);\n\n if (extras) {\n MEDIA_EXTRAS.set(copy, JSON.parse(JSON.stringify(extras)) as Record<string, unknown>);\n }\n\n return copy;\n};\n\nconst keepExtras = (media: object, record: Record<string, unknown>, known: readonly string[]): void => {\n const extras = Object.fromEntries(Object.entries(record).filter(([key]) => !known.includes(key)));\n\n if (Object.keys(extras).length > 0) {\n MEDIA_EXTRAS.set(media, extras);\n }\n};\n\n/** The `src` of a media attribute: a URL string, or an object with a string `src`. */\nconst mediaRecord = (value: unknown): Record<string, unknown> | null => {\n if (typeof value === 'string' && value.trim() !== '') {\n return { src: value.trim() };\n }\n\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n const record = value as Record<string, unknown>;\n\n if (typeof record.src === 'string' && record.src.trim() !== '') {\n return record;\n }\n }\n\n return null;\n};\n\nconst optionalString = (value: unknown): string | undefined => {\n return typeof value === 'string' || typeof value === 'number' ? String(value) : undefined;\n};\n\nexport const readImage = (value: unknown): ImageMedia | undefined => {\n const record = mediaRecord(value);\n\n if (!record) {\n return undefined;\n }\n\n const image: ImageMedia = { src: String(record.src) };\n const alt = optionalString(record.alt);\n const caption = optionalString(record.caption);\n\n if (alt !== undefined) {\n image.alt = alt;\n }\n\n if (caption !== undefined) {\n image.caption = caption;\n }\n\n keepExtras(image, record, ['src', 'alt', 'caption']);\n return image;\n};\n\nexport const readVideo = (value: unknown): VideoMedia | undefined => {\n const record = mediaRecord(value);\n\n if (!record) {\n return undefined;\n }\n\n const video: VideoMedia = { src: String(record.src) };\n const knownProvider = typeof record.provider === 'string' && VIDEO_PROVIDERS.has(record.provider);\n\n if (knownProvider) {\n video.provider = record.provider as VideoMedia['provider'];\n }\n\n const thumbnail = optionalString(record.thumbnail);\n const caption = optionalString(record.caption);\n\n if (thumbnail !== undefined) {\n video.thumbnail = thumbnail;\n }\n\n if (caption !== undefined) {\n video.caption = caption;\n }\n\n // A provider Orbit doesn't know is played as a link, and kept as written.\n keepExtras(video, record, knownProvider ? ['src', 'provider', 'thumbnail', 'caption'] : ['src', 'thumbnail', 'caption']);\n return video;\n};\n\nexport const readEmbed = (value: unknown): EmbedMedia | undefined => {\n const record = mediaRecord(value);\n\n if (!record) {\n return undefined;\n }\n\n const embed: EmbedMedia = { src: String(record.src) };\n const caption = optionalString(record.caption);\n\n if (caption !== undefined) {\n embed.caption = caption;\n }\n\n keepExtras(embed, record, ['src', 'caption']);\n return embed;\n};\n\n/** The attributes every node takes, in `<!-- orbit … -->` blocks and in YAML. */\nexport const NODE_ATTRIBUTE_KEYS = [\n 'color', 'paletteColor', 'icon', 'status', 'priority', 'tags', 'collapsed', 'link',\n 'note', 'noteFormat', 'image', 'video', 'embed', 'caption', 'id', 'type',\n] as const;\n\n/** Words people (and agents) reach for instead of an attribute's name. */\nconst ATTRIBUTE_SYNONYMS: Record<string, string> = {\n colour: 'color',\n emoji: 'icon',\n state: 'status',\n tag: 'tags',\n labels: 'tags',\n url: 'link',\n href: 'link',\n img: 'image',\n picture: 'image',\n photo: 'image',\n youtube: 'video',\n iframe: 'embed',\n notes: 'note',\n description: 'note',\n details: 'note',\n collapse: 'collapsed',\n folded: 'collapsed',\n kind: 'type',\n};\n\n/** Keys a flavor accepts besides the node attributes, and the words that stand in for them. */\nexport interface AttributeVocabulary {\n keys: readonly string[];\n synonyms?: Readonly<Record<string, string>>;\n}\n\n/** A value Orbit reads as text: a string, or a number or true/false written without quotes. */\nconst scalar = (value: unknown): string | undefined => {\n return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' ? String(value) : undefined;\n};\n\n/**\n * A value Orbit can't read for one of its own attributes: a list where it\n * takes one word, a word where it takes a number. Reported, and kept in\n * `attrs` under its own name, so saving writes it back as it was written:\n * a newer version of Orbit, or another app, may read it.\n */\nconst keepUnread = (node: OrbitNode, key: string, value: unknown, diagnostics: DiagnosticCollector, line: number | undefined, expected: string): void => {\n diagnostics.recover('invalid-attributes', `${key} must be ${expected}; kept as written, but not used`, line);\n node.attrs ??= {};\n assignKey(node.attrs, key, value);\n};\n\n/**\n * Applies one typed attribute (from a `<!-- orbit ... -->` block or a YAML\n * node map) to a node. Unknown keys are kept in `node.attrs`, with a note\n * when they look like a misspelled attribute. Values Orbit can't read are\n * reported and kept in `node.attrs` too, so they're written back.\n */\nexport const assignNodeAttribute = (\n node: OrbitNode,\n key: string,\n value: unknown,\n diagnostics: DiagnosticCollector,\n line?: number,\n vocabulary: AttributeVocabulary = { keys: [] },\n): void => {\n switch (key) {\n case 'color':\n case 'icon':\n case 'status':\n case 'link': {\n const text = scalar(value);\n\n if (text === undefined) {\n keepUnread(node, key, value, diagnostics, line, 'one value');\n } else {\n node[key] = text;\n }\n\n return;\n }\n case 'paletteColor': {\n const paletteNumber = typeof value === 'number' || (typeof value === 'string' && value.trim() !== '') ? Number(value) : Number.NaN;\n\n if (isPaletteNumber(paletteNumber)) {\n node.paletteColor = paletteNumber;\n } else {\n keepUnread(node, key, value, diagnostics, line, 'a whole number from 1');\n }\n\n return;\n }\n case 'priority': {\n const priority = typeof value === 'number' || (typeof value === 'string' && value.trim() !== '') ? Number(value) : Number.NaN;\n\n if (Number.isFinite(priority)) {\n node.priority = priority;\n } else {\n keepUnread(node, key, value, diagnostics, line, 'a number');\n }\n\n return;\n }\n case 'tags': {\n // Joins any hashtags from the title. A single value may list several, as `palette` does: `tags: web, mobile`.\n const single = Array.isArray(value) ? undefined : scalar(value);\n const tags = Array.isArray(value)\n ? value.map(scalar)\n : single === undefined ? [undefined] : single.split(',').map((tag) => tag.trim()).filter((tag) => tag !== '');\n\n if (tags.some((tag) => tag === undefined)) {\n keepUnread(node, key, value, diagnostics, line, 'a word or a list of words');\n return;\n }\n\n node.tags = [...new Set([...(node.tags ?? []), ...(tags as string[])])];\n return;\n }\n case 'collapsed': {\n const word = scalar(value)?.toLowerCase();\n\n if (word !== undefined && (TRUE_VALUES.has(word) || FALSE_VALUES.has(word))) {\n node.collapsed = TRUE_VALUES.has(word);\n } else {\n keepUnread(node, key, value, diagnostics, line, 'true or false');\n }\n\n return;\n }\n case 'note': {\n const text = scalar(value);\n\n if (text === undefined) {\n keepUnread(node, key, value, diagnostics, line, 'text');\n return;\n }\n\n node.note = text;\n\n if (node.noteFormat === undefined) {\n node.noteFormat = 'markdown';\n }\n\n return;\n }\n case 'noteFormat':\n if (value === 'markdown' || value === 'plain') {\n node.noteFormat = value;\n } else {\n keepUnread(node, key, value, diagnostics, line, '\"markdown\" or \"plain\"');\n }\n\n return;\n case 'id': {\n const text = scalar(value);\n\n if (text === undefined || text.trim() === '') {\n keepUnread(node, key, value, diagnostics, line, 'one word');\n } else {\n node.id = text;\n }\n\n return;\n }\n case 'type': {\n const text = scalar(value);\n\n if (text === undefined) {\n keepUnread(node, key, value, diagnostics, line, 'one word');\n return;\n }\n\n // `task@2`: the version of the type the node was written for.\n const versioned = /^(.*\\S)@(\\d+)$/.exec(text.trim());\n node.type = versioned ? versioned[1] : text.trim();\n\n if (versioned) {\n node.typeVersion = Number(versioned[2]);\n }\n\n return;\n }\n case 'image': {\n const image = readImage(value);\n\n if (image) {\n node.image = image;\n } else {\n diagnostics.recover('media-missing-source', 'image needs a URL (or an object with a src)', line);\n }\n\n return;\n }\n case 'video': {\n const video = readVideo(value);\n\n if (video) {\n node.video = video;\n } else {\n diagnostics.recover('media-missing-source', 'video needs a URL (or an object with a src)', line);\n }\n\n return;\n }\n case 'embed': {\n const embed = readEmbed(value);\n\n if (embed) {\n node.embed = embed;\n } else {\n diagnostics.recover('media-missing-source', 'embed needs a URL (or an object with a src)', line);\n }\n\n return;\n }\n case 'caption': {\n const target = node.video ?? node.embed ?? node.image;\n\n if (target) {\n if (value !== null && value !== undefined) {\n target.caption = String(value);\n }\n } else {\n diagnostics.note('caption-without-media', 'caption kept, but not shown: the node has no image, video or embed', line);\n node.attrs ??= {};\n node.attrs.caption = value;\n }\n\n return;\n }\n default: {\n const hint = didYouMean(key, [...NODE_ATTRIBUTE_KEYS, ...vocabulary.keys], { ...ATTRIBUTE_SYNONYMS, ...vocabulary.synonyms });\n\n if (hint) {\n diagnostics.note('unknown-attribute', `Unknown attribute \"${key}\", kept as a custom attribute.${hint}`, line);\n }\n\n if (!node.attrs) {\n node.attrs = {};\n }\n\n assignKey(node.attrs, key, value);\n }\n }\n};\n",
|
|
17
|
+
"/**\n * Links between nodes. A node's link, or a link in its note, written as\n * `#id` points at another node of the same map, the way `#heading` links\n * point at a heading in a markdown page.\n */\n\nimport type { OrbitNode } from './types.js';\nimport type { DiagnosticCollector } from './diagnostics.js';\nimport { findNodeById, nodeSlug } from './utils.js';\nimport { suggest } from './suggest.js';\n\n/** Whether a link points at a node of the same map: `#research`. */\nexport const isNodeLink = (href: string | undefined): href is string => {\n return typeof href === 'string' && /^#\\S/.test(href);\n};\n\n/**\n * The node a `#id` link points at: the node with that id, or the one whose\n * id the fragment's text would get, so `#Research` and GitHub-style\n * `#-research` anchors find `research` too.\n */\nexport const findLinkedNode = (root: OrbitNode, href: string): OrbitNode | null => {\n return resolveNodeLink(href, (id) => findNodeById(root, id));\n};\n\n/** `findLinkedNode` with the map's nodes indexed by `indexNodes`, for checking many links at once. */\nexport const findIndexedLinkedNode = (nodes: Map<string, OrbitNode>, href: string): OrbitNode | null => {\n return resolveNodeLink(href, (id) => nodes.get(id) ?? null);\n};\n\n/** The map's nodes by id; when ids repeat, the first in the tree, as `findNodeById` finds it. */\nexport const indexNodes = (root: OrbitNode): Map<string, OrbitNode> => {\n const nodes = new Map<string, OrbitNode>();\n\n const visit = (node: OrbitNode): void => {\n if (!nodes.has(node.id)) {\n nodes.set(node.id, node);\n }\n\n for (const child of node.children) {\n visit(child);\n }\n };\n\n visit(root);\n return nodes;\n};\n\nconst resolveNodeLink = (href: string, lookup: (id: string) => OrbitNode | null): OrbitNode | null => {\n if (!isNodeLink(href)) {\n return null;\n }\n\n let fragment = href.slice(1);\n\n try {\n fragment = decodeURIComponent(fragment);\n } catch {\n // A malformed escape: look the fragment up as written.\n }\n\n return lookup(fragment) ?? lookup(nodeSlug(fragment).replace(/^-+|-+$/g, ''));\n};\n\nconst NOTE_NODE_LINK = /\\]\\((#[^)\\s]+)\\)/g;\n\n/** The `#id` links a node has: its link, then the ones in its note. */\nexport const nodeLinksOf = (node: OrbitNode): string[] => {\n // A plain note never renders its `[x](#y)` as a link, so it isn't one.\n const links = node.noteFormat === 'plain' ? [] : [...(node.note ?? '').matchAll(NOTE_NODE_LINK)].map((match) => match[1]);\n\n if (isNodeLink(node.link)) {\n links.unshift(node.link);\n }\n\n return links;\n};\n\n/** Where a parser saw a node's link (`inNote` false) or a link in its note: the line it's on, when it knows. */\nexport type LinkLine = (node: OrbitNode, href: string, inNote: boolean) => number | undefined;\n\n/** Reports each `#id` link, in a node's link or note, that points at no node of the map, on its own line where `lineOf` knows it. */\nexport const checkNodeLinks = (root: OrbitNode, diagnostics: DiagnosticCollector, lineOf?: LinkLine): void => {\n const ids: string[] = [];\n collectIds(root, ids);\n // Large maps link between their nodes hundreds of times: look ids up, don't search the tree.\n const nodes = indexNodes(root);\n\n const visit = (node: OrbitNode): void => {\n nodeLinksOf(node).forEach((href, index) => {\n if (!findIndexedLinkedNode(nodes, href)) {\n const suggestion = suggest(href.slice(1), ids);\n const hint = suggestion === undefined ? ' Ids come from the nodes\\' text: \"Q3 plan\" is #q3-plan.' : ` Did you mean #${suggestion}?`;\n const inNote = !(index === 0 && isNodeLink(node.link));\n diagnostics.recover(\n 'unknown-link-target',\n `\"${node.text}\" links to ${href}, but no node has that id.${hint}`,\n lineOf?.(node, href, inNote) ?? node.source?.line,\n );\n }\n });\n\n for (const child of node.children) {\n visit(child);\n }\n };\n\n visit(root);\n};\n\nconst collectIds = (node: OrbitNode, ids: string[]): void => {\n ids.push(node.id);\n\n for (const child of node.children) {\n collectIds(child, ids);\n }\n};\n",
|
|
18
|
+
"/**\n * Where a markdown document came from: its text, and which lines each node\n * owns. Saving uses it to write back only what an edit changed, so a map\n * written by hand (or by another app) keeps its own formatting, and\n * everything Orbit doesn't read, through edits.\n */\n\nimport type { OrbitDocument, OrbitDocumentOptions, OrbitNode } from './types.js';\nimport { copyMedia } from './node-attributes.js';\n\n/** What a line is to the node that owns it. */\nexport type LineRole =\n /** The frontmatter block, and blank lines before it. */\n | 'frontmatter'\n /** A heading or list item line (a setext heading's underline too), or the paragraph that names a generated root. */\n | 'title'\n /** An `<!-- orbit … -->` block. */\n | 'attributes'\n /** A picture or video line, and the comment after it that sets its caption or content type. */\n | 'media'\n /** Text of the node's note: paragraphs, quotes, code, or headings under a list item. */\n | 'note'\n /**\n * The end of the document, which stays at its end: link and footnote\n * definitions there (the root's note), and the blank lines around them.\n */\n | 'end'\n /** Text Orbit keeps without reading: other HTML comments, rules, attribute blocks it couldn't read. */\n | 'foreign'\n | 'blank';\n\n/** How a node was written. */\nexport type NodeShape =\n | { kind: 'heading'; level: number; setext: boolean }\n /** `indent` is the marker's column, `content` the column its text starts at. */\n | { kind: 'item'; indent: number; marker: string; content: number }\n /** A root Orbit made up: named after the title or a lead paragraph (`lead`), or \"Untitled map\". */\n | { kind: 'generated'; lead: boolean };\n\n/** A node's own fields, as they were read: to tell which ones an edit changed. */\nexport type NodeFields = Pick<OrbitNode, 'id' | 'text' | 'icon' | 'link' | 'status' | 'tags' | 'color' | 'paletteColor' | 'priority' | 'collapsed' | 'type' | 'typeVersion' | 'note' | 'noteFormat' | 'image' | 'video' | 'embed' | 'attrs'>;\n\nexport interface NodeRecord {\n shape: NodeShape;\n\n /** The title line, 0-based; null for a generated root without a lead paragraph. */\n titleLine: number | null;\n\n /** The lines the node and everything under it span, 0-based, end exclusive. */\n start: number;\n\n end: number;\n\n /** Whether every line in the span is the node's or under it, so the span can be written back as one piece. */\n contiguous: boolean;\n\n /** Its children, in their order in the source. */\n children: OrbitNode[];\n\n fields: NodeFields;\n\n /** Whether the node's id was written as an attribute (or would have to be). */\n explicitId: boolean;\n}\n\nexport interface DocumentSource {\n /** The lines as the parser read them: line endings as `\\n`, without a byte-order mark or shared indentation. */\n lines: string[];\n\n /** For each line, the node it belongs to (null for the frontmatter) and what it is there. */\n owners: (OrbitNode | null)[];\n\n roles: LineRole[];\n records: WeakMap<OrbitNode, NodeRecord>;\n root: OrbitNode;\n\n /** The options as read, to tell which ones changed. */\n options: OrbitDocumentOptions;\n\n /** The frontmatter keys Orbit doesn't read, as read, to tell which ones changed. */\n extra: Record<string, unknown>;\n\n /** The frontmatter's fences, 0-based, when the document has frontmatter. */\n frontmatter: { open: number; close: number } | null;\n\n /** How the file was written, so it's written back the same way. */\n encoding: SourceEncoding;\n}\n\nexport interface SourceEncoding {\n lineEnding: '\\n' | '\\r\\n';\n byteOrderMark: boolean;\n\n /** Indentation every line shared (a map indented inside HTML or a template), put back on save. */\n indentation: string;\n\n /** Lines around the map that the parser unwrapped: a ```` ```orbit ```` fence. */\n before: string[];\n\n after: string[];\n}\n\n/** How a text is written: its line endings and byte-order mark. Indentation and wrapping are set where they're found. */\nexport const encodingOf = (text: string): SourceEncoding => {\n const crlf = (text.match(/\\r\\n/g) ?? []).length;\n const lf = (text.match(/\\n/g) ?? []).length;\n return {\n lineEnding: crlf > 0 && crlf * 2 >= lf ? '\\r\\n' : '\\n',\n byteOrderMark: text.startsWith('\\uFEFF'),\n indentation: '',\n before: [],\n after: [],\n };\n};\n\n/** Sources by the root of the tree read from them: copies of a document (`{ ...document, options }`) share it. */\nconst SOURCES = new WeakMap<OrbitNode, DocumentSource>();\n\n/**\n * The source a document's tree was read from, when it was read from\n * markdown. Kept by the tree's root, off the document itself, so documents\n * stay plain data that JSON leaves out, and a copy of a document with other\n * options (or a map holding the tree) still saves from its source.\n */\nexport const documentSource = (document: Pick<OrbitDocument, 'root'>): DocumentSource | undefined => {\n const source = SOURCES.get(document.root);\n return source?.root === document.root ? source : undefined;\n};\n\n/** Remembers where a document's tree came from (see `documentSource`). */\nexport const setDocumentSource = (document: Pick<OrbitDocument, 'root'>, source: DocumentSource): void => {\n SOURCES.set(document.root, source);\n};\n\n/** A copy of a node's own fields, deep enough that edits to the node don't reach it. */\nexport const nodeFields = (node: OrbitNode): NodeFields => {\n const copy = (value: unknown): unknown => (value === undefined ? undefined : JSON.parse(JSON.stringify(value)));\n return {\n id: node.id,\n text: node.text,\n icon: node.icon,\n link: node.link,\n status: node.status,\n tags: copy(node.tags) as string[] | undefined,\n color: node.color,\n paletteColor: node.paletteColor,\n priority: node.priority,\n collapsed: node.collapsed,\n type: node.type,\n typeVersion: node.typeVersion,\n note: node.note,\n noteFormat: node.noteFormat,\n image: node.image && copyMedia(node.image),\n video: node.video && copyMedia(node.video),\n embed: node.embed && copyMedia(node.embed),\n attrs: copy(node.attrs) as NodeFields['attrs'],\n };\n};\n\n/**\n * Collects, while a document is parsed, which node owns each line and what\n * the line is, then works out each node's span.\n */\nexport class SourceRecorder {\n readonly owners: (OrbitNode | null)[];\n readonly roles: (LineRole | undefined)[];\n private readonly lines: string[];\n private readonly shapes = new Map<OrbitNode, { shape: NodeShape; titleLine: number | null }>();\n\n constructor(lines: string[]) {\n this.lines = lines;\n this.owners = new Array(lines.length).fill(null);\n this.roles = new Array(lines.length).fill(undefined);\n }\n\n /** Lines `first` to `last` (1-based, inclusive) belong to `node` as `role`. */\n mark(first: number, last: number, node: OrbitNode | null, role: LineRole): void {\n for (let line = Math.max(1, first); line <= last && line <= this.lines.length; line += 1) {\n this.owners[line - 1] = node;\n this.roles[line - 1] = role;\n }\n }\n\n /** A line's text (1-based), as read. */\n line(line: number): string {\n return this.lines[line - 1] ?? '';\n }\n\n /** How `node` was written, and its title line (1-based), if it has one. */\n shape(node: OrbitNode, shape: NodeShape, titleLine: number | null): void {\n this.shapes.set(node, { shape, titleLine: titleLine === null ? null : titleLine - 1 });\n }\n\n /**\n * The finished source. Blank lines nothing claimed go with the text they\n * lead up to (an idea moved takes the blank line before it, and the\n * paragraph after a list keeps the blank line that keeps it out of the\n * list); at the end of the document, with the line above. Every line has\n * an owner, so spans cover the whole document.\n */\n finish(\n root: OrbitNode,\n options: OrbitDocumentOptions,\n extra: Record<string, unknown>,\n frontmatter: DocumentSource['frontmatter'],\n explicitIds: ReadonlySet<OrbitNode>,\n ): DocumentSource {\n const owners = [...this.owners];\n const claimed = [...this.roles];\n let next: OrbitNode | null = null;\n let nextRole: LineRole | undefined;\n\n for (let index = this.lines.length - 1; index >= 0; index -= 1) {\n const role = claimed[index];\n\n if (role !== undefined) {\n if (role !== 'frontmatter') {\n next = owners[index];\n nextRole = role;\n }\n } else if (next && this.lines[index].trim() === '') {\n owners[index] = next;\n // The blank line before definitions at the end stays with them.\n claimed[index] = nextRole === 'end' ? 'end' : 'blank';\n }\n }\n\n const roles: LineRole[] = [];\n let owner: OrbitNode | null = null;\n let lastClaimed = -1;\n\n claimed.forEach((role, index) => {\n if (role !== undefined && role !== 'frontmatter') {\n lastClaimed = index;\n }\n });\n\n for (let index = 0; index < this.lines.length; index += 1) {\n const role = claimed[index];\n\n if (role !== undefined) {\n roles.push(role);\n\n if (role !== 'frontmatter') {\n owner = owners[index];\n }\n\n continue;\n }\n\n const blank = this.lines[index].trim() === '';\n\n if (index > lastClaimed) {\n // After every node: the end of the document, which stays at the end.\n owners[index] = root;\n roles.push(blank ? 'end' : 'foreign');\n } else {\n owners[index] = owner ?? root;\n roles.push(blank ? 'blank' : 'foreign');\n }\n }\n\n const records = new WeakMap<OrbitNode, NodeRecord>();\n const firstLines = new Map<OrbitNode, number>();\n const lastLines = new Map<OrbitNode, number>();\n\n owners.forEach((node, index) => {\n if (node) {\n if (!firstLines.has(node)) {\n firstLines.set(node, index);\n }\n\n lastLines.set(node, index);\n }\n });\n\n const spanOf = (node: OrbitNode): { start: number; end: number } => {\n let start = firstLines.get(node) ?? Number.POSITIVE_INFINITY;\n let end = (lastLines.get(node) ?? -1) + 1;\n\n for (const child of node.children) {\n const span = spanOf(child);\n start = Math.min(start, span.start);\n end = Math.max(end, span.end);\n }\n\n const known = this.shapes.get(node);\n const shape: NodeShape = known?.shape ?? { kind: 'generated', lead: false };\n\n if (!Number.isFinite(start)) {\n start = end = 0;\n }\n\n records.set(node, {\n shape,\n titleLine: known?.titleLine ?? null,\n start,\n end,\n contiguous: true,\n children: [...node.children],\n fields: nodeFields(node),\n explicitId: explicitIds.has(node),\n });\n return { start, end };\n };\n\n spanOf(root);\n // A span with another node's line inside it (definitions written halfway through an idea's text, say).\n // A depth-first walk's enter/exit counters bracket a node's descendants, so the ancestor test is O(1).\n const brackets = new Map<OrbitNode, [number, number]>();\n let order = 0;\n\n const bracket = (node: OrbitNode): void => {\n const enter = order;\n order += 1;\n\n for (const child of node.children) {\n bracket(child);\n }\n\n brackets.set(node, [enter, order]);\n };\n\n bracket(root);\n\n const insideOf = (node: OrbitNode, ancestor: OrbitNode): boolean => {\n const [enter, exit] = brackets.get(ancestor)!;\n const bracketed = brackets.get(node)!;\n return bracketed[0] >= enter && bracketed[0] < exit;\n };\n\n const check = (node: OrbitNode): void => {\n const record = records.get(node)!;\n\n for (let index = record.start; index < record.end; index += 1) {\n const owner = owners[index];\n\n if (owner && !insideOf(owner, node)) {\n record.contiguous = false;\n break;\n }\n }\n\n node.children.forEach(check);\n };\n\n root.children.forEach(check);\n // The root spans the whole body, blank lines at the end included.\n const rootRecord = records.get(root)!;\n rootRecord.start = Math.min(rootRecord.start, frontmatter ? frontmatter.close + 1 : 0);\n rootRecord.end = this.lines.length;\n return {\n lines: this.lines,\n owners,\n roles,\n records,\n root,\n options: JSON.parse(JSON.stringify(options)) as OrbitDocumentOptions,\n extra: JSON.parse(JSON.stringify(extra)) as Record<string, unknown>,\n frontmatter,\n encoding: { lineEnding: '\\n', byteOrderMark: false, indentation: '', before: [], after: [] },\n };\n }\n}\n",
|
|
19
|
+
"import type { OrbitDocumentOptions, OrbitNode, ParsedOrbitDocument } from './types.js';\nimport { parseYaml, YamlMiniError } from './yaml-mini.js';\nimport { ensureUniqueNodeIds, nodeSlug, setParent } from './utils.js';\nimport { detectVideoProvider } from './media.js';\nimport { DiagnosticCollector } from './diagnostics.js';\nimport { findFrontmatter, firstContentLineIndex, lineOfKey, normalizeSource, sharedIndentation } from './source.js';\nimport { assignNodeAttribute, NODE_ATTRIBUTE_KEYS } from './node-attributes.js';\nimport { applyDocumentOption, DOCUMENT_OPTION_KEYS, unknownOptionMessage } from './document-options.js';\nimport { checkNodeLinks, type LinkLine } from './node-links.js';\nimport { encodingOf, setDocumentSource, SourceRecorder, type LineRole, type NodeShape } from './document-source.js';\nimport { nodesWithExplicitIds } from './utils.js';\nimport { upgradeFormat } from './format-upgrades.js';\n\nexport { OrbitParseError } from './diagnostics.js';\n\nexport { SUPPORTED_SCHEMA_VERSION } from './format-upgrades.js';\n\nexport interface ParseOptions {\n /**\n * Throw an `OrbitParseError` on the first problem instead of recording a\n * diagnostic and carrying on. Off by default; `orbit validate` turns it on.\n */\n strict?: boolean;\n\n /**\n * The name of the root Orbit makes up for a document with no single top\n * heading and no title, in the reader's language. Default \"Untitled map\".\n * Its id is `untitled-map` whatever its name.\n */\n untitled?: string;\n}\n\n/** Text of the generated root when a document has no single top-level heading or title. */\nexport const UNTITLED_ROOT_TEXT = 'Untitled map';\n/** The generated root's id, whatever the `untitled` option names it. */\nexport const UNTITLED_ROOT_ID = 'untitled-map';\n\n// Titles: status checkbox, emoji icon, hashtags, links and inline markdown\n\n// A single emoji: a flag (pair of regional indicators), a keycap, or a\n// pictograph with an optional variation selector and skin-tone modifier.\n// ©, ® and ™ are pictographs too but read as text in titles, so they never\n// become icons.\nconst EMOJI_UNIT = String.raw`(?:\\p{Regional_Indicator}{2}|[0-9#*]️?⃣|(?![©®™])\\p{Extended_Pictographic}️?\\p{Emoji_Modifier}?)`;\nconst EMOJI = String.raw`${EMOJI_UNIT}(?:${EMOJI_UNIT})*`;\nconst LEADING_EMOJI = new RegExp(String.raw`^((?:${EMOJI})+)\\s+(.*)$`, 'u');\nconst ONLY_EMOJI = new RegExp(String.raw`^(?:${EMOJI})+$`, 'u');\n\n/** Whether an icon reads back from the start of a title (emoji do; other symbols need an `icon:` attribute). */\nexport const isTitleIcon = (icon: string): boolean => {\n return ONLY_EMOJI.test(icon);\n};\n\n/** 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. */\nexport const leadingEmoji = (title: string): { icon: string; text: string } | null => {\n const match = LEADING_EMOJI.exec(title);\n return match ? { icon: match[1], text: match[2].trim() } : null;\n};\n\nconst TASK_MARKER = /^\\[( |x|X|\\/)\\]\\s+(.*)$/;\nconst TASK_STATUSES: Record<string, string> = { ' ': 'todo', x: 'done', X: 'done', '/': 'active' };\n// A backslash before ASCII punctuation keeps it literal: `\\*`, `\\#`, `\\[`.\nconst ESCAPE = /\\\\([!-/:-@[-`{-~])/g;\n// While a title is read, escaped characters and code spans wait in\n// private-use characters, so nothing inside them is read as markup.\nconst HIDDEN_BASE = 0x100000;\nconst HIDDEN = /[\\u{100000}-\\u{10fffd}]/gu;\n/** The last code point the reveal pattern reads: how many tokens one line can hide. */\nconst HIDDEN_LIMIT = 0x10fffd - HIDDEN_BASE + 1;\n// A hashtag at the end, after a space: `#frontend`, `#sprint-3`, `#team/web`.\n// It needs a letter, so `#42` stays text; `C#` has no space before it.\nconst TRAILING_TAG = /\\s+#([\\p{L}\\p{N}_][\\p{L}\\p{N}_/-]*)$/u;\nconst CODE_SPAN = /(`+)(?!`)([\\s\\S]*?[^`])\\1(?!`)/g;\n// The destination allows one level of balanced parentheses, as in CommonMark.\nconst TITLE_LINK = /(!?)\\[([^\\]]*)\\]\\(\\s*((?:[^\\s()]|\\([^\\s()]*\\))+)(?:\\s+\"[^\"]*\")?\\s*\\)/g;\nconst EMPHASIS = [\n /~~(?=\\S)([\\s\\S]*?\\S)~~/g,\n /\\*\\*(?=\\S)([\\s\\S]*?\\S)\\*\\*/g,\n /(?<![\\p{L}\\p{N}_])__(?=\\S)([\\s\\S]*?\\S)__(?![\\p{L}\\p{N}_])/gu,\n /\\*(?=\\S)([\\s\\S]*?\\S)\\*/g,\n /(?<![\\p{L}\\p{N}_])_(?=\\S)([\\s\\S]*?\\S)_(?![\\p{L}\\p{N}_])/gu,\n];\n\nexport interface TitleParts {\n text: string;\n icon?: string;\n link?: string;\n status?: string;\n tags?: string[];\n}\n\n/**\n * Reads a heading's or list item's text. `[ ]`, `[x]` and `[/]` set the\n * status, an emoji first is the icon, hashtags at the end are tags, a link\n * gives the node its link, and bold, italics, code and strikethrough show\n * as plain text. A backslash keeps any of those characters literal.\n */\nexport const parseTitle = (raw: string): TitleParts => {\n const hidden: string[] = [];\n\n const hide = (value: string): string => {\n if (hidden.length >= HIDDEN_LIMIT) {\n // Out of private-use codes (a line with ~64k escapes): the text stays literal.\n return value;\n }\n\n return String.fromCodePoint(HIDDEN_BASE + hidden.push(value) - 1);\n };\n\n let text = raw.trim().replace(ESCAPE, (_match, character: string) => hide(character));\n text = text.replace(HIDDEN_COMMENT, (_match, before: string, _body: string, after: string) => (before || after ? ' ' : '')).trim();\n const parts: Omit<TitleParts, 'text'> = {};\n\n const task = TASK_MARKER.exec(text);\n\n if (task) {\n parts.status = TASK_STATUSES[task[1]];\n text = task[2].trim();\n }\n\n const emoji = LEADING_EMOJI.exec(text);\n\n if (emoji) {\n parts.icon = emoji[1];\n text = emoji[2].trim();\n }\n\n const tags: string[] = [];\n\n for (let match = TRAILING_TAG.exec(text); match && /\\p{L}/u.test(match[1]); match = TRAILING_TAG.exec(text)) {\n tags.unshift(match[1]);\n text = text.slice(0, match.index);\n }\n\n if (tags.length > 0) {\n parts.tags = tags;\n }\n\n text = text.replace(CODE_SPAN, (_match, _ticks: string, code: string) => hide(code.replace(/^ ([\\s\\S]*) $/, '$1')));\n\n text = text.replace(TITLE_LINK, (match, image: string, label: string, url: string) => {\n if (image) {\n return match;\n }\n\n parts.link ??= reveal(url, hidden);\n return label;\n });\n\n // An emoji at the start of a link's text: `[🚀 Launch](…)`.\n const linkedEmoji = parts.icon ? null : LEADING_EMOJI.exec(text);\n\n if (linkedEmoji) {\n parts.icon = linkedEmoji[1];\n text = linkedEmoji[2].trim();\n }\n\n for (let pass = 0; pass < 3; pass += 1) {\n const before = text;\n\n for (const pattern of EMPHASIS) {\n text = text.replace(pattern, '$1');\n }\n\n if (text === before) {\n break;\n }\n }\n\n return { text: reveal(text, hidden).trim(), ...parts };\n};\n\nconst reveal = (text: string, hidden: string[]): string => {\n let revealed = text;\n\n // Code spans can hold escaped characters, so reveal until nothing is hidden.\n for (let pass = 0; pass < 4; pass += 1) {\n const next = revealed.replace(HIDDEN, (character) => hidden[character.codePointAt(0)! - HIDDEN_BASE] ?? character);\n\n if (next === revealed) {\n break;\n }\n\n revealed = next;\n }\n\n return revealed;\n};\n\n// Blocks\n\ninterface SourceLine { text: string; line: number; /** Leading spaces (after tab expansion), computed once per line. */ indent: number; }\n\n// Every block knows its first and last line (1-based), so saving can keep\n// the lines of whatever an edit didn't touch.\ninterface HeaderBlock { kind: 'header'; level: number; text: string; line: number; last: number; setext: boolean; }\ninterface ListBlock { kind: 'list'; items: ListItem[]; line: number; last: number; }\ninterface ParagraphBlock { kind: 'paragraph'; text: string; line: number; last: number; }\n/** A blockquote: a note written as one, never read again as structure. */\ninterface NoteBlock { kind: 'note'; text: string; line: number; last: number; }\ninterface BlankBlock { kind: 'blank'; line: number; last: number; }\n/** Text Orbit keeps without reading: an HTML comment that isn't Orbit's (`comment` is its text), or a rule. */\ninterface ForeignBlock { kind: 'foreign'; line: number; last: number; comment?: string; }\ntype MediaKind = 'image' | 'wrapped' | 'link';\n\ninterface MediaBlock {\n kind: 'media';\n mediaKind: MediaKind;\n url: string;\n alt?: string;\n thumb?: string;\n text?: string;\n line: number;\n last: number;\n}\n\n/** An `<!-- orbit … -->` comment. `inline` when it ends a heading's or list item's line. */\ninterface CommentBlock {\n kind: 'comment';\n body: string;\n line: number;\n last: number;\n\n /** Line of the body's first line, when it starts below the comment's opening. */\n bodyLine?: number;\n\n inline?: boolean;\n}\n\ntype Block = HeaderBlock | ListBlock | ParagraphBlock | NoteBlock | BlankBlock | ForeignBlock | MediaBlock | CommentBlock;\n\ninterface ListItem {\n text: string;\n line: number;\n inlineAttrs?: string;\n\n /** Everything written under the item: its note, media, attributes and nested items. */\n content: Block[];\n}\n\ntype ContentType = 'image' | 'video' | 'embed' | 'none';\nconst CONTENT_TYPES = new Set<ContentType>(['image', 'video', 'embed', 'none']);\n\nconst HEADER = /^ {0,3}(#{1,6})\\s+(.*\\S)\\s*$/;\nconst HEADER_START = /^ {0,3}#{1,6}\\s+/;\nconst SETEXT_UNDERLINE = /^ {0,3}(?:=+|-+)\\s*$/;\nconst THEMATIC_BREAK = /^ {0,3}([-*_])(?:\\s*\\1){2,}\\s*$/;\nconst LIST_ITEM = /^(\\s*)(?:[-*+]|\\d{1,9}[.)])\\s+(.*\\S)\\s*$/;\n// A list may interrupt a paragraph only with a bullet or an ordered list\n// starting at 1, as in CommonMark, so \"2024. A good year\" stays prose.\nconst LIST_INTERRUPTS_PARAGRAPH = /^\\s*(?:[-*+]|1[.)])\\s+\\S/;\nconst QUOTE = /^\\s*>/;\nconst FENCE = /^ {0,3}(```|~~~)/;\n// `orbit` in any case, with or without a colon after it: <!-- Orbit: status: done -->.\nconst INLINE_ATTRIBUTES = /^(.*\\S)\\s+<!--\\s*orbit:?\\s+([\\s\\S]*?)\\s*-->\\s*$/i;\n/** A heading or list item with no text, only attributes: an idea without a name yet, say one holding a picture. */\nconst ONLY_ATTRIBUTES = /^()<!--\\s*orbit:?\\s+([\\s\\S]*?)\\s*-->\\s*$/i;\n/** Any other HTML comment, hidden as markdown hides it; a backslash before `<` keeps it as text. */\nconst HIDDEN_COMMENT = /(\\s*)(?<!\\\\)<!--([\\s\\S]*?)-->(\\s*)/g;\nconst WRAPPED_LINE = /^\\[!\\[([^\\]]*)\\]\\(([^)]+)\\)\\]\\(([^)]+)\\)$/;\nconst IMAGE_LINE = /^!\\[([^\\]]*)\\]\\(([^)]+)\\)$/;\nconst LINK_LINE = /^\\[([^\\]]*)\\]\\(([^)]+)\\)$/;\n\n// Public API\n\nexport const parseOrbitMarkdown = (input: string, options: ParseOptions = {}): ParsedOrbitDocument => {\n const diagnostics = new DiagnosticCollector(options.strict ?? false);\n const rawLines = normalizeSource(input).split('\\n');\n const { options: docOptions, extra, bodyStartIndex } = readFrontmatter(rawLines, diagnostics);\n\n const recorder = new SourceRecorder(rawLines);\n recorder.mark(1, bodyStartIndex, null, 'frontmatter');\n\n const lines = rawLines.slice(bodyStartIndex).map((raw, index) => {\n const text = expandLeadingTabs(raw);\n return { text, line: bodyStartIndex + index + 1, indent: indentation(text) };\n });\n\n const root = buildTree(tokenize(lines, { headings: true }), docOptions, diagnostics, firstContentLineIndex(rawLines) === -1, recorder, options.untitled);\n fixLevels(root, 0);\n ensureUniqueNodeIds(root);\n checkNodeLinks(root, diagnostics, noteLinkLines(root, rawLines));\n const document: ParsedOrbitDocument = { root, options: docOptions, warnings: diagnostics.warnings, diagnostics: diagnostics.diagnostics };\n\n if (Object.keys(extra).length > 0) {\n document.extra = extra;\n }\n\n const frontmatter = findFrontmatter(rawLines);\n const fences = frontmatter && bodyStartIndex > 0 ? { open: frontmatter.openIndex, close: frontmatter.closeIndex } : null;\n const source = recorder.finish(root, docOptions, extra, fences, nodesWithExplicitIds(root));\n source.encoding = { ...encodingOf(input), indentation: sharedIndentation(input.replace(/^\\uFEFF/, '').replace(/\\r\\n?/g, '\\n')) };\n setDocumentSource(document, source);\n // Upgraded after the source is noted: saving then writes the upgraded nodes, and only them.\n upgradeFormat(document, diagnostics, lineOfKey(rawLines, 'schemaVersion'));\n document.warnings = diagnostics.warnings;\n return document;\n};\n\n// Frontmatter\n\nconst readFrontmatter = (\n lines: string[],\n diagnostics: DiagnosticCollector,\n): { options: OrbitDocumentOptions; extra: Record<string, unknown>; bodyStartIndex: number } => {\n const extra: Record<string, unknown> = {};\n const frontmatter = findFrontmatter(lines);\n\n if (!frontmatter) {\n warnUnclosedFrontmatter(lines, diagnostics);\n return { options: {}, extra, bodyStartIndex: 0 };\n }\n\n if (isMarkdownBetweenRules(lines, frontmatter.openIndex, frontmatter.closeIndex)) {\n return { options: {}, extra, bodyStartIndex: 0 };\n }\n\n const bodyStartIndex = frontmatter.closeIndex + 1;\n let parsed: unknown;\n\n try {\n parsed = parseYaml(frontmatter.yaml) ?? {};\n } catch (error) {\n // The frontmatter's first line is the one after the opening fence.\n const problem = error instanceof YamlMiniError ? error : null;\n const line = problem ? frontmatter.openIndex + 1 + problem.line : frontmatter.openIndex + 1;\n diagnostics.recover('invalid-frontmatter', `Invalid frontmatter YAML: ${problem?.reason ?? (error as Error).message}`, line, 'error');\n return { options: {}, extra, bodyStartIndex };\n }\n\n if (typeof parsed !== 'object' || Array.isArray(parsed)) {\n diagnostics.recover('invalid-frontmatter', 'Frontmatter must contain \"key: value\" pairs.', frontmatter.openIndex + 1, 'error');\n return { options: {}, extra, bodyStartIndex };\n }\n\n const options: OrbitDocumentOptions = {};\n\n for (const [key, value] of Object.entries(parsed as Record<string, unknown>)) {\n const line = lineOfKey(lines, key, frontmatter.openIndex, frontmatter.closeIndex) ?? frontmatter.openIndex + 1;\n\n if (!DOCUMENT_OPTION_KEYS.has(key)) {\n diagnostics.recover('unknown-frontmatter-key', unknownOptionMessage(key, 'frontmatter'), line);\n extra[key] = value;\n continue;\n }\n\n applyDocumentOption(options, key, value, (message) => diagnostics.recover('invalid-option-value', message, line));\n }\n\n return { options, extra, bodyStartIndex };\n};\n\n/** A heading or a list item: the lines that give a map its shape. */\nconst isStructureLine = (line: string): boolean => {\n return /^ {0,3}#{1,6}\\s+\\S/.test(line) || /^\\s*(?:[-*+]|\\d+[.)])\\s+\\S/.test(line);\n};\n\n/**\n * A map written between two `---` rules, which only looks like frontmatter:\n * the block holds headings or items and no `key: value` line, and nothing\n * after it has a shape of its own. Read as frontmatter, it would be an empty map.\n */\nconst isMarkdownBetweenRules = (lines: string[], openIndex: number, closeIndex: number): boolean => {\n const block = lines.slice(openIndex + 1, closeIndex);\n return block.some(isStructureLine)\n && !block.some((line) => /^[A-Za-z_][\\w-]*\\s*:/.test(line))\n && !lines.slice(closeIndex + 1).some(isStructureLine);\n};\n\n/** Frontmatter that opens with `---` and never closes is read as markdown: say so. */\nconst warnUnclosedFrontmatter = (lines: string[], diagnostics: DiagnosticCollector): void => {\n const openIndex = firstContentLineIndex(lines);\n\n if (openIndex === -1 || lines[openIndex].trim() !== '---') {\n return;\n }\n\n const next = lines.slice(openIndex + 1).find((line) => line.trim() !== '');\n\n if (next !== undefined && /^[A-Za-z_][\\w-]*\\s*:/.test(next)) {\n diagnostics.recover('invalid-frontmatter', 'The frontmatter has no closing \"---\" line, so it reads as part of the map. Close it with \"---\".', openIndex + 1);\n }\n};\n\n// Tokenizer\n\ninterface TokenizeOptions {\n /** Headings make nodes at the top level; under a list item they are note text. */\n headings: boolean;\n}\n\nconst tokenize = (lines: SourceLine[], options: TokenizeOptions): Block[] => {\n const blocks: Block[] = [];\n let index = 0;\n\n while (index < lines.length) {\n const { text: raw, line } = lines[index];\n\n if (raw.trim() === '') {\n blocks.push({ kind: 'blank', line, last: line });\n index += 1;\n continue;\n }\n\n const header = options.headings ? HEADER.exec(raw) : null;\n\n if (header) {\n // Drop an optional closing sequence: `## Title ##`.\n blocks.push(...headerBlocks(header[1].length, header[2].replace(/\\s+#+$/, ''), line, line, false));\n index += 1;\n continue;\n }\n\n if (raw.trim().startsWith('<!--')) {\n index = readComment(lines, index, blocks);\n continue;\n }\n\n if (QUOTE.test(raw)) {\n const quoted: string[] = [];\n\n while (index < lines.length && QUOTE.test(lines[index].text)) {\n quoted.push(lines[index].text.replace(/^\\s*> ?/, ''));\n index += 1;\n }\n\n blocks.push({ kind: 'note', text: quoted.join('\\n'), line, last: lines[index - 1].line });\n continue;\n }\n\n if (THEMATIC_BREAK.test(raw)) {\n blocks.push({ kind: 'foreign', line, last: line });\n index += 1;\n continue;\n }\n\n const item = LIST_ITEM.exec(raw);\n\n if (item) {\n const items: ListItem[] = [];\n index = readList(lines, index, item[1].length, items);\n blocks.push({ kind: 'list', items, line, last: lines[index - 1].line });\n continue;\n }\n\n const media = mediaBlock(raw.trim(), line);\n\n if (media) {\n blocks.push(media);\n index += 1;\n continue;\n }\n\n const fence = FENCE.exec(raw);\n\n if (fence) {\n let buffer = raw;\n index += 1;\n\n while (index < lines.length) {\n buffer += '\\n' + lines[index].text;\n index += 1;\n\n if (lines[index - 1].text.trimStart().startsWith(fence[1])) {\n break;\n }\n }\n\n blocks.push({ kind: 'paragraph', text: buffer, line, last: lines[index - 1].line });\n continue;\n }\n\n // A paragraph runs until a blank line or another block. Underlined with\n // `===` or `---`, it is a heading instead.\n let buffer = raw;\n index += 1;\n let heading = false;\n\n while (index < lines.length) {\n const next = lines[index].text;\n\n if (options.headings && SETEXT_UNDERLINE.test(next)) {\n const level = next.trim().startsWith('=') ? 1 : 2;\n blocks.push(...headerBlocks(level, buffer.split('\\n').map((part) => part.trim()).join(' '), line, lines[index].line, true));\n index += 1;\n heading = true;\n break;\n }\n\n if (endsParagraph(next)) {\n break;\n }\n\n buffer += '\\n' + next;\n index += 1;\n }\n\n if (!heading) {\n blocks.push({ kind: 'paragraph', text: buffer, line, last: lines[index - 1].line });\n }\n }\n\n return blocks;\n};\n\nconst headerBlocks = (level: number, text: string, line: number, last: number, setext: boolean): Block[] => {\n const inline = INLINE_ATTRIBUTES.exec(text) ?? ONLY_ATTRIBUTES.exec(text);\n\n if (inline) {\n return [\n { kind: 'header', level, text: inline[1], line, last, setext },\n { kind: 'comment', body: inline[2], line, last: line, inline: true },\n ];\n }\n\n return [{ kind: 'header', level, text, line, last, setext }];\n};\n\nconst endsParagraph = (next: string): boolean => {\n const trimmed = next.trim();\n return (\n trimmed === '' ||\n HEADER_START.test(next) ||\n LIST_INTERRUPTS_PARAGRAPH.test(next) ||\n QUOTE.test(next) ||\n FENCE.test(next) ||\n THEMATIC_BREAK.test(next) ||\n trimmed.startsWith('<!--') ||\n isStandaloneMedia(trimmed)\n );\n};\n\n/** A picture or video on a line of its own is media, even right after a paragraph line. */\nconst isStandaloneMedia = (text: string): boolean => {\n if (WRAPPED_LINE.test(text) || IMAGE_LINE.test(text)) {\n return true;\n }\n\n const link = LINK_LINE.exec(text);\n return link !== null && detectVideoProvider(mediaDestination(link[2])) !== null;\n};\n\n/** The destination of a media line's parens: the src, with CommonMark's optional \"title\" dropped. */\nconst mediaDestination = (raw: string): string => {\n return raw.replace(/\\s+(?:\"[^\"]*\"|'[^']*')?\\s*$/, '');\n};\n\nconst mediaBlock = (text: string, line: number): MediaBlock | null => {\n const wrapped = WRAPPED_LINE.exec(text);\n\n if (wrapped) {\n return { kind: 'media', mediaKind: 'wrapped', alt: wrapped[1], thumb: mediaDestination(wrapped[2]), url: mediaDestination(wrapped[3]), line, last: line };\n }\n\n const image = IMAGE_LINE.exec(text);\n\n if (image) {\n return { kind: 'media', mediaKind: 'image', alt: image[1], url: mediaDestination(image[2]), line, last: line };\n }\n\n const link = LINK_LINE.exec(text);\n\n if (link) {\n return { kind: 'media', mediaKind: 'link', text: link[1], url: mediaDestination(link[2]), line, last: line };\n }\n\n return null;\n};\n\n/**\n * Reads an HTML comment from `start`: `<!-- orbit … -->` ones become comment\n * blocks, others are kept as they are, unread.\n */\nconst readComment = (lines: SourceLine[], start: number, blocks: Block[]): number => {\n let index = start;\n let buffer = lines[index].text;\n index += 1;\n\n while (index < lines.length && !buffer.includes('-->')) {\n buffer += '\\n' + lines[index].text;\n index += 1;\n }\n\n const comment = /<!--\\s*([\\s\\S]*?)\\s*-->/.exec(buffer);\n\n if (comment && /^orbit(?::|\\b)/i.test(comment[1])) {\n // Only the `orbit` keyword's own line is trimmed, then the body is\n // dedented, so YAML indented under the comment keeps its nesting.\n const startsBelow = /^orbit:?[^\\S\\n]*\\n/i.test(comment[1]);\n const body = comment[1].replace(/^orbit:?[^\\S\\n]*\\n?/i, '');\n blocks.push({\n kind: 'comment',\n body: dedent(body.split('\\n')).join('\\n'),\n line: lines[start].line,\n last: lines[index - 1].line,\n bodyLine: startsBelow ? lines[start].line + 1 : lines[start].line,\n });\n } else {\n blocks.push({ kind: 'foreign', line: lines[start].line, last: lines[index - 1].line, comment: comment?.[1] });\n }\n\n return index;\n};\n\nconst readList = (lines: SourceLine[], start: number, baseIndent: number, items: ListItem[]): number => {\n let index = start;\n\n while (index < lines.length) {\n const { text: raw, line } = lines[index];\n\n if (raw.trim() === '') {\n index += 1;\n continue;\n }\n\n const match = THEMATIC_BREAK.test(raw) ? null : LIST_ITEM.exec(raw);\n\n if (!match || match[1].length < baseIndent) {\n break;\n }\n\n let text = match[2];\n let inlineAttrs: string | undefined;\n const inline = INLINE_ATTRIBUTES.exec(text) ?? ONLY_ATTRIBUTES.exec(text);\n\n if (inline) {\n text = inline[1];\n inlineAttrs = inline[2];\n }\n\n index += 1;\n\n // The item's first line is its title. Lines indented under it, and lines\n // that continue it without a blank line in between, are its content.\n const indented: SourceLine[] = [];\n const content: SourceLine[] = [];\n let blanks: SourceLine[] = [];\n let continues = true;\n\n while (index < lines.length) {\n const next = lines[index];\n\n if (isBlank(next)) {\n blanks.push(next);\n continues = false;\n index += 1;\n continue;\n }\n\n if (next.indent > baseIndent) {\n content.push(...blanks, next);\n indented.push(next);\n blanks = [];\n index += 1;\n continue;\n }\n\n if (continues && continuesItem(next.text)) {\n content.push({ text: next.text.trimStart(), line: next.line, indent: 0 });\n index += 1;\n continue;\n }\n\n break;\n }\n\n let shift = Number.POSITIVE_INFINITY;\n\n for (const entry of indented) {\n shift = Math.min(shift, entry.indent);\n }\n\n const indentedSet = new Set(indented);\n const dedented = content.map((entry) =>\n indentedSet.has(entry) ? { text: entry.text.slice(shift), line: entry.line, indent: entry.indent - shift } : entry);\n items.push({ text, line, inlineAttrs, content: tokenize(dedented, { headings: false }) });\n }\n\n return index;\n};\n\n/** A line right after a list item, not indented, that still belongs to it (CommonMark's lazy continuation). */\nconst continuesItem = (text: string): boolean => {\n return !(\n LIST_ITEM.test(text) ||\n HEADER_START.test(text) ||\n QUOTE.test(text) ||\n FENCE.test(text) ||\n THEMATIC_BREAK.test(text) ||\n text.trim().startsWith('<!--')\n );\n};\n\nconst indentation = (text: string): number => {\n return /^ */.exec(text)![0].length;\n};\n\n/** A line with nothing but whitespace: its leading spaces are its whole length. No trim() copy. */\nconst isBlank = (line: SourceLine): boolean => {\n if (line.indent === line.text.length) {\n return true;\n }\n\n // Printable ASCII past the indent is visible; a control character (a form\n // feed, a vertical tab) or exotic whitespace needs the slow check.\n const code = line.text.charCodeAt(line.indent);\n return (code < 33 || code > 126) && /^\\s*$/.test(line.text);\n};\n\n/** Tabs in the indentation count to the next multiple of four columns. */\nconst expandLeadingTabs = (text: string): string => {\n const leading = /^[ \\t]*/.exec(text)![0];\n\n if (!leading.includes('\\t')) {\n return text;\n }\n\n let columns = 0;\n\n for (const character of leading) {\n columns = character === '\\t' ? columns + 4 - (columns % 4) : columns + 1;\n }\n\n return ' '.repeat(columns) + text.slice(leading.length);\n};\n\nconst dedent = (lines: string[]): string[] => {\n const shift = Math.min(...lines.filter((line) => line.trim() !== '').map(indentation));\n return Number.isFinite(shift) && shift > 0 ? lines.map((line) => line.slice(Math.min(shift, indentation(line)))) : lines;\n};\n\n// Tree building\n\nconst buildTree = (\n blocks: Block[],\n docOptions: OrbitDocumentOptions,\n diagnostics: DiagnosticCollector,\n inputIsBlank: boolean,\n recorder: SourceRecorder,\n untitled: string | undefined,\n): OrbitNode => {\n const attacher = new ContentAttacher(diagnostics, recorder, untitled);\n const headers = blocks.filter((block): block is HeaderBlock => block.kind === 'header');\n const root = headers.length > 0\n ? buildFromHeadings(blocks, headers, docOptions, attacher)\n : buildFromLists(blocks, docOptions, diagnostics, attacher, inputIsBlank);\n attacher.finish();\n return root;\n};\n\n/**\n * Headings nest by level, and everything else belongs to the heading above\n * it. One heading at the top level, written first, is the root; several\n * share a root named after the title.\n */\nconst buildFromHeadings = (\n blocks: Block[],\n headers: HeaderBlock[],\n docOptions: OrbitDocumentOptions,\n attacher: ContentAttacher,\n): OrbitNode => {\n const topLevel = Math.min(...headers.map((header) => header.level));\n const topHeaders = headers.filter((header) => header.level === topLevel);\n const rootHeader = topHeaders.length === 1 && topHeaders[0] === headers[0] ? headers[0] : null;\n const lead = rootHeader || docOptions.title !== undefined ? null : leadParagraph(blocks, headers[0]);\n const root = rootHeader ? attacher.addHeading(rootHeader) : attacher.addGeneratedRoot(docOptions.title ?? lead?.text, lead, headers[0].line);\n attacher.setRoot(root);\n attacher.keepAtDocumentLevel(blocks);\n // Text before the root heading belongs to the root too.\n const stack: { node: OrbitNode; level: number }[] = [{ node: root, level: rootHeader ? topLevel : 0 }];\n\n for (const block of blocks) {\n if (block === lead || block === rootHeader) {\n continue;\n }\n\n if (block.kind !== 'header') {\n attacher.attach(block, stack[stack.length - 1].node);\n continue;\n }\n\n while (stack.length > 1 && stack[stack.length - 1].level >= block.level) {\n stack.pop();\n }\n\n const node = attacher.addHeading(block);\n const parent = stack[stack.length - 1].node;\n setParent(node, parent);\n parent.children.push(node);\n stack.push({ node, level: block.level });\n attacher.reset();\n }\n\n return root;\n};\n\n/** Documents without headings: the outline comes from their bullet or numbered lists. */\nconst buildFromLists = (\n blocks: Block[],\n docOptions: OrbitDocumentOptions,\n diagnostics: DiagnosticCollector,\n attacher: ContentAttacher,\n inputIsBlank: boolean,\n): OrbitNode => {\n const lists = blocks.filter((block): block is ListBlock => block.kind === 'list');\n\n if (lists.length === 0) {\n if (inputIsBlank) {\n diagnostics.recover('empty-document', 'The document is empty.', 1);\n const empty = emptyNode();\n attacher.setRoot(empty);\n return empty;\n }\n\n const firstContent = blocks.find((block) => block.kind !== 'blank');\n diagnostics.recover(\n 'no-structure',\n 'No headings or lists found. Start the map with a \"# Title\" heading or a bullet list.',\n firstContent?.line,\n );\n // Only text: it's the note of a map with no ideas yet, so editing the map keeps it.\n const root = attacher.addGeneratedRoot(docOptions.title, null, firstContent?.line ?? 1, true);\n attacher.setRoot(root);\n\n for (const block of blocks) {\n attacher.attach(block, root);\n }\n\n return root;\n }\n\n const [firstList] = lists;\n const lead = docOptions.title !== undefined ? null : leadParagraph(blocks, firstList);\n\n if (!docOptions.title && !lead && lists.length === 1 && firstList.items.length === 1) {\n // A single top-level item is the root: `- Project\\n - Research`.\n const root = attacher.addItem(firstList.items[0], undefined);\n attacher.setRoot(root);\n attacher.keepAtDocumentLevel(blocks);\n\n for (const block of blocks) {\n if (block !== firstList) {\n attacher.attach(block, root);\n }\n }\n\n return root;\n }\n\n const root = attacher.addGeneratedRoot(docOptions.title ?? lead?.text, lead, firstList.line);\n attacher.setRoot(root);\n attacher.keepAtDocumentLevel(blocks);\n\n for (const block of blocks) {\n if (block !== lead) {\n attacher.attach(block, root);\n }\n }\n\n return root;\n};\n\n/** A single-line paragraph directly before `target` (with only blank lines between) names the generated root. */\nconst leadParagraph = (blocks: Block[], target: Block): ParagraphBlock | null => {\n const targetIndex = blocks.indexOf(target);\n const before = blocks.slice(0, targetIndex).filter((block) => block.kind !== 'blank');\n\n if (before.length !== 1 || before[0].kind !== 'paragraph' || before[0].text.includes('\\n')) {\n return null;\n }\n\n return before[0];\n};\n\nconst syntheticRoot = (text: string | undefined, diagnostics: DiagnosticCollector, line: number, quiet = false, untitled = UNTITLED_ROOT_TEXT): OrbitNode => {\n if (text !== undefined) {\n return makeNode({ text, line });\n }\n\n if (!quiet) {\n diagnostics.note(\n 'synthetic-root',\n `No single top-level heading, so the map is rooted at \"${untitled}\". Add a \"# Title\" heading or a title in the frontmatter to name it.`,\n line,\n );\n }\n\n // Named in the reader's language, with the same id in every one.\n return { ...makeNode({ text: untitled, line }), id: UNTITLED_ROOT_ID };\n};\n\n/**\n * A paragraph of link reference or footnote definitions (`[docs]: https://…`,\n * `[^1]: …`). They belong to the whole document, wherever they're written:\n * deleting the idea above them mustn't take them along.\n */\nconst isDefinitions = (text: string): boolean => {\n const lines = text.split('\\n');\n return DEFINITION.test(lines[0]) && lines.every((line) => DEFINITION.test(line) || /^\\s{2,}\\S/.test(line));\n};\n\nconst DEFINITION = /^ {0,3}\\[\\^?[^\\]\\n]+\\]:\\s*\\S/;\n\n/** How a list item's line is written: where its marker is, the marker, and where its text starts. */\nconst itemShape = (raw: string): NodeShape => {\n const match = /^([ \\t]*)([-*+]|\\d{1,9}[.)])([ \\t]+)/.exec(raw);\n\n if (!match) {\n return { kind: 'item', indent: 0, marker: '-', content: 2 };\n }\n\n const indent = expandLeadingTabs(match[1]).length;\n return { kind: 'item', indent, marker: match[2], content: indent + match[2].length + match[3].length };\n};\n\n// Content: lists become children; everything else is a note, media or attributes\n\ntype MediaAssign = 'image' | 'video' | 'embed' | 'note';\n\n/**\n * Attaches blocks to nodes in document order: every list's items become\n * children, and paragraphs, quotes, code, media lines and attribute\n * comments go to the node itself.\n */\nclass ContentAttacher {\n private readonly diagnostics: DiagnosticCollector;\n private readonly recorder: SourceRecorder;\n private readonly notes = new Map<OrbitNode, string[]>();\n\n /** The map's root, which definitions belong to. */\n private root: OrbitNode | null = null;\n\n /** Blocks of the whole document rather than of the idea above them: definitions at its end. */\n private documentLevel = new Set<Block>();\n\n /** The list item made last, in reading order. */\n private lastItem: OrbitNode | null = null;\n\n /** The node a list was just attached to, and that list's last item, until anything else comes (a blank line too). */\n private afterList: { node: OrbitNode; item: OrbitNode; lastLine: number } | null = null;\n\n /** The media line just read, which a `contentType` comment below it can reclassify. */\n private lastMedia: { node: OrbitNode; block: MediaBlock; result: MediaAssign } | null = null;\n\n /** A `contentType` comment waiting for the media line below it. */\n private pendingContentType: { node: OrbitNode; kind: ContentType } | null = null;\n\n /** The made-up root's name, when it has no title. */\n private readonly untitled: string | undefined;\n\n constructor(diagnostics: DiagnosticCollector, recorder: SourceRecorder, untitled?: string) {\n this.diagnostics = diagnostics;\n this.recorder = recorder;\n this.untitled = untitled;\n }\n\n setRoot(root: OrbitNode): void {\n this.root = root;\n }\n\n /**\n * Link reference and footnote definitions at the end of the document\n * (`[docs]: https://…`, `[^1]: …`) belong to the whole map, not to the\n * idea above them: deleting that idea mustn't take them along.\n */\n keepAtDocumentLevel(blocks: Block[]): void {\n for (let index = blocks.length - 1; index >= 0; index -= 1) {\n const block = blocks[index];\n\n if (block.kind === 'blank') {\n continue;\n }\n\n if (block.kind !== 'paragraph' || !isDefinitions(block.text)) {\n return;\n }\n\n this.documentLevel.add(block);\n }\n }\n\n /** A heading's node, its line recorded as its title. */\n addHeading(header: HeaderBlock): OrbitNode {\n noteAttributeComments(header.text, header.line, this.diagnostics);\n const node = makeNode(header);\n this.recorder.mark(header.line, header.last, node, 'title');\n this.recorder.shape(node, { kind: 'heading', level: header.level, setext: header.setext }, header.line);\n return node;\n }\n\n /** A root Orbit makes up: named after the title, the paragraph `lead`, or \"Untitled map\". */\n addGeneratedRoot(text: string | undefined, lead: ParagraphBlock | null, line: number, quiet = false): OrbitNode {\n const node = syntheticRoot(text, this.diagnostics, line, quiet, this.untitled);\n\n if (lead) {\n this.recorder.mark(lead.line, lead.last, node, 'title');\n }\n\n this.recorder.shape(node, { kind: 'generated', lead: lead !== null }, lead ? lead.line : null);\n return node;\n }\n\n attach(block: Block, node: OrbitNode): void {\n if (block.kind === 'comment' && !block.inline && this.afterList?.node === node && block.line === this.afterList.lastLine + 1) {\n const item = this.afterList.item.text;\n this.diagnostics.note('attributes-after-list', `This attribute block sets \"${node.text}\"'s attributes: it isn't indented under \"${item}\" above it. Indent it to set \"${item}\"'s.`, block.line);\n }\n\n this.afterList = null;\n\n switch (block.kind) {\n case 'blank':\n // A blank line goes with the line above it (see SourceRecorder.finish).\n return;\n case 'foreign':\n if (block.comment !== undefined) {\n noteAttributeComments(`<!--${block.comment}-->`, block.line, this.diagnostics);\n }\n\n this.recorder.mark(block.line, block.last, node, 'foreign');\n return;\n case 'comment':\n this.applyComment(block, node);\n return;\n case 'media': {\n const forced = this.pendingContentType?.node === node ? this.pendingContentType.kind : null;\n this.pendingContentType = null;\n const result = assignMedia(block, node, this.noteParts(node), forced);\n this.lastMedia = { node, block, result };\n this.recorder.mark(block.line, block.last, node, result === 'note' ? 'note' : 'media');\n return;\n }\n case 'list':\n for (const item of block.items) {\n this.addItem(item, node);\n }\n\n this.afterList = this.lastItem ? { node, item: this.lastItem, lastLine: lastLineOf(block.items) } : null;\n break;\n case 'header':\n this.noteParts(node).push(`${'#'.repeat(block.level)} ${block.text}`);\n this.recorder.mark(block.line, block.last, node, 'note');\n break;\n case 'note':\n case 'paragraph': {\n const documentLevel = this.documentLevel.has(block) && this.root !== null;\n const owner = documentLevel ? this.root! : node;\n this.noteParts(owner).push(block.text);\n this.recorder.mark(block.line, block.last, owner, documentLevel ? 'end' : 'note');\n break;\n }\n }\n\n this.reset();\n }\n\n /** Builds a list item's node (under `parent`, if any) with everything written under it. */\n addItem(item: ListItem, parent: OrbitNode | undefined): OrbitNode {\n noteAttributeComments(item.text, item.line, this.diagnostics);\n const node = makeNode(item);\n this.lastItem = node;\n this.recorder.mark(item.line, item.line, node, 'title');\n this.recorder.shape(node, itemShape(this.recorder.line(item.line)), item.line);\n\n if (parent) {\n setParent(node, parent);\n parent.children.push(node);\n }\n\n if (item.inlineAttrs !== undefined) {\n applyAttributeBlock(node, { kind: 'comment', body: item.inlineAttrs, line: item.line, last: item.line, inline: true }, this.diagnostics);\n }\n\n this.reset();\n\n for (const block of item.content) {\n this.attach(block, node);\n }\n\n this.reset();\n return node;\n }\n\n /** Forgets the media line just read, at a new heading or after other content. */\n reset(): void {\n this.lastMedia = null;\n this.pendingContentType = null;\n }\n\n /** Writes the collected notes, after any `note` attribute. */\n finish(): void {\n for (const [node, parts] of this.notes) {\n const note = parts.join('\\n\\n');\n\n // Emptiness is checked on the trimmed form, but the stored note keeps\n // its whitespace: blockquote notes carry it on purpose.\n if (note.trim()) {\n node.note = node.note ? `${node.note}\\n\\n${note}` : note;\n // Only a default: an explicit `noteFormat` attribute wins.\n node.noteFormat = node.noteFormat ?? 'markdown';\n }\n }\n }\n\n private noteParts(node: OrbitNode): string[] {\n let parts = this.notes.get(node);\n\n if (!parts) {\n parts = [];\n this.notes.set(node, parts);\n }\n\n return parts;\n }\n\n private applyComment(block: CommentBlock, node: OrbitNode): void {\n const keys = applyAttributeBlock(node, block, this.diagnostics, {\n applyContentType: (kind) => {\n if (this.lastMedia?.node === node) {\n reclassify(node, this.lastMedia.block, kind, this.noteParts(node), this.lastMedia.result);\n this.lastMedia.result = kind === 'none' ? 'note' : kind;\n const media = this.lastMedia.block;\n this.recorder.mark(media.line, media.last, node, this.lastMedia.result === 'note' ? 'note' : 'media');\n } else {\n this.pendingContentType = { node, kind };\n }\n },\n clearLastMedia: () => {\n this.lastMedia = null;\n },\n captionTarget: () => {\n const last = this.lastMedia;\n return last?.node === node && (last.result === 'image' || last.result === 'video' || last.result === 'embed') ? last.result : null;\n },\n });\n\n if (!block.inline) {\n // A comment that only says what the media line above it is goes with it; one Orbit\n // couldn't read is kept as it's written.\n const role: LineRole = keys === null ? 'foreign' : keys.length > 0 && keys.every((key) => key === 'contentType' || key === 'caption') ? 'media' : 'attributes';\n this.recorder.mark(block.line, block.last, node, role);\n }\n }\n}\n\nconst reclassify = (\n node: OrbitNode,\n media: MediaBlock,\n kind: ContentType,\n noteLines: string[],\n previous: MediaAssign | null,\n): void => {\n // Undo only what this media block was read as, so an earlier block's\n // assignment survives.\n if (previous === 'image') {\n node.image = undefined;\n } else if (previous === 'video') {\n node.video = undefined;\n } else if (previous === 'embed') {\n node.embed = undefined;\n } else if (previous === 'note') {\n const reconstructed = reconstructMediaSource(media);\n\n if (noteLines.length && noteLines[noteLines.length - 1] === reconstructed) {\n noteLines.pop();\n }\n }\n\n if (kind === 'none') {\n noteLines.push(reconstructMediaSource(media));\n return;\n }\n\n if (kind === 'image') {\n node.image = { src: media.url, alt: media.alt || undefined };\n return;\n }\n\n if (kind === 'video') {\n const provider = detectVideoProvider(media.url) ?? 'native';\n node.video = { src: media.url, provider, thumbnail: media.mediaKind === 'wrapped' ? media.thumb : undefined };\n return;\n }\n\n node.embed = { src: media.url };\n};\n\ninterface AttributeContext {\n applyContentType: (kind: ContentType) => void;\n clearLastMedia: () => void;\n\n /** The media of the line just above the block, which a caption in it describes. */\n captionTarget: () => MediaKey | null;\n}\n\ntype MediaKey = 'image' | 'video' | 'embed';\n\n/** Keys an attribute block takes besides the node attributes. */\nconst MARKDOWN_ATTRIBUTE_VOCABULARY = { keys: ['contentType'] };\n\n/**\n * Applies a `<!-- orbit ... -->` block to a node. Media keys are applied\n * before `caption`, which describes, in order: the one image, video or embed\n * the block itself sets; the media line just above the block; or else the\n * node's video, embed or image.\n */\nconst applyAttributeBlock = (\n node: OrbitNode,\n comment: CommentBlock,\n diagnostics: DiagnosticCollector,\n context?: AttributeContext,\n): string[] | null => {\n const body = comment.body.trim();\n\n if (body === '') {\n return [];\n }\n\n // On one line, `status: active, priority: 1` is two attributes.\n const pairs = comment.inline ? commaSeparatedAttributes(body) : null;\n let parsed: Record<string, unknown>;\n\n try {\n parsed = pairs\n ? Object.assign({}, ...pairs.map((pair) => parseYaml(pair) as Record<string, unknown>))\n : ((parseYaml(body) ?? {}) as Record<string, unknown>);\n } catch (error) {\n const problem = error instanceof YamlMiniError ? error : null;\n // A pair split out of a one-line comment keeps no line numbers of its own.\n const line = problem && !pairs ? (comment.bodyLine ?? comment.line) + problem.line - 1 : comment.line;\n diagnostics.recover('invalid-attributes', `Invalid YAML in attribute block: ${problem?.reason ?? (error as Error).message}`, line);\n return null;\n }\n\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n diagnostics.recover('invalid-attributes', 'An attribute block must contain \"key: value\" pairs.', comment.line);\n return null;\n }\n\n const entries = Object.entries(parsed);\n\n for (const [key, value] of entries) {\n if (key === 'caption') {\n continue;\n }\n\n if (key === 'contentType') {\n if (!CONTENT_TYPES.has(value as ContentType)) {\n diagnostics.recover(\n 'unknown-content-type',\n `Unknown contentType \"${String(value)}\"; expected image, video, embed or none.`,\n comment.line,\n );\n continue;\n }\n\n context?.applyContentType(value as ContentType);\n continue;\n }\n\n assignNodeAttribute(node, key, value, diagnostics, comment.line, MARKDOWN_ATTRIBUTE_VOCABULARY);\n\n if (key === 'image' || key === 'video' || key === 'embed') {\n context?.clearLastMedia();\n }\n }\n\n const mediaSet = entries.map(([key]) => key).filter((key): key is MediaKey => key === 'image' || key === 'video' || key === 'embed');\n\n for (const [key, value] of entries) {\n if (key !== 'caption') {\n continue;\n }\n\n const described = mediaSet.length === 1 ? mediaSet[0] : mediaSet.length === 0 ? context?.captionTarget() ?? null : null;\n const media = described ? node[described] : undefined;\n\n if (media && value !== null && value !== undefined) {\n media.caption = String(value);\n } else {\n assignNodeAttribute(node, key, value, diagnostics, comment.line);\n }\n }\n\n return entries.map(([key]) => key);\n};\n\nconst assignMedia = (block: MediaBlock, node: OrbitNode, noteLines: string[], forced: ContentType | null): MediaAssign => {\n const toNote = (): MediaAssign => {\n noteLines.push(reconstructMediaSource(block));\n return 'note';\n };\n\n if (forced === 'none') {\n return toNote();\n }\n\n if (forced === 'image') {\n if (node.image) {\n return toNote();\n }\n\n node.image = { src: block.url, alt: block.alt || undefined };\n return 'image';\n }\n\n if (forced === 'video') {\n if (node.video) {\n return toNote();\n }\n\n node.video = { src: block.url, provider: detectVideoProvider(block.url) ?? 'native', thumbnail: block.mediaKind === 'wrapped' ? block.thumb : undefined };\n return 'video';\n }\n\n if (forced === 'embed') {\n if (node.embed) {\n return toNote();\n }\n\n node.embed = { src: block.url };\n return 'embed';\n }\n\n // Auto-detect path\n if (block.mediaKind === 'wrapped') {\n const provider = detectVideoProvider(block.url);\n\n if (provider) {\n // Wrapped video: only consume into node.video; if taken, fall to note.\n if (!node.video) {\n node.video = { src: block.url, provider, thumbnail: block.thumb };\n return 'video';\n }\n } else if (!node.image) {\n // Wrapped link that's not a video: treat the inner thumbnail as the image.\n node.image = { src: block.thumb!, alt: block.alt || undefined };\n return 'image';\n }\n } else if (block.mediaKind === 'image') {\n if (!node.image) {\n node.image = { src: block.url, alt: block.alt || undefined };\n return 'image';\n }\n } else if (block.mediaKind === 'link') {\n const provider = detectVideoProvider(block.url);\n\n if (!node.video && provider) {\n node.video = { src: block.url, provider };\n return 'video';\n }\n }\n\n return toNote();\n};\n\n/**\n * `key: value, key: value` on one line, split into its pairs; null when the\n * text isn't a list of pairs. Commas inside quotes or brackets don't split,\n * and a backslash escapes the next character inside double quotes.\n */\nconst commaSeparatedAttributes = (body: string): string[] | null => {\n if (body.includes('\\n')) {\n return null;\n }\n\n const pairs: string[] = [];\n let depth = 0;\n let quote = '';\n let start = 0;\n\n for (let index = 0; index < body.length; index += 1) {\n const character = body[index];\n\n if (quote) {\n if (character === '\\\\' && quote === '\"') {\n index += 1;\n } else if (character === quote) {\n quote = '';\n }\n } else if (character === '\"' || character === \"'\") {\n quote = character;\n } else if (character === '[' || character === '{') {\n depth += 1;\n } else if (character === ']' || character === '}') {\n depth -= 1;\n } else if (character === ',' && depth === 0) {\n pairs.push(body.slice(start, index).trim());\n start = index + 1;\n }\n }\n\n pairs.push(body.slice(start).trim());\n const isPair = (text: string) => /^[A-Za-z][\\w-]*\\s*:(\\s|$)/.test(text);\n return pairs.length > 1 && pairs.every(isPair) ? pairs : null;\n};\n\nconst reconstructMediaSource = (block: MediaBlock): string => {\n if (block.mediaKind === 'image') {\n return ``;\n }\n\n if (block.mediaKind === 'wrapped') {\n return `[](${block.url})`;\n }\n\n return `[${block.text ?? ''}](${block.url})`;\n};\n\n// Shared helpers\n\n/** Where a link in a node's note is: the first line from the node's title up to the next node's that has it. */\nconst noteLinkLines = (root: OrbitNode, rawLines: string[]): LinkLine => {\n const titles: number[] = [];\n\n const collect = (node: OrbitNode): void => {\n if (node.source?.line !== undefined) {\n titles.push(node.source.line);\n }\n\n node.children.forEach(collect);\n };\n\n collect(root);\n titles.sort((a, b) => a - b);\n\n return (node, href, inNote) => {\n const start = node.source?.line;\n\n if (start === undefined || !inNote) {\n return start;\n }\n\n const end = titles.find((line) => line > start) ?? rawLines.length + 1;\n\n for (let line = start; line < end; line += 1) {\n if (rawLines[line - 1].includes(`](${href})`)) {\n return line;\n }\n }\n\n return start;\n };\n};\n\n/** The last line a list's items take, blank lines after them aside. */\nconst lastLineOf = (items: ListItem[]): number => {\n const item = items[items.length - 1];\n const content = item.content.filter((block) => block.kind !== 'blank');\n const last = content[content.length - 1];\n\n if (last?.kind === 'list') {\n return lastLineOf(last.items);\n }\n\n return last ? last.last : item.line;\n};\n\n/**\n * Notes a comment that sets nothing because it lacks the `orbit` keyword,\n * although it reads like attributes: `<!-- status: done -->`.\n */\nconst noteAttributeComments = (text: string, line: number, diagnostics: DiagnosticCollector): void => {\n for (const match of text.matchAll(HIDDEN_COMMENT)) {\n const body = match[2].trim();\n const key = /^([A-Za-z]+)\\s*:/.exec(body)?.[1];\n\n if (key !== undefined && (NODE_ATTRIBUTE_KEYS as readonly string[]).includes(key)) {\n diagnostics.note('comment-without-orbit', `This comment is hidden, so it sets nothing: to set \"${key}\", write <!-- orbit ${body} -->.`, line);\n }\n }\n};\n\nconst makeNode = (source: { text: string; line: number }): OrbitNode => {\n const parts = parseTitle(source.text);\n const node: OrbitNode = {\n id: nodeSlug(parts.text),\n text: parts.text,\n level: 0,\n children: [],\n icon: parts.icon,\n link: parts.link,\n source: { line: source.line, raw: '' },\n };\n\n if (parts.status) {\n node.status = parts.status;\n }\n\n if (parts.tags) {\n node.tags = parts.tags;\n }\n\n return node;\n};\n\nconst emptyNode = (): OrbitNode => {\n return { id: 'empty', text: '', level: 0, children: [] };\n};\n\nconst fixLevels = (node: OrbitNode, level: number): void => {\n node.level = level;\n\n for (const child of node.children) {\n setParent(child, node);\n fixLevels(child, level + 1);\n }\n};\n",
|
|
20
|
+
"import type { OrbitDocumentOptions, OrbitNode, ParsedOrbitDocument } from './types.js';\nimport { parseYaml, yamlItemLine, yamlLineOf, YamlMiniError } from './yaml-mini.js';\nimport { UNTITLED_ROOT_ID, UNTITLED_ROOT_TEXT } from './parser-markdown.js';\nimport { upgradeFormat } from './format-upgrades.js';\nimport { checkNodeLinks } from './node-links.js';\nimport { ensureUniqueNodeIds, nodeSlug, setParent } from './utils.js';\nimport { DiagnosticCollector } from './diagnostics.js';\nimport { applyDocumentOption, DOCUMENT_OPTION_KEYS, unknownOptionMessage } from './document-options.js';\nimport { assignNodeAttribute, type AttributeVocabulary } from './node-attributes.js';\nimport { lineOfKey, normalizeSource } from './source.js';\n\nexport interface ParseYamlOptions {\n /** Throw on the first problem instead of recording a diagnostic. Off by default. */\n strict?: boolean;\n\n /** 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. */\n untitled?: string;\n}\n\nexport const parseOrbitYAML = (input: string, options: ParseYamlOptions = {}): ParsedOrbitDocument => {\n const diagnostics = new DiagnosticCollector(options.strict ?? false);\n const source = normalizeSource(input);\n const lines = source.split('\\n');\n const extra: Record<string, unknown> = {};\n const result = (root: OrbitNode, docOptions: OrbitDocumentOptions): ParsedOrbitDocument => ({\n root,\n options: docOptions,\n ...(Object.keys(extra).length > 0 ? { extra } : {}),\n warnings: diagnostics.warnings,\n diagnostics: diagnostics.diagnostics,\n });\n\n let parsed: unknown;\n\n try {\n parsed = parseYaml(source);\n } catch (error) {\n const problem = error instanceof YamlMiniError ? error : null;\n diagnostics.recover('invalid-yaml', `Invalid YAML: ${problem?.reason ?? (error as Error).message}`, problem?.line ?? 1, 'error');\n return result(emptyNode(), {});\n }\n\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n diagnostics.recover('invalid-yaml', 'A YAML map needs top-level \"key: value\" entries such as \"nodes:\".', 1, 'error');\n return result(emptyNode(), {});\n }\n\n const docOptions: OrbitDocumentOptions = {};\n const map = parsed as Record<string, unknown>;\n\n for (const [key, value] of Object.entries(map)) {\n if (key === 'nodes') {\n continue;\n }\n\n const line = lineOfKey(lines, key);\n\n if (!DOCUMENT_OPTION_KEYS.has(key)) {\n diagnostics.recover('unknown-yaml-key', unknownOptionMessage(key, 'top-level'), line);\n extra[key] = value;\n continue;\n }\n\n applyDocumentOption(docOptions, key, value, (message) => diagnostics.recover('invalid-option-value', message, line));\n }\n\n const nodes = map.nodes;\n\n if (!Array.isArray(nodes) || nodes.length === 0) {\n const message = nodes !== undefined && nodes !== null && !Array.isArray(nodes)\n ? '\"nodes\" must be a list: start the root on the line below it with \"- text: …\".'\n : 'No nodes found. Add a \"nodes:\" list with one root node.';\n diagnostics.recover('no-structure', message, lineOfKey(lines, 'nodes') ?? 1);\n return result(emptyNode(), docOptions);\n }\n\n const root = nodes.length === 1 ? buildNode(nodes[0], 0, undefined, diagnostics, yamlItemLine(nodes, 0)) : sharedRoot(docOptions.title, diagnostics, lineOfKey(lines, 'nodes'), options.untitled);\n\n if (nodes.length > 1) {\n // Several top-level nodes share a root named after the title.\n nodes.forEach((raw, index) => {\n root.children.push(buildNode(raw, 1, root, diagnostics, yamlItemLine(nodes, index)));\n });\n }\n\n ensureUniqueNodeIds(root);\n checkNodeLinks(root, diagnostics, (node, _href, inNote) => nodeKeyLines.get(node)?.(inNote ? 'note' : 'link'));\n const document = result(root, docOptions);\n upgradeFormat(document, diagnostics, lineOfKey(lines, 'schemaVersion'));\n document.warnings = diagnostics.warnings;\n return document;\n};\n\nconst sharedRoot = (title: string | undefined, diagnostics: DiagnosticCollector, line: number | undefined, untitled = UNTITLED_ROOT_TEXT): OrbitNode => {\n if (title !== undefined) {\n return { id: nodeSlug(title), text: title, level: 0, children: [] };\n }\n\n diagnostics.note(\n 'synthetic-root',\n `Several top-level nodes, so the map is rooted at \"${untitled}\". Add a title to name it.`,\n line,\n );\n // Named in the reader's language, with the same id in every one.\n return { id: UNTITLED_ROOT_ID, text: untitled, level: 0, children: [] };\n};\n\n/** A YAML node's own keys: its text and its children. */\nconst YAML_NODE_VOCABULARY: AttributeVocabulary = {\n keys: ['text', 'children'],\n synonyms: { title: 'text', label: 'text', name: 'text', items: 'children', nodes: 'children', subnodes: 'children' },\n};\n\n/** Keys people (and agents) write for a node's text and its children: read as them when the real key is missing, and reported. */\nconst TEXT_SYNONYMS = ['title', 'name', 'label'];\nconst CHILDREN_SYNONYMS = ['items', 'nodes', 'subnodes'];\n\n/** The key a node's text or children are under: the real one, or a synonym standing in for it. */\nconst misnamedKey = (map: Record<string, unknown>, key: 'text' | 'children', diagnostics: DiagnosticCollector, lineOf: (key: string) => number | undefined): string => {\n if (map[key] !== undefined && map[key] !== null) {\n return key;\n }\n\n const synonym = key === 'text'\n ? TEXT_SYNONYMS.find((candidate) => typeof map[candidate] === 'string' || typeof map[candidate] === 'number')\n : CHILDREN_SYNONYMS.find((candidate) => Array.isArray(map[candidate]));\n\n if (synonym === undefined) {\n return key;\n }\n\n const what = key === 'text' ? 'text goes' : 'children go';\n diagnostics.recover('misnamed-node-key', `A node's ${what} in \"${key}\", not \"${synonym}\": read as its ${key === 'text' ? 'text' : 'children'}. Rename \"${synonym}\" to \"${key}\".`, lineOf(synonym));\n return synonym;\n};\n\n/** Where each node's keys were written, for problems found once the tree is built (links to missing nodes). */\nconst nodeKeyLines = new WeakMap<OrbitNode, (key: string) => number | undefined>();\n\n/** A YAML node, from its map (or plain text); `line` is where its list item starts, for problems Orbit can't place closer. */\nconst buildNode = (raw: unknown, level: number, parent: OrbitNode | undefined, diagnostics: DiagnosticCollector, line?: number): OrbitNode => {\n // Scalar shorthand: a plain string/number/boolean child is its text.\n if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {\n const text = raw === null || Array.isArray(raw) ? '' : String(raw);\n\n if (raw === null || Array.isArray(raw)) {\n diagnostics.note('ignored-node-entry', `Ignored ${Array.isArray(raw) ? 'an array' : 'a null'} node entry: expected a map or plain text.`, line);\n }\n\n const node: OrbitNode = { id: nodeSlug(text), text, level, children: [] };\n setParent(node, parent);\n nodeKeyLines.set(node, () => line);\n return node;\n }\n\n const map = raw as Record<string, unknown>;\n const lineOf = (key: string) => yamlLineOf(map, key) ?? line;\n\n if (map.text !== undefined && map.text !== null && typeof map.text === 'object') {\n diagnostics.recover('invalid-attributes', `text must be a word or a number, not ${Array.isArray(map.text) ? 'a list' : 'a map'}; its text form is used`, lineOf('text'));\n }\n\n if (map.children !== undefined && map.children !== null && !Array.isArray(map.children)) {\n const got = typeof map.children === 'object' ? 'a map' : `\"${String(map.children)}\"`;\n diagnostics.recover('invalid-attributes', `children must be a list of nodes, not ${got}; ignored`, lineOf('children'));\n }\n\n const textKey = misnamedKey(map, 'text', diagnostics, lineOf);\n const childrenKey = misnamedKey(map, 'children', diagnostics, lineOf);\n const node: OrbitNode = {\n id: (typeof map.id === 'string' || typeof map.id === 'number') && String(map.id).trim() !== '' ? String(map.id) : nodeSlug(String(map[textKey] ?? '')),\n text: String(map[textKey] ?? ''),\n level,\n children: [],\n };\n setParent(node, parent);\n nodeKeyLines.set(node, lineOf);\n const entries = Object.entries(map);\n\n for (const [key, value] of entries) {\n if (key === 'text' || key === 'id' || key === 'children' || key === 'caption' || key === textKey || key === childrenKey) {\n continue;\n }\n\n assignNodeAttribute(node, key, value, diagnostics, lineOf(key), YAML_NODE_VOCABULARY);\n }\n\n // A node-level caption applies to the media set above.\n if ('caption' in map) {\n assignNodeAttribute(node, 'caption', map.caption, diagnostics, lineOf('caption'));\n }\n\n const children = map[childrenKey];\n\n if (Array.isArray(children)) {\n children.forEach((child, index) => {\n node.children.push(buildNode(child, level + 1, node, diagnostics, yamlItemLine(children, index) ?? lineOf(childrenKey)));\n });\n }\n\n return node;\n};\n\nconst emptyNode = (): OrbitNode => {\n return { id: 'empty', text: '', level: 0, children: [] };\n};\n",
|
|
21
|
+
"import type { OrbitDocument, ParsedOrbitDocument } from './types.js';\nimport type { ParseOptions } from './parser-markdown.js';\nimport { parseOrbitMarkdown } from './parser-markdown.js';\nimport { parseOrbitYAML } from './parser-yaml.js';\nimport { parseYaml } from './yaml-mini.js';\nimport { DOCUMENT_OPTION_KEYS } from './document-options.js';\nimport { findFrontmatter, firstContentLineIndex, normalizeSource, sharedIndentation } from './source.js';\nimport { documentSource, encodingOf } from './document-source.js';\n\n/**\n * Parses an orbit document in either flavor. Markdown is the default; a\n * document is read as YAML when its first line is a top-level YAML key\n * (`nodes:`, `title:`, `view:`, …), it has a top-level `nodes:` list, or its\n * frontmatter says `flavor: yaml`. A fenced ```orbit block is unwrapped first.\n *\n * Problems the parser can work around are listed in `diagnostics` (each with\n * a `code`, `line`, `severity` and a message that says how to fix it); pass\n * `{ strict: true }` to throw an `OrbitParseError` on the first one instead.\n *\n * @example\n * ```ts\n * import { parseOrbit } from '@restless-dreams/orbit';\n *\n * const { root, diagnostics } = parseOrbit('# Launch\\n## Research <!-- orbit status: active -->');\n * for (const problem of diagnostics ?? []) console.warn(`line ${problem.line}: ${problem.message}`);\n * ```\n */\nexport const parseOrbit = (input: string, options: ParseOptions = {}): ParsedOrbitDocument => {\n const unfenced = stripOrbitFence(input);\n const source = normalizeSource(unfenced);\n const lines = source.split('\\n');\n\n if (chooseFlavor(source, lines) === 'markdown') {\n const document = parseOrbitMarkdown(source, options);\n keepEncoding(document, input, unfenced);\n return document;\n }\n\n const frontmatter = findFrontmatter(lines);\n\n if (frontmatter) {\n // The frontmatter keys join the YAML document. Blanking the fences keeps\n // every line where it was, so diagnostics point at the right line.\n const yamlLines = [...lines];\n yamlLines[frontmatter.openIndex] = '';\n yamlLines[frontmatter.closeIndex] = '';\n return parseOrbitYAML(yamlLines.join('\\n'), options);\n }\n\n return parseOrbitYAML(source, options);\n};\n\n/** The flavor `parseOrbit` reads a document as: `markdown` or `yaml`. */\nexport const orbitFlavor = (input: string): 'markdown' | 'yaml' => {\n const source = normalizeSource(stripOrbitFence(input));\n return chooseFlavor(source, source.split('\\n'));\n};\n\n/**\n * YAML when the document is a YAML map of a map: its first line is\n * `nodes:`, or it reads as YAML with a `nodes:` list, or it starts with one\n * of the map's options and reads as YAML. Markdown with headings, lists or\n * paragraphs doesn't read as a YAML map, so a note that starts with\n * \"nodes:\" or \"title:\" never turns a markdown map into a YAML one.\n */\nconst chooseFlavor = (source: string, lines: string[]): 'markdown' | 'yaml' => {\n const frontmatter = findFrontmatter(lines);\n\n if (frontmatter) {\n return frontmatterFlavor(frontmatter.yaml) === 'yaml' ? 'yaml' : 'markdown';\n }\n\n const firstIndex = firstContentLineIndex(lines);\n\n if (firstIndex === -1) {\n return 'markdown';\n }\n\n const first = lines[firstIndex];\n\n // A plausible YAML `nodes` key: nothing after the colon (a list below), or\n // a flow value or comment. Prose like \"nodes: the points of a graph\" stays markdown.\n if (/^nodes\\s*:\\s*(?:$|[#[{])/.test(first)) {\n return 'yaml';\n }\n\n const startsWithOption = isOptionLine(first);\n\n if (!startsWithOption && !/^nodes\\s*:/m.test(source)) {\n return 'markdown';\n }\n\n let value: unknown;\n\n try {\n value = parseYaml(source);\n } catch {\n // Not YAML at all: markdown, unless it starts like a YAML map with a mistake further down.\n return startsWithOption && /^nodes\\s*:/m.test(source) ? 'yaml' : 'markdown';\n }\n\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return 'markdown';\n }\n\n return Array.isArray((value as Record<string, unknown>).nodes) || startsWithOption ? 'yaml' : 'markdown';\n};\n\n/** A first line like `title: …` or `theme: …`: one of a map's options. */\nconst isOptionLine = (line: string): boolean => {\n const match = /^([A-Za-z][\\w-]*)\\s*:(\\s|$)/.exec(line);\n return match !== null && DOCUMENT_OPTION_KEYS.has(match[1]);\n};\n\n/**\n * Notes how the text was written before it was normalized (line endings, a\n * byte-order mark, shared indentation, a ```` ```orbit ```` fence around\n * it), so saving writes it back the same way.\n */\nconst keepEncoding = (document: OrbitDocument, input: string, unfenced: string): void => {\n const source = documentSource(document);\n\n if (!source) {\n return;\n }\n\n const plain = (text: string) => text.replace(/^\\uFEFF/, '').replace(/\\r\\n?/g, '\\n');\n const fence = unfenced === input ? null : ORBIT_FENCE.exec(input);\n let before: string[] = [];\n let after: string[] = [];\n\n if (fence) {\n // The body starts on the line after the opening fence: indexOf can't be\n // trusted (an empty body, or one repeated in the fence's info string).\n const bodyStart = fence[1].length;\n before = plain(input.slice(0, bodyStart)).split('\\n').slice(0, -1);\n const rest = plain(input.slice(bodyStart + fence[3].length));\n // A body of its own lines ends with a line break before the closing fence.\n after = rest.startsWith('\\n') || rest === '' ? rest.split('\\n').slice(1) : rest.split('\\n');\n }\n\n source.encoding = { ...encodingOf(input), indentation: sharedIndentation(plain(unfenced)), before, after };\n};\n\n/**\n * A document wrapped in a ```` ```orbit ```` fence: the opening line, the\n * fence's kind, the body, then a closing fence of the same kind, indented or\n * not. The info string is `orbit`, alone or followed by display options after\n * a space (```` ```orbit height=480 ````), so ```` ```orbital ```` stays\n * markdown. The body ends before the closing line's break, `\\r\\n` included.\n */\nconst ORBIT_FENCE = /^(\\s*(```|~~~)orbit(?:[^\\S\\n][^\\n]*)?\\n)([\\s\\S]*?)(?:\\r?\\n)?[^\\S\\n]*\\2\\s*$/;\n\nconst stripOrbitFence = (input: string): string => {\n const match = ORBIT_FENCE.exec(input);\n return match ? match[3] : input;\n};\n\nconst frontmatterFlavor = (yaml: string): string | undefined => {\n try {\n const frontmatter = parseYaml(yaml) as Record<string, unknown> | null;\n return frontmatter && typeof frontmatter.flavor === 'string' ? frontmatter.flavor : undefined;\n } catch {\n return undefined;\n }\n};\n",
|
|
22
|
+
"/**\n * How Orbit writes a map as markdown: its own form, the way people write\n * maps. `serializeOrbitMarkdown` writes a whole map this way, and saving an\n * edited map writes its changed ideas this way (see source-patch.ts).\n */\n\nimport type { OrbitDocument, OrbitNode } from './types.js';\nimport { emitYaml, assignKey, plainScalarReadsBack, type YamlValue } from './yaml-mini.js';\nimport { nodesWithExplicitIds } from './utils.js';\nimport { detectVideoProvider } from './media.js';\nimport { isTitleIcon, parseOrbitMarkdown, parseTitle } from './parser-markdown.js';\nimport { mediaExtras } from './node-attributes.js';\n\n/** A whole map in Orbit's own form. */\nexport const writeMarkdown = (doc: OrbitDocument): string => {\n let out = '';\n const fmKeys = collectFrontmatter(doc);\n\n if (Object.keys(fmKeys).length > 0) {\n out += '---\\n' + emitYaml(fmKeys as unknown as YamlValue) + '---\\n\\n';\n }\n\n out += emitHeading(doc.root, 1, { explicitIds: nodesWithExplicitIds(doc.root) });\n return out;\n};\n\nexport const collectFrontmatter = (doc: Pick<OrbitDocument, 'options' | 'extra'>): Record<string, unknown> => {\n const o = doc.options;\n const r: Record<string, unknown> = {};\n\n if (o.title) {\n r.title = o.title;\n }\n\n if (o.theme) {\n r.theme = o.theme;\n }\n\n if (o.viewMode) {\n r.view = o.viewMode;\n }\n\n if (o.showRings !== undefined) {\n r.showRings = o.showRings;\n }\n\n if (o.interactive !== undefined) {\n r.interactive = o.interactive;\n }\n\n if (o.orbitAnimation !== undefined) {\n r.animation = o.orbitAnimation;\n }\n\n if (o.orbitSpeed !== undefined) {\n r.speed = o.orbitSpeed;\n }\n\n if (o.palette) {\n r.palette = o.palette;\n }\n\n if (o.height !== undefined) {\n r.height = o.height;\n }\n\n if (o.maxDepth !== undefined) {\n r.maxDepth = o.maxDepth;\n }\n\n if (o.className) {\n r.className = o.className;\n }\n\n if (o.baseUrl) {\n r.baseUrl = o.baseUrl;\n }\n\n if (o.schemaVersion !== undefined) {\n r.schemaVersion = o.schemaVersion;\n }\n\n // Keys Orbit doesn't read, after its own: as they were written.\n for (const [key, value] of Object.entries(doc.extra ?? {})) {\n if (!Object.prototype.hasOwnProperty.call(r, key)) {\n assignKey(r, key, value);\n }\n }\n\n return r;\n};\n\n/**\n * The root and its children are headings; everything under them is a\n * list, the way people write maps. Below two levels, headings would only\n * make a map harder to read.\n */\nexport const HEADING_LEVELS = 2;\n\n/** The statuses a list item writes as a checkbox. */\nexport const CHECKBOXES: Record<string, string> = { todo: '[ ]', done: '[x]', active: '[/]' };\n\n/** What writing a node needs besides the node: which ids to write. */\nexport interface Writing {\n /** The nodes whose ids the parsers wouldn't make from their text, so they are written. */\n explicitIds: ReadonlySet<OrbitNode>;\n}\n\nexport const emitHeading = (node: OrbitNode, level: number, writing: Writing): string => {\n const parts = nodeParts(node, false, writing, '');\n const out = `${'#'.repeat(level)} ${parts.line}\\n${parts.body}`;\n\n if (node.children.length === 0) {\n return out;\n }\n\n if (level < HEADING_LEVELS) {\n return out + node.children.map((child) => `\\n${emitHeading(child, level + 1, writing)}`).join('');\n }\n\n return out + emitList(node.children, '', writing);\n};\n\nexport const emitList = (children: OrbitNode[], indent: string, writing: Writing): string => {\n let out = '';\n\n for (const child of children) {\n const parts = nodeParts(child, true, writing, `${indent} `);\n out += `${indent}- ${parts.line}\\n${parts.body}`;\n out += emitList(child.children, `${indent} `, writing);\n }\n\n return out;\n};\n\n/**\n * A node as written: its line after the heading's `#`s or the item's\n * marker (title, then the attributes that fit on it), and what follows the\n * line, indented by `indent`.\n */\nexport const nodeParts = (node: OrbitNode, listItem: boolean, writing: Writing, indent: string): { line: string; title: string; inline: string; body: string } => {\n const pieces = nodePieces(node, listItem, writing, indent);\n return { line: `${pieces.title}${pieces.inline}`.trimStart(), title: pieces.title, inline: pieces.inline, body: pieces.attributes + pieces.media + pieces.note };\n};\n\n/** The pieces of a node as written, each ending with a line break (or empty): see `nodeParts`. */\nexport interface NodePieces {\n title: string;\n\n /** The attributes on the title line, with the space before them; empty when they don't fit there. */\n inline: string;\n\n /** The attributes that didn't fit on the line, as a block of their own. */\n attributes: string;\n\n media: string;\n note: string;\n}\n\nexport const nodePieces = (node: OrbitNode, listItem: boolean, writing: Writing, indent: string): NodePieces => {\n const { title, attributes } = titleLine(node, listItem, writing);\n let inline = inlineAttributes(attributes);\n let block = inline ? {} : attributes;\n\n if (title === '' && inline === '') {\n // A line without a title only reads back with an attribute on it: the id, at least.\n inline = ` <!-- orbit id: ${inlineValue(node.id) ?? JSON.stringify(node.id)} -->`;\n block = Object.fromEntries(Object.entries(attributes).filter(([key]) => key !== 'id'));\n }\n\n return {\n title,\n inline,\n attributes: attributeBlock(block, indent),\n media: indentLines(renderMedia(node).trimEnd(), indent),\n note: noteLines(node, indent),\n };\n};\n\n/**\n * A node's title as written: a checkbox for a list item's status, its\n * icon, its text, its link around them and its tags as hashtags, with the\n * attributes those don't carry.\n */\n/** A link markdown can hold in a title, `[text](link)`: no spaces, parentheses, quotes, angle brackets or backslashes. */\nconst isTitleLink = (link: string): boolean => {\n return /^[^\\s()<>\"'\\\\]+$/.test(link);\n};\n\nexport const titleLine = (node: OrbitNode, listItem: boolean, writing: Writing): { title: string; attributes: Record<string, unknown> } => {\n const attributes = collectAttrs(node, writing.explicitIds);\n let title = escapeTitle(node.text);\n const linked = node.link !== undefined && isTitleLink(node.link);\n\n if (linked && title === node.text) {\n // Inside the link's brackets, brackets of the text's own would end it.\n title = title.replace(/[[\\]]/g, '\\\\$&');\n }\n\n if (node.icon && isTitleIcon(node.icon)) {\n title = `${node.icon} ${title}`;\n }\n\n if (linked) {\n title = `[${title}](${node.link})`;\n }\n\n const checkbox = listItem && node.status ? CHECKBOXES[node.status] : undefined;\n\n if (checkbox) {\n title = `${checkbox} ${title}`;\n delete attributes.status;\n }\n\n if (node.tags?.length && node.tags.every(isHashtag)) {\n title += node.tags.map((tag) => ` #${tag}`).join('');\n delete attributes.tags;\n }\n\n return { title, attributes };\n};\n\n/** Whether a tag reads back as a hashtag at the end of a title. */\nconst isHashtag = (tag: string): boolean => {\n return /^[\\p{L}\\p{N}_][\\p{L}\\p{N}_/-]*$/u.test(tag) && /\\p{L}/u.test(tag);\n};\n\n/** The longest comment of more than `INLINE_ENTRIES` attributes that still goes on the node's line. */\nconst INLINE_LENGTH = 80;\n/** Up to this many attributes go on the node's line however long their values are, within `inlineValue`'s limit. */\nconst INLINE_ENTRIES = 3;\n\n/**\n * Attributes on the node's own line, `<!-- orbit status: done, priority: 2 -->`,\n * when they are short, plain values: up to three of them, or more while the\n * comment stays short, as a goal's numbers are (`type: goal, target: 5,\n * current: 2, unit: apples`). Keys that wouldn't survive the comma-separated\n * form (with a quote, a comma, a colon or a space of their own) go to the\n * block form instead.\n */\nexport const inlineAttributes = (attributes: Record<string, unknown>): string => {\n const entries = Object.entries(attributes);\n\n if (entries.length === 0 || !entries.every(([key, value]) => INLINE_KEY.test(key) && inlineValue(value) !== null)) {\n return '';\n }\n\n const comment = ` <!-- orbit ${entries.map(([key, value]) => `${key}: ${inlineValue(value)}`).join(', ')} -->`;\n return entries.length <= INLINE_ENTRIES || comment.length <= INLINE_LENGTH ? comment : '';\n};\n\n/** A key the comma-separated inline form reads back: what its pair pattern accepts. */\nconst INLINE_KEY = /^[A-Za-z][\\w-]*$/;\n\nexport const inlineValue = (value: unknown): string | null => {\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n\n if (typeof value !== 'string' || value.length > 60 || /[\\r\\n]|--/.test(value)) {\n return null;\n }\n\n // Quoted when the parser wouldn't hand it back plain, when it holds a\n // character the inline form itself reads (a comma splits attributes, a\n // quote toggles them, a bracket or brace nests so the comma after it\n // doesn't split, \":\" and \"#\" are syntax anywhere they appear), or when it\n // starts like a number (`2026-11-01` reads as text, but plain it would look\n // like one).\n return plainScalarReadsBack(value) && !/[\"',:#[\\]{}]/.test(value) && !/^-?\\d/.test(value) ? value : JSON.stringify(value);\n};\n\n/** What follows a node's line, indented under a list item: attributes that didn't fit on the line, media, then the note. */\nexport const body = (node: OrbitNode, blockAttributes: Record<string, unknown>, indent: string): string => {\n return attributeBlock(blockAttributes, indent) + indentLines(renderMedia(node).trimEnd(), indent) + noteLines(node, indent);\n};\n\n/** Attributes as a `<!-- orbit … -->` block of their own, indented by `indent`; nothing when there are none. */\nexport const attributeBlock = (attributes: Record<string, unknown>, indent: string): string => {\n return Object.keys(attributes).length > 0 ? indentLines(`<!-- orbit\\n${commentYaml(attributes)}\\n-->`, indent) : '';\n};\n\n/** A node's note as written under it, indented by `indent`. */\nexport const noteLines = (node: OrbitNode, indent: string): string => {\n return node.note ? indentLines(noteText(node.note, indent !== ''), indent) : '';\n};\n\n/**\n * A note as paragraphs when they read back as the same note, otherwise\n * quoted: quoted lines never turn into nodes, so a note can hold lines that\n * look like headings, lists or media.\n */\nexport const noteText = (note: string, listItem: boolean): string => {\n return plainNoteReadsBack(note, listItem) ? note : note.split('\\n').map((line) => (line === '' ? '>' : `> ${line}`)).join('\\n');\n};\n\n/**\n * Whether a note written as plain paragraphs reads back as the same note,\n * and leaves what follows it alone: a node after it must still be a node\n * (an unclosed code fence, say, would swallow it).\n */\nconst plainNoteReadsBack = (note: string, listItem: boolean): boolean => {\n // Indentation inside a list item is measured against its other lines: quoted, it stays exact.\n if (/^[ \\t]/m.test(note)) {\n return false;\n }\n\n const source = listItem\n ? `# Map\\n\\n## Branch\\n- Node\\n${indentLines(note, ' ')} - Next\\n- After\\n`\n : `# Map\\n\\n## Node\\n${note}\\n- Next\\n\\n## After\\n`;\n const document = parseOrbitMarkdown(source);\n const branches = document.root.children;\n const node = listItem ? branches[0]?.children[0] : branches[0];\n const after = listItem ? branches[0]?.children[1] : branches[1];\n\n if (!node || node.note !== note || node.children.length !== 1 || node.children[0].text !== 'Next' || after?.text !== 'After') {\n return false;\n }\n\n // Nothing in the note may read as the node's own attributes or media.\n const read = new Set(['id', 'text', 'level', 'children', 'source', 'note']);\n return Object.entries(node).every(([key, value]) => read.has(key) || value === undefined || (key === 'noteFormat' && value === 'markdown'));\n};\n\nexport const indentLines = (text: string, indent: string): string => {\n if (text === '') {\n return '';\n }\n\n return `${text.split('\\n').map((line) => (line === '' ? '' : `${indent}${line}`)).join('\\n')}\\n`;\n};\n\n/** Characters a title reads as markup: emphasis, code, links, checkboxes, hashtags. */\nconst TITLE_MARKUP = /[\\\\`*_~[\\]#<]/g;\n\n/**\n * A node's text as a heading or list item title: as is when it reads back\n * unchanged, otherwise with its markup characters escaped.\n */\nexport const escapeTitle = (text: string): string => {\n // A comment would be read as attributes, and a closing `#` run dropped from a heading.\n const misread = /<!--/.test(text) || /\\s#+$/.test(text) || !readsBack(text);\n return misread ? text.replace(TITLE_MARKUP, '\\\\$&') : text;\n};\n\nconst readsBack = (text: string): boolean => {\n const parts = parseTitle(text);\n return parts.text === text && parts.icon === undefined && parts.link === undefined && parts.tags === undefined && parts.status === undefined;\n};\n\n/**\n * A node's media as markdown lines, each followed (when needed) by an\n * attribute comment carrying what the line form cannot express: an explicit\n * `contentType` when auto-detection would misclassify, and the caption.\n */\n/** Media a markdown line can hold: plain addresses, and alt text without brackets. Others go in the attributes. */\nconst fitsOnALine = (media: { src: string; alt?: string; thumbnail?: string; provider?: string }): boolean => {\n // A media line reads its provider back from the address: one set differently would be rewritten.\n const providerKept = media.provider === undefined || media.provider === (detectVideoProvider(media.src) ?? 'native');\n return providerKept && isTitleLink(media.src) && (media.thumbnail === undefined || isTitleLink(media.thumbnail)) && !/[[\\]\\n]/.test(media.alt ?? '')\n && mediaExtras(media) === undefined;\n};\n\n/** A media value as an attribute: its defined fields, and a video's provider only when its address doesn't say it. */\nconst mediaAttribute = (media: { src: string; alt?: string; caption?: string; thumbnail?: string; provider?: string }): Record<string, unknown> => {\n // Fields Orbit doesn't read go first, as written; Orbit's own follow.\n const value: Record<string, unknown> = { src: media.src, ...mediaExtras(media) };\n\n for (const key of ['alt', 'thumbnail', 'caption'] as const) {\n if (media[key] !== undefined) {\n value[key] = media[key];\n }\n }\n\n if (media.provider !== undefined && media.provider !== (detectVideoProvider(media.src) ?? 'native')) {\n value.provider = media.provider;\n }\n\n return value;\n};\n\nexport const renderMedia = (node: OrbitNode): string => {\n let out = '';\n\n if (node.image && fitsOnALine(node.image)) {\n out += `\\n`;\n out += mediaMarker(undefined, node.image.caption);\n }\n\n if (node.video && fitsOnALine(node.video)) {\n const v = node.video;\n const detected = detectVideoProvider(v.src);\n out += v.thumbnail ? `[](${v.src})\\n` : `[video](${v.src})\\n`;\n out += mediaMarker(detected === null ? 'video' : undefined, v.caption);\n }\n\n if (node.embed && fitsOnALine(node.embed)) {\n out += `[embed](${node.embed.src})\\n`;\n out += mediaMarker('embed', node.embed.caption);\n }\n\n return out;\n};\n\nconst mediaMarker = (contentType: 'video' | 'embed' | undefined, caption: string | undefined): string => {\n const fields: Record<string, unknown> = {};\n\n if (contentType) {\n fields.contentType = contentType;\n }\n\n if (caption !== undefined) {\n fields.caption = caption;\n }\n\n if (Object.keys(fields).length === 0) {\n return '';\n }\n\n const yaml = commentYaml(fields);\n return yaml.includes('\\n') ? `<!-- orbit\\n${yaml}\\n-->\\n` : `<!-- orbit ${yaml} -->\\n`;\n};\n\n/**\n * YAML to write inside an HTML comment. A \"-->\" in a value would end the\n * comment early, so its \">\" is written as an escape; strings holding one are\n * always double-quoted, where the escape reads back as \">\".\n */\nexport const commentYaml = (value: Record<string, unknown>): string => {\n return emitYaml(value as unknown as YamlValue).trimEnd().replace(/--(!?)>/g, '--$1\\\\u003e');\n};\n\n/** Attributes carried in `<!-- orbit ... -->` comments: the ones a node's title and lines don't show. */\nexport const collectAttrs = (node: OrbitNode, explicitIds: ReadonlySet<OrbitNode>): Record<string, unknown> => {\n const r: Record<string, unknown> = {};\n\n if (node.icon && !isTitleIcon(node.icon)) {\n r.icon = node.icon;\n }\n\n if (node.color) {\n r.color = node.color;\n }\n\n if (node.paletteColor !== undefined) {\n r.paletteColor = node.paletteColor;\n }\n\n if (node.status) {\n r.status = node.status;\n }\n\n if (node.priority !== undefined) {\n r.priority = node.priority;\n }\n\n if (node.tags) {\n r.tags = node.tags;\n }\n\n if (node.collapsed !== undefined) {\n r.collapsed = node.collapsed;\n }\n\n if (node.type) {\n r.type = node.typeVersion === undefined ? node.type : `${node.type}@${node.typeVersion}`;\n }\n\n if (node.link && !isTitleLink(node.link)) {\n r.link = node.link;\n }\n\n for (const key of ['image', 'video', 'embed'] as const) {\n const media = node[key];\n\n if (media && !fitsOnALine(media)) {\n r[key] = mediaAttribute(media);\n }\n }\n\n if (node.noteFormat && node.noteFormat !== 'markdown' && node.note) {\n r.noteFormat = node.noteFormat;\n }\n\n if (explicitIds.has(node)) {\n r.id = node.id;\n }\n\n if (node.attrs) {\n for (const [k, v] of Object.entries(node.attrs)) {\n // A value Orbit couldn't read for one of its own attributes is written back, unless one was set since.\n if (!Object.prototype.hasOwnProperty.call(r, k)) {\n assignKey(r, k, v);\n }\n }\n }\n\n return r;\n};\n",
|
|
23
|
+
"/**\n * Saving an edited map without rewriting it. Every line an edit didn't\n * change is written back as it was, and only what changed is written again,\n * in place, in Orbit's own form: a renamed idea gets a new title, a moved\n * one takes its lines along. A map written by hand, or by another app,\n * keeps its formatting and everything Orbit doesn't read: other HTML\n * comments, rules, the frontmatter keys of other apps.\n *\n * The result is read back before it's used: when it doesn't read as the\n * edited map, saving falls back to rewriting the changed ideas whole, then\n * to Orbit's own form for the whole map.\n */\n\nimport type { OrbitDocument, OrbitDocumentOptions, OrbitNode } from './types.js';\nimport { nodeFields, type DocumentSource, type LineRole, type NodeFields, type NodeRecord, type NodeShape } from './document-source.js';\nimport { CHECKBOXES, collectFrontmatter, HEADING_LEVELS, nodePieces, renderMedia, titleLine, type NodePieces, type Writing } from './markdown-writing.js';\nimport { emitYaml, type YamlValue } from './yaml-mini.js';\nimport { nodesWithExplicitIds } from './utils.js';\nimport { parseOrbit } from './dispatch.js';\nimport { UNTITLED_ROOT_ID } from './parser-markdown.js';\n\n/** Where a node is written: as a heading of a level, a list item at a column, or as the made-up root. */\ntype Context =\n | { kind: 'heading'; level: number }\n | { kind: 'item'; indent: number; marker: string }\n | { kind: 'generated' };\n\n/** Lines of a node's own, in a row, with one role: after which of its children they come (-1: before them all). */\ninterface Run {\n from: number;\n to: number;\n role: LineRole;\n after: number;\n}\n\n/** What an edit changed in a node's own lines. */\ninterface Changes {\n title: boolean;\n attributes: boolean;\n media: boolean;\n note: boolean;\n}\n\n/** Thrown when the map can't be written by patching; saving falls back to the next way. */\nclass CannotPatch extends Error {}\n\n/**\n * The document as markdown, its source's lines kept wherever nothing\n * changed; null when that can't be done faithfully.\n */\nexport const patchMarkdown = (document: OrbitDocument, source: DocumentSource): string | null => {\n if (document.root !== source.root) {\n return null;\n }\n\n for (const coarse of [false, true]) {\n const patcher = new Patcher(document, source, coarse);\n let lines: string[];\n\n try {\n lines = patcher.write();\n } catch (error) {\n if (error instanceof CannotPatch) {\n continue;\n }\n\n throw error;\n }\n\n const text = encode(lines, source);\n\n // The made-up root's new name may be written as the title option. A document without extra keys of its own\n // keeps the ones its file has, so that's what the text should read back with.\n if (lines === source.lines || readsAs(text, { ...document, options: patcher.writtenOptions, extra: document.extra ?? source.extra })) {\n return text;\n }\n }\n\n return null;\n};\n\n/**\n * The patched text without checking that it reads back, or why it couldn't\n * be made: for tests and debugging.\n */\nexport const patchedText = (document: OrbitDocument, source: DocumentSource, coarse = false): string => {\n return encode(new Patcher(document, source, coarse).write(), source);\n};\n\n/**\n * Whether `text` reads back as the `expected` map: the same options and\n * keys, and the same tree, each node with the same id and the same\n * fields, as Orbit would write them.\n */\nconst readsAs = (text: string, expected: OrbitDocument): boolean => {\n let read: OrbitDocument;\n\n try {\n // A made-up root keeps its id in every language: read it back with the name it was given.\n read = parseOrbit(text, { untitled: expected.root.id === UNTITLED_ROOT_ID ? expected.root.text : undefined });\n } catch {\n return false;\n }\n\n if (JSON.stringify(collectFrontmatter(read)) !== JSON.stringify(collectFrontmatter(expected))) {\n return false;\n }\n\n const readIds = nodesWithExplicitIds(read.root);\n const expectedIds = nodesWithExplicitIds(expected.root);\n const same = (left: OrbitNode, right: OrbitNode): boolean =>\n left.id === right.id\n && JSON.stringify(describe(left, false, readIds.has(left))) === JSON.stringify(describe(right, false, expectedIds.has(right)))\n && left.children.length === right.children.length\n && left.children.every((child, index) => same(child, right.children[index]));\n return same(read.root, expected.root);\n};\n\n/** Lines written as the source was: its line endings, byte-order mark, indentation and wrapping. */\nconst encode = (lines: string[], source: DocumentSource): string => {\n const { encoding } = source;\n const indented = encoding.indentation ? lines.map((line) => (line.trim() === '' ? line : encoding.indentation + line)) : lines;\n const text = [...encoding.before, ...indented, ...encoding.after].join(encoding.lineEnding);\n return encoding.byteOrderMark ? `\\uFEFF${text}` : text;\n};\n\nclass Patcher {\n private readonly lines: string[];\n private readonly records: WeakMap<OrbitNode, NodeRecord>;\n private readonly writing: Writing;\n private readonly cleanness = new Map<OrbitNode, boolean>();\n private readonly document: OrbitDocument;\n private readonly source: DocumentSource;\n\n /** Rewrite changed ideas whole, instead of only their changed lines. */\n private readonly coarse: boolean;\n\n /** The node whose own lines are being written. */\n private current: OrbitNode | null = null;\n\n /** The options the frontmatter was written with. */\n writtenOptions: OrbitDocumentOptions = {};\n\n /** Whether the made-up root is written as a heading of its own. */\n private rootHeading = false;\n\n constructor(document: OrbitDocument, source: DocumentSource, coarse: boolean) {\n this.document = document;\n this.source = source;\n this.coarse = coarse;\n this.lines = source.lines;\n this.records = source.records;\n this.writing = { explicitIds: nodesWithExplicitIds(document.root) };\n }\n\n write(): string[] {\n const root = this.document.root;\n const record = this.record(root);\n this.rootHeading = record.shape.kind === 'generated' && this.becomesHeading(root, record);\n const options = this.options();\n this.writtenOptions = options;\n const optionsChanged = JSON.stringify(this.frontmatterKeys(options)) !== JSON.stringify(this.frontmatterKeys(this.source.options, this.source.extra));\n\n if (!optionsChanged && this.isClean(root)) {\n return this.lines;\n }\n\n const out = this.frontmatter(options);\n const body: string[] = [];\n const context: Context = this.rootHeading ? { kind: 'heading', level: 1 } : contextOf(record.shape);\n this.emit(root, context, body);\n\n // A frontmatter that went takes the blank line that kept it apart with it: the map starts at its first line.\n if (this.source.frontmatter && out.length === 0) {\n while (body.length > 0 && body[0].trim() === '') {\n body.shift();\n }\n }\n\n out.push(...body);\n\n // A file that ended with a line break still does.\n if (this.lines[this.lines.length - 1] === '' && out[out.length - 1] !== '') {\n out.push('');\n }\n\n return out;\n }\n\n /**\n * Whether the root Orbit made up gets a heading of its own: when it's\n * renamed, or its attributes or media change (a heading line is where they\n * go), or a map of only text gets its first idea. Not when its children are\n * top-level headings themselves: a heading above them would change their\n * levels, so a new name goes to the frontmatter's title instead.\n */\n private becomesHeading(root: OrbitNode, record: NodeRecord): boolean {\n if (record.children.some((child) => this.records.get(child)?.shape.kind === 'heading')) {\n return false;\n }\n\n if (record.children.length === 0 && root.children.length > 0) {\n return true;\n }\n\n const changes = this.changes(root, record, this.ownRuns(root, record));\n return changes.title || changes.attributes || changes.media;\n }\n\n /** The options to write: the document's, with the made-up root's new name as its title when it has no heading. */\n private options(): OrbitDocumentOptions {\n const options = { ...this.document.options };\n const root = this.document.root;\n const record = this.record(root);\n\n if (record.shape.kind === 'generated' && !this.rootHeading && root.text !== record.fields.text) {\n options.title = root.text;\n }\n\n return options;\n }\n\n private record(node: OrbitNode): NodeRecord {\n const record = this.records.get(node);\n\n if (!record) {\n throw new CannotPatch('A node without a record');\n }\n\n return record;\n }\n\n /** Whether a node and everything under it are as they were read. */\n private isClean(node: OrbitNode): boolean {\n let clean = this.cleanness.get(node);\n\n if (clean === undefined) {\n const record = this.records.get(node);\n clean = record !== undefined\n && this.ownUnchanged(node, record)\n && sameChildren(node.children, record.children)\n && node.children.every((child) => this.isClean(child));\n this.cleanness.set(node, clean);\n }\n\n return clean;\n }\n\n private ownUnchanged(node: OrbitNode, record: NodeRecord): boolean {\n return JSON.stringify(nodeFields(node)) === JSON.stringify(record.fields) && this.writing.explicitIds.has(node) === record.explicitId;\n }\n\n // Frontmatter\n\n /**\n * The frontmatter's keys and values for `options`, with the keys Orbit\n * doesn't read (`extra`, by default the document's): other apps' keys, and\n * keys an app keeps there itself, are saved when they change too. A\n * document without `extra` changes none of them: one built from a tree and\n * options alone would otherwise drop every key another app wrote, so only\n * an `extra` object, even an empty one, removes keys.\n */\n private frontmatterKeys(options: OrbitDocumentOptions, extra = this.document.extra ?? this.source.extra): Record<string, unknown> {\n return collectFrontmatter({ options, extra });\n }\n\n /** The frontmatter, with the keys whose values changed written again and the rest as they were. */\n private frontmatter(options: OrbitDocumentOptions): string[] {\n const fences = this.source.frontmatter;\n const before = this.frontmatterKeys(this.source.options, this.source.extra);\n const after = this.frontmatterKeys(options);\n const lines = fences ? this.lines.slice(0, fences.close + 1) : [];\n const keys = [...new Set([...Object.keys(before), ...Object.keys(after)])];\n const changed = keys.filter((key) => JSON.stringify(before[key]) !== JSON.stringify(after[key]));\n\n if (changed.length === 0) {\n return fences ? lines : this.lines.slice(0, this.bodyStart());\n }\n\n if (!fences) {\n const written = Object.fromEntries(Object.entries(after));\n return ['---', ...yamlLines(written), '---', '', ...this.lines.slice(0, this.bodyStart())];\n }\n\n const open = fences.open;\n let close = fences.close;\n\n for (const key of changed) {\n const range = keyRange(lines, key, open + 1, close);\n const replacement = after[key] === undefined ? [] : yamlLines({ [key]: after[key] });\n\n if (range) {\n lines.splice(range.from, range.to - range.from, ...replacement);\n close += replacement.length - (range.to - range.from);\n } else {\n lines.splice(close, 0, ...replacement);\n close += replacement.length;\n }\n }\n\n // A frontmatter left with nothing in it goes.\n if (lines.slice(open + 1, close).every((line) => line.trim() === '')) {\n lines.splice(open, close - open + 1);\n }\n\n return lines;\n }\n\n private bodyStart(): number {\n const fences = this.source.frontmatter;\n return fences ? fences.close + 1 : 0;\n }\n\n // Nodes\n\n /** Writes `node` and everything under it, as `context` asks, into `out`. */\n private emit(node: OrbitNode, context: Context, out: string[]): void {\n const record = this.records.get(node);\n\n if (!record) {\n this.generate(node, context, out);\n return;\n }\n\n if (this.isClean(node) && sameContext(record.shape, context) && record.contiguous) {\n // An underlined heading needs a blank line before it, or its text would join the paragraph above.\n if (record.shape.kind === 'heading' && record.shape.setext && this.lines[record.start]?.trim() !== '') {\n separate(out);\n }\n\n const lines = this.lines.slice(record.start, record.end);\n\n // An indented heading starts at the margin: with what's around it written again, a list item before it could take it.\n if (context.kind === 'heading' && record.titleLine !== null) {\n const index = record.titleLine - record.start;\n lines[index] = lines[index].replace(/^ {1,3}(?=#)/, '');\n }\n\n out.push(...lines);\n return;\n }\n\n const runs = this.ownRuns(node, record);\n const changes = this.changes(node, record, runs);\n this.current = node;\n const kindChanged = record.shape.kind !== context.kind;\n const pieces = nodePieces(node, context.kind === 'item', this.writing, ' '.repeat(contentColumn(record.shape, context)));\n const head = runs.filter((run) => run.after < 0);\n\n if (kindChanged && record.shape.kind !== 'generated') {\n this.rewriteOwn(record, context, pieces, runs, out);\n } else {\n this.patchOwn(record, context, pieces, head, changes, out);\n }\n\n this.emitChildren(node, record, context, runs, changes, out);\n }\n\n /** The lines a node owns, in runs of one role. */\n private ownRuns(node: OrbitNode, record: NodeRecord): Run[] {\n const starts = record.children.map((child) => this.record(child).start);\n const runs: Run[] = [];\n\n for (let line = record.start; line < record.end; line += 1) {\n if (this.source.owners[line] !== node) {\n continue;\n }\n\n const role = this.source.roles[line];\n let after = -1;\n\n while (after + 1 < starts.length && starts[after + 1] <= line) {\n after += 1;\n }\n\n const last = runs[runs.length - 1];\n\n if (last && last.to === line && last.role === role && last.after === after) {\n last.to = line + 1;\n } else {\n runs.push({ from: line, to: line + 1, role, after });\n }\n }\n\n return runs;\n }\n\n private changes(node: OrbitNode, record: NodeRecord, runs: Run[]): Changes {\n const listItem = record.shape.kind === 'item';\n const before = describe(asNode(record.fields), listItem, record.explicitId);\n const after = describe(node, listItem, this.writing.explicitIds.has(node));\n const changes: Changes = {\n title: before.title !== after.title,\n attributes: before.attributes !== after.attributes,\n media: before.media !== after.media,\n note: before.note !== after.note,\n };\n // A note written (partly) as a `note:` attribute is written again as text whenever either changes.\n const noteAttribute = /(^|[\\s,])note\\s*:/;\n const titleComment = record.titleLine === null ? '' : (INLINE_COMMENT.exec(this.lines[record.titleLine]) ?? [''])[0];\n\n if (runs.some((run) => run.role === 'attributes' && noteAttribute.test(this.text(run))) || noteAttribute.test(titleComment)) {\n if (changes.note || changes.attributes) {\n changes.note = true;\n changes.attributes = true;\n }\n }\n\n if (this.coarse && Object.values(changes).some(Boolean)) {\n return { title: true, attributes: true, media: true, note: true };\n }\n\n return changes;\n }\n\n private text(run: Run): string {\n return this.lines.slice(run.from, run.to).join('\\n');\n }\n\n /**\n * A node's own lines with what changed written again in place: a new\n * title on its line, new attributes after it, media and note where the old\n * ones were. Everything else, including what Orbit doesn't read, stays.\n */\n private patchOwn(record: NodeRecord, context: Context, pieces: NodePieces, head: Run[], changes: Changes, out: string[]): void {\n const shift = indentShift(record.shape, context);\n const own: string[] = [];\n let afterTitle = 0;\n let wroteAttributes = false;\n let wroteMedia = false;\n let wroteNote = false;\n const generated = record.shape.kind === 'generated';\n\n // The made-up root that becomes a heading: its line goes first.\n if (generated && context.kind === 'heading') {\n own.push(`${'#'.repeat(context.level)} ${`${pieces.title}${pieces.inline}`.trimStart()}`);\n afterTitle = own.length;\n\n if (pieces.attributes) {\n own.push(...splitLines(pieces.attributes));\n afterTitle = own.length;\n }\n\n wroteAttributes = true;\n }\n\n for (const run of head) {\n const lines = this.lines.slice(run.from, run.to);\n\n switch (run.role) {\n case 'title': {\n if (generated) {\n // A lead paragraph names the root. Once the root has a heading, or a new name in the frontmatter, it goes.\n if (context.kind !== 'heading' && !changes.title) {\n own.push(...lines);\n }\n\n afterTitle = own.length;\n break;\n }\n\n own.push(...this.patchTitle(lines, record, context, pieces, changes));\n afterTitle = own.length;\n\n if (changes.attributes && pieces.attributes) {\n own.push(...splitLines(pieces.attributes));\n afterTitle = own.length;\n }\n\n wroteAttributes = true;\n break;\n }\n case 'attributes':\n if (!changes.attributes) {\n own.push(...shiftLines(lines, shift));\n }\n\n break;\n case 'media':\n if (!changes.media) {\n own.push(...shiftLines(lines, shift));\n } else if (!wroteMedia) {\n own.push(...splitLines(pieces.media));\n wroteMedia = true;\n }\n\n break;\n case 'note':\n case 'end':\n if (!changes.note) {\n own.push(...shiftLines(lines, shift));\n } else if (!wroteNote) {\n own.push(...splitLines(pieces.note));\n wroteNote = true;\n }\n\n break;\n default:\n own.push(...shiftLines(lines, shift));\n }\n }\n\n // A generated root has no title line: its attributes go first, on lines of their own.\n if (changes.attributes && !wroteAttributes && pieces.attributes) {\n own.splice(afterTitle, 0, ...splitLines(pieces.attributes));\n afterTitle += splitLines(pieces.attributes).length;\n }\n\n if (changes.media && !wroteMedia && pieces.media) {\n own.splice(afterTitle, 0, ...splitLines(pieces.media));\n }\n\n if (changes.note && !wroteNote && pieces.note) {\n let end = own.length;\n\n while (end > afterTitle && own[end - 1].trim() === '') {\n end -= 1;\n }\n\n const note = splitLines(pieces.note);\n // Between a heading and its note, a blank line, as Orbit writes them.\n own.splice(end, 0, ...note);\n }\n\n // A heading the root just got, or an underlined one, needs a blank line before it; others are kept as written.\n const blankBefore = record.shape.kind !== 'heading' || (record.shape.setext && own[0] === this.lines[record.titleLine ?? -1]);\n\n if (context.kind === 'heading' && own.length > 0 && own[0].trim() !== '' && blankBefore) {\n separate(out);\n }\n\n out.push(...own);\n }\n\n /** A node that changed between heading and list item: its own lines written again, keeping what Orbit doesn't read. */\n private rewriteOwn(record: NodeRecord, context: Context, pieces: NodePieces, runs: Run[], out: string[]): void {\n if (context.kind === 'heading') {\n separate(out);\n out.push(`${'#'.repeat(context.level)} ${`${pieces.title}${pieces.inline}`.trimStart()}`);\n } else if (context.kind === 'item') {\n out.push(`${' '.repeat(context.indent)}${markerOf(record.shape, context)} ${`${pieces.title}${pieces.inline}`.trimStart()}`);\n } else {\n throw new CannotPatch('A node can only become the root by being it');\n }\n\n out.push(...splitLines(pieces.attributes + pieces.media + pieces.note));\n const column = contentColumn(record.shape, context);\n\n for (const run of runs) {\n if (run.role === 'foreign') {\n out.push(...this.lines.slice(run.from, run.to).map((line) => ' '.repeat(column) + line.trimStart()));\n }\n }\n }\n\n /** The title line, with its new title, attributes, level or indentation. */\n private patchTitle(lines: string[], record: NodeRecord, context: Context, pieces: NodePieces, changes: Changes): string[] {\n const shape = record.shape;\n const fresh = `${pieces.title}${pieces.inline}`.trimStart();\n\n if (shape.kind === 'heading' && context.kind === 'heading') {\n const match = ATX.exec(lines[0]);\n\n if (shape.setext || !match) {\n return !changes.title && !changes.attributes && shape.level === context.level ? lines : [`${'#'.repeat(context.level)} ${fresh}`];\n }\n\n // Written again, a heading starts at the margin: indented, a list item before it could take it.\n return [`${'#'.repeat(context.level)}${match[3]}${this.titleText(match[4], record, pieces, changes)}`];\n }\n\n if (shape.kind === 'item' && context.kind === 'item') {\n const match = ITEM.exec(lines[0]);\n\n if (!match) {\n return [`${' '.repeat(context.indent)}${shape.marker} ${fresh}`];\n }\n\n const indent = context.indent === shape.indent ? match[1] : ' '.repeat(context.indent);\n return [`${indent}${match[2]}${match[3]}${this.titleText(match[4], record, pieces, changes)}`];\n }\n\n throw new CannotPatch('A title line of another kind');\n }\n\n /** A title line's text after its marker: the title and the attributes on it, each kept unless it changed. */\n private titleText(text: string, record: NodeRecord, pieces: NodePieces, changes: Changes): string {\n const inline = INLINE_COMMENT.exec(text);\n let title = inline ? text.slice(0, inline.index) : text;\n const comment = changes.attributes ? pieces.inline : inline ? text.slice(inline.index) : '';\n\n // A heading's closing `#`s only close it at the end of its line: before a comment, they'd join its title.\n if (record.shape.kind === 'heading' && comment) {\n title = title.replace(/\\s+#+\\s*$/, '');\n }\n\n const hidden = changes.title ? TRAILING_COMMENTS.exec(title) : null;\n const bare = hidden ? title.slice(0, hidden.index) : title;\n const written = `${changes.title ? `${this.retitle(bare, record, pieces)}${hidden ? hidden[0].trimEnd() : ''}` : title}${comment}`;\n return written.trimStart();\n }\n\n /**\n * A changed title. When only a list item's checkbox changed (an idea\n * checked off, say), only the checkbox is written again, so the title\n * keeps its own markdown: bold, code, links.\n */\n private retitle(title: string, record: NodeRecord, pieces: NodePieces): string {\n if (record.shape.kind !== 'item' || this.coarse) {\n return pieces.title;\n }\n\n const node = this.current;\n const box = node?.status ? CHECKBOXES[node.status] : undefined;\n const before = titleLine(asNode({ ...record.fields, status: node?.status }), true, { explicitIds: new Set() }).title;\n\n if (!node || before !== pieces.title) {\n return pieces.title;\n }\n\n const written = CHECKBOX.exec(title);\n const rest = written ? title.slice(written[0].length) : title.trimStart();\n return box ? `${box} ${rest}` : rest;\n }\n\n /**\n * The children, each followed by what the node wrote right after it.\n * What came after the last child stays after all of them: the node's\n * closing text. Text after a heading belongs to that heading, so under a\n * heading (or at the top level) the node's own text goes before its first\n * child heading, and definitions at the end of the document stay at its end.\n */\n private emitChildren(node: OrbitNode, record: NodeRecord, context: Context, runs: Run[], changes: Changes, out: string[]): void {\n let previous: Context | null = null;\n let headings = false;\n const kinds = this.childKinds(node, context);\n const last = record.children.length - 1;\n const placed = new Set<number>();\n const originalIndex = new Map(record.children.map((child, index) => [child, index]));\n\n const flush = (): void => {\n for (let index = 0; index <= last; index += 1) {\n if (!placed.has(index)) {\n this.emitGap(record, index, runs, changes, context, out);\n placed.add(index);\n }\n }\n };\n\n node.children.forEach((child, position) => {\n const index = originalIndex.get(child) ?? -1;\n const childContext = this.childContext(child, record, context, previous, kinds[position], index !== -1);\n\n if (childContext.kind === 'heading' && !headings) {\n flush();\n headings = true;\n }\n\n this.emit(child, childContext, out);\n previous = childContext;\n\n if (index !== -1 && index !== last && !placed.has(index)) {\n this.emitGap(record, index, runs, changes, context, out);\n placed.add(index);\n }\n });\n\n // What came after children that moved away, or were deleted, is still the node's own.\n flush();\n\n for (const run of runs) {\n // The document's end stays at its end. Definitions there are the root's note: written\n // again with it when it changed, though the blank lines around them stay.\n const definitions = run.role === 'end' && this.lines.slice(run.from, run.to).some((line) => line.trim() !== '');\n\n if (run.role === 'end' && !(definitions && changes.note)) {\n out.push(...this.lines.slice(run.from, run.to));\n }\n }\n }\n\n private emitGap(record: NodeRecord, index: number, runs: Run[], changes: Changes, context: Context, out: string[]): void {\n const shift = indentShift(record.shape, context);\n\n for (const run of runs) {\n if (run.after !== index || run.role === 'end') {\n continue;\n }\n\n const dropped = (run.role === 'attributes' && changes.attributes) || (run.role === 'media' && changes.media) || (run.role === 'note' && changes.note);\n\n if (!dropped) {\n out.push(...shiftLines(this.lines.slice(run.from, run.to), shift));\n }\n }\n }\n\n /**\n * Under a heading, or at the top level, whether each child is written as\n * a list item or a heading. Items have to come first: after a heading,\n * they'd belong to it. Each child would rather stay as it was written (a\n * new one, like the sibling before it), so the split between items and\n * headings is where the fewest children change.\n */\n private childKinds(node: OrbitNode, context: Context): ('heading' | 'item')[] {\n // Markdown has six levels of headings: below the sixth, children are list items.\n if (context.kind === 'item' || (context.kind === 'heading' && context.level >= 6)) {\n return node.children.map(() => 'item');\n }\n\n const preferHeadings = context.kind === 'generated' || context.level < HEADING_LEVELS;\n\n const written = node.children.map((child) => {\n const shape = this.records.get(child)?.shape;\n return shape?.kind === 'heading' || shape?.kind === 'item' ? shape.kind : null;\n });\n\n // New children take after the sibling before them, or the one after them.\n const before: ('heading' | 'item' | null)[] = [];\n let seen: 'heading' | 'item' | null = null;\n\n for (const kind of written) {\n before.push(seen);\n seen = kind ?? seen;\n }\n\n const after: ('heading' | 'item' | null)[] = new Array(written.length).fill(null);\n seen = null;\n\n for (let index = written.length - 1; index >= 0; index -= 1) {\n after[index] = seen;\n seen = written[index] ?? seen;\n }\n\n const wanted = written.map((kind, index) => kind ?? before[index] ?? after[index] ?? (preferHeadings ? 'heading' : 'item'));\n // Changes for each split: headings before it become items, items after it become headings.\n const total = wanted.filter((kind) => kind === 'item').length;\n let split = preferHeadings ? 0 : wanted.length;\n let fewest = Number.POSITIVE_INFINITY;\n let headingsBefore = 0;\n let itemsBefore = 0;\n\n for (let candidate = 0; candidate <= wanted.length; candidate += 1) {\n const changes = headingsBefore + (total - itemsBefore);\n\n if (changes < fewest || (changes === fewest && !preferHeadings)) {\n fewest = changes;\n split = candidate;\n }\n\n if (candidate < wanted.length) {\n if (wanted[candidate] === 'heading') {\n headingsBefore += 1;\n } else {\n itemsBefore += 1;\n }\n }\n }\n\n return wanted.map((_kind, index) => (index < split ? 'item' : 'heading'));\n }\n\n /**\n * Where a child is written, as `kind` says (see `childKinds`): an item\n * keeps its marker; a heading keeps its level relative to its parent, so\n * a map that skips a level (`#`, then `###`) keeps skipping it.\n */\n private childContext(child: OrbitNode, record: NodeRecord, context: Context, previous: Context | null, kind: 'heading' | 'item', original: boolean): Context {\n const shape = this.records.get(child)?.shape;\n\n if (context.kind === 'item') {\n const column = contentColumn(record.shape, context);\n return { kind: 'item', indent: column, marker: shape?.kind === 'item' ? shape.marker : nextMarker(previous) };\n }\n\n if (kind === 'item') {\n return { kind: 'item', indent: 0, marker: shape?.kind === 'item' ? shape.marker : nextMarker(previous) };\n }\n\n const firstShape = record.children.length > 0 ? this.records.get(record.children[0])?.shape : undefined;\n const parentLevel = context.kind === 'heading' ? context.level : 0;\n const shift = context.kind === 'heading' && record.shape.kind === 'heading' ? context.level - record.shape.level : 0;\n const wanted = original && shape?.kind === 'heading'\n ? shape.level + shift\n : previous?.kind === 'heading'\n ? previous.level\n : firstShape?.kind === 'heading' ? firstShape.level + shift : parentLevel + 1;\n // No deeper than the heading before it, or it would read as that heading's child.\n const level = Math.max(parentLevel + 1, previous?.kind === 'heading' ? Math.min(wanted, previous.level) : wanted);\n\n if (level > 6) {\n throw new CannotPatch('Headings only go six levels deep');\n }\n\n return { kind: 'heading', level };\n }\n\n /** A node Orbit didn't read, with everything under it, in Orbit's own form. */\n private generate(node: OrbitNode, context: Context, out: string[]): void {\n if (context.kind === 'heading') {\n const pieces = nodePieces(node, false, this.writing, '');\n separate(out);\n out.push(`${'#'.repeat(context.level)} ${`${pieces.title}${pieces.inline}`.trimStart()}`, ...splitLines(pieces.attributes + pieces.media + pieces.note));\n let previous: Context | null = null;\n\n for (const child of node.children) {\n const childContext: Context = context.level < HEADING_LEVELS\n ? { kind: 'heading', level: context.level + 1 }\n : { kind: 'item', indent: 0, marker: nextMarker(previous) };\n this.generate(child, childContext, out);\n previous = childContext;\n }\n\n return;\n }\n\n if (context.kind === 'item') {\n const column = context.indent + context.marker.length + 1;\n const pieces = nodePieces(node, true, this.writing, ' '.repeat(column));\n out.push(`${' '.repeat(context.indent)}${context.marker} ${`${pieces.title}${pieces.inline}`.trimStart()}`, ...splitLines(pieces.attributes + pieces.media + pieces.note));\n let previous: Context | null = null;\n\n for (const child of node.children) {\n const childContext: Context = { kind: 'item', indent: column, marker: nextMarker(previous) };\n this.generate(child, childContext, out);\n previous = childContext;\n }\n\n return;\n }\n\n throw new CannotPatch('A new root');\n }\n}\n\nconst ATX = /^( {0,3})(#{1,6})([ \\t]+)(.*)$/;\nconst CHECKBOX = /^\\s*\\[( |x|X|\\/)\\]\\s+/;\nconst ITEM = /^([ \\t]*)([-*+]|\\d{1,9}[.)])([ \\t]+)(.*)$/;\nconst INLINE_COMMENT = /\\s*<!--\\s*orbit:?\\s[\\s\\S]*-->\\s*$/i;\n/** Other comments at the end of a title: hidden, and kept when the title changes. */\nconst TRAILING_COMMENTS = /(?:\\s*(?<!\\\\)<!--[\\s\\S]*?-->)+\\s*$/;\n\nconst contextOf = (shape: NodeShape): Context => {\n if (shape.kind === 'heading') {\n return { kind: 'heading', level: shape.level };\n }\n\n if (shape.kind === 'item') {\n return { kind: 'item', indent: shape.indent, marker: shape.marker };\n }\n\n return { kind: 'generated' };\n};\n\nconst sameContext = (shape: NodeShape, context: Context): boolean => {\n if (shape.kind === 'heading') {\n return context.kind === 'heading' && context.level === shape.level;\n }\n\n if (shape.kind === 'item') {\n return context.kind === 'item' && context.indent === shape.indent;\n }\n\n return context.kind === 'generated';\n};\n\nconst sameChildren = (current: OrbitNode[], original: OrbitNode[]): boolean => {\n return current.length === original.length && current.every((child, index) => child === original[index]);\n};\n\n/** Columns an item's lines move by in its new place. */\nconst indentShift = (shape: NodeShape, context: Context): number => {\n return shape.kind === 'item' && context.kind === 'item' ? context.indent - shape.indent : 0;\n};\n\n/** The column a node's own text starts at under it (0 for headings). */\nconst contentColumn = (shape: NodeShape, context: Context): number => {\n if (context.kind !== 'item') {\n return 0;\n }\n\n if (shape.kind === 'item') {\n return shape.content + context.indent - shape.indent;\n }\n\n return context.indent + context.marker.length + 1;\n};\n\nconst markerOf = (shape: NodeShape, context: Context): string => {\n if (shape.kind === 'item') {\n return shape.marker;\n }\n\n return context.kind === 'item' ? context.marker : '-';\n};\n\n/** The marker after a sibling's: the next number in a numbered list, the same bullet otherwise. */\nconst nextMarker = (previous: Context | null): string => {\n if (previous?.kind !== 'item') {\n return '-';\n }\n\n const numbered = /^(\\d+)([.)])$/.exec(previous.marker);\n return numbered ? `${Number(numbered[1]) + 1}${numbered[2]}` : previous.marker;\n};\n\n/** Moves lines right (or left, as far as their indentation goes) by `shift` columns. */\nconst shiftLines = (lines: string[], shift: number): string[] => {\n if (shift === 0) {\n return lines;\n }\n\n return lines.map((line) => {\n if (line.trim() === '') {\n return line;\n }\n\n const expanded = line.replace(/^[ \\t]+/, (indent) => expandTabs(indent));\n\n if (shift > 0) {\n return ' '.repeat(shift) + expanded;\n }\n\n const indent = /^ */.exec(expanded)![0].length;\n return expanded.slice(Math.min(indent, -shift));\n });\n};\n\nconst expandTabs = (indent: string): string => {\n let columns = 0;\n\n for (const character of indent) {\n columns = character === '\\t' ? columns + 4 - (columns % 4) : columns + 1;\n }\n\n return ' '.repeat(columns);\n};\n\nconst splitLines = (text: string): string[] => {\n if (text === '') {\n return [];\n }\n\n const lines = text.split('\\n');\n\n if (lines[lines.length - 1] === '') {\n lines.pop();\n }\n\n return lines;\n};\n\n/** A blank line before a heading, unless the line before is blank already. */\nconst separate = (out: string[]): void => {\n if (out.length > 0 && out[out.length - 1].trim() !== '') {\n out.push('');\n }\n};\n\n/** A node's own fields as a node, to write them as they were. */\nconst asNode = (fields: NodeFields): OrbitNode => {\n return { ...fields, level: 0, children: [] } as OrbitNode;\n};\n\n/** What Orbit would write for a node's title, attributes, media and note, to compare before and after an edit. */\nconst describe = (node: OrbitNode, listItem: boolean, explicitId: boolean): { title: string; attributes: string; media: string; note: string } => {\n const writing = { explicitIds: explicitId ? new Set([node]) : new Set<OrbitNode>() };\n const { title, attributes } = titleLine(node, listItem, writing);\n // The note as text, not as written: writing it decides whether to quote it, which reads it again (slow on big maps).\n return { title, attributes: JSON.stringify(attributes), media: renderMedia(node), note: node.note ?? '' };\n};\n\n/** A key's lines in a frontmatter: its own line and the lines indented under it (or a list right below it). */\nconst keyRange = (lines: string[], key: string, from: number, to: number): { from: number; to: number } | null => {\n // The key as it may be written: bare, or quoted (the emitter double-quotes keys that need it).\n const written = [key, JSON.stringify(key), `'${key.replace(/'/g, \"''\")}'`]\n .map((form) => form.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'));\n const pattern = new RegExp(`^(?:${written.join('|')})\\\\s*:`);\n\n for (let index = from; index < to; index += 1) {\n if (pattern.test(lines[index])) {\n let end = index + 1;\n\n while (end < to && (lines[end].trim() === '' || /^\\s/.test(lines[end]) || /^-(\\s|$)/.test(lines[end]))) {\n end += 1;\n }\n\n // Blank lines after the value belong to what follows.\n while (end > index + 1 && lines[end - 1].trim() === '') {\n end -= 1;\n }\n\n return { from: index, to: end };\n }\n }\n\n return null;\n};\n\nconst yamlLines = (value: Record<string, unknown>): string[] => {\n return splitLines(emitYaml(value as unknown as YamlValue));\n};\n",
|
|
24
|
+
"import type { OrbitDocument } from './types.js';\nimport { documentSource } from './document-source.js';\nimport { writeMarkdown } from './markdown-writing.js';\nimport { patchMarkdown } from './source-patch.js';\n\nexport interface SerializeOptions {\n /**\n * Keep the source's own lines for everything an edit didn't change (the\n * default, for a document parsed from markdown): its formatting, and the\n * text Orbit doesn't read, such as other HTML comments or frontmatter\n * keys of other apps. `false` writes the whole map in Orbit's own form.\n */\n keepSource?: boolean;\n}\n\n/**\n * A map as orbit-md. A document parsed from markdown comes back as it was\n * written, with only what changed since rewritten, so maps written by hand\n * or by other apps keep their formatting and everything Orbit doesn't read.\n * Other documents (built in code, or read from YAML) are written in Orbit's\n * own form: headings for the root and its children, lists below them.\n */\nexport const serializeOrbitMarkdown = (doc: OrbitDocument, options: SerializeOptions = {}): string => {\n const source = options.keepSource === false ? undefined : documentSource(doc);\n\n if (source) {\n const patched = patchMarkdown(doc, source);\n\n if (patched !== null) {\n return patched;\n }\n }\n\n return writeMarkdown(doc);\n};\n",
|
|
25
|
+
"/**\n * The words Orbit shows and says: the controls, the detail sheet, the\n * outline and what it announces, what a screen reader hears about each\n * idea, the media viewer and the empty map. English and Spanish are built\n * in; `registerLanguage` adds others, or changes words of one Orbit has.\n *\n * A map speaks the language its `language` option names, or else the one\n * its element is in: the closest `lang` attribute around it, through shadow\n * roots, then the document's. A language Orbit doesn't have falls back to\n * its base (es-MX reads es), then to English.\n */\n\n/**\n * Text that depends on a number: one form for each plural category the\n * language uses (see `Intl.PluralRules`), `other` for any it leaves out.\n * `{count}` is the number, written the language's way.\n */\nexport interface OrbitPluralText {\n zero?: string;\n one?: string;\n two?: string;\n few?: string;\n many?: string;\n other: string;\n}\n\n/**\n * Everything Orbit says, in one language. `{name}`-style placeholders are\n * filled in as described on each; keep them in a translation, in any order.\n */\nexport interface OrbitStrings {\n /** The map's name for assistive technology, and an exported SVG's title, when it has no `ariaLabel` and its root no text. */\n mindMap: string;\n\n /** What assistive technology calls the map (`aria-roledescription`), in lower case. */\n mindMapRole: string;\n\n /** An idea with no text, wherever its name shows. */\n untitled: string;\n\n /** The root Orbit makes up for a map that's just a list, or has several top headings, and no title. */\n untitledMap: string;\n\n /** The message on a map with nothing in it. */\n emptyMap: string;\n\n /** The hint under it. */\n emptyMapHint: string;\n\n /** The title of the card shown where a map couldn't be drawn. */\n mapNotDrawn: string;\n\n /** The card's message when the problem came with none of its own. */\n mapNotDrawnReason: string;\n\n /** The card's message for a problem on a line of the map's source: `{line}` and `{message}`, which stays as Orbit wrote it. */\n problemOnLine: string;\n\n /** The breadcrumbs, for assistive technology. */\n mapPath: string;\n\n /** The back button, when the idea it goes back to has no name. */\n back: string;\n\n /** The back button's label: `{name}` is the idea it goes back to. */\n backTo: string;\n\n /** The back button's label when that idea has no text. */\n backToParent: string;\n\n /** The group of view buttons. */\n view: string;\n\n /** The button that shows the focused idea with the ideas around it. */\n focus: string;\n\n /** The button that shows the whole map at once. */\n overview: string;\n\n /** The button that shows the map as a list. */\n showOutline: string;\n\n /** The group of zoom buttons. */\n zoom: string;\n\n zoomIn: string;\n zoomOut: string;\n\n /** The button that zooms to fit the view. */\n fitMap: string;\n\n /** Shown when the wheel scrolls the page over a map: `{key}` is Ctrl, or ⌘ on Apple devices. */\n scrollToZoom: string;\n\n /** The map as a list, for assistive technology. */\n outline: string;\n\n /** Announced when the overview opens. */\n overviewAnnouncement: string;\n\n /** How many ideas an idea holds, as announced and in its description: `{count}`. */\n ideaCount: OrbitPluralText;\n\n /** Announced when an idea is added: `{name}`. */\n added: string;\n\n /** Announced when an idea is deleted: `{name}`. */\n removed: string;\n\n /** Announced when an idea moves: `{name}` into `{parent}`. */\n moved: string;\n\n /** Announced when an idea moves to a parent with no text: `{name}`. */\n movedToTop: string;\n\n /** `{name}` in those announcements when the idea has no text. */\n anIdea: string;\n\n /** Part of an idea's description: `{status}` is its status word. */\n status: string;\n\n /** The status in the tooltip: `{status}`. */\n statusLabel: string;\n\n /** Part of an idea's description: `{list}` lists what it has, from the words below. */\n has: string;\n\n hasDetails: string;\n hasNote: string;\n hasImage: string;\n hasVideo: string;\n hasEmbed: string;\n hasLink: string;\n\n /** The text field over an idea being renamed: `{name}`. */\n textOf: string;\n\n /** The text field for a new idea: `{name}` is the idea it goes into. */\n newIdeaFor: string;\n\n /** The empty text field's placeholder for a new idea. */\n newIdea: string;\n\n /** The + in an orbit: `{name}` is the idea it adds to. */\n addIdeaTo: string;\n\n /** Where an idea being moved would land: `{name}` is that idea. */\n moveHere: string;\n\n /** `{name}` in the text fields and the + when the idea has no text. */\n thisIdea: string;\n\n /** `{name}` in `moveHere` when the idea has no text. */\n theIdea: string;\n\n /** The buttons under an idea: `{name}`. */\n ideaActions: string;\n\n /** The buttons under an idea with no text. */\n ideaActionsUntitled: string;\n\n showDetails: string;\n viewImage: string;\n\n /** The picture in the detail sheet, which opens the viewer: `{description}` is its alternative text. */\n viewImageOf: string;\n\n playVideo: string;\n openEmbed: string;\n readNote: string;\n openLink: string;\n\n /** A link to another idea of the map: `{name}` is that idea, or `theIdea` when it has no text. */\n goTo: string;\n\n /** The same link printed, where it can't be followed: `{name}` is that idea. */\n seeIdea: string;\n\n /** The detail sheet's name when the idea has no text. */\n details: string;\n\n close: string;\n previous: string;\n next: string;\n\n /** The button that presents a map shared as a web page, one idea at a time with its note as a caption. */\n present: string;\n\n /** The priority chip: `{priority}`. */\n priority: string;\n\n /** The button over a video in the detail sheet. */\n expand: string;\n\n /** That button, for assistive technology. */\n expandVideo: string;\n\n /** A picture's name in the viewer when it has no description or caption. */\n picture: string;\n\n /** A video's name in the viewer when it has no caption. */\n video: string;\n\n /** Where the viewer is among the map's pictures and videos: `{index}` of `{total}`. */\n position: string;\n\n /** The viewer's button that zooms the picture to fit. */\n fitPicture: string;\n\n pictureUnavailable: string;\n videoUnavailable: string;\n\n /** A video its site doesn't let other pages play. */\n videoUnavailableHere: string;\n\n openPictureInNewTab: string;\n openVideoInNewTab: string;\n\n /** A video's link to its site: `{provider}` is YouTube or Vimeo. */\n watchOn: string;\n}\n\ntype TextKey = { [Key in keyof OrbitStrings]: OrbitStrings[Key] extends string ? Key : never }[keyof OrbitStrings];\ntype CountKey = { [Key in keyof OrbitStrings]: OrbitStrings[Key] extends OrbitPluralText ? Key : never }[keyof OrbitStrings];\ntype Values = Record<string, string | number>;\n\nconst ENGLISH: OrbitStrings = {\n mindMap: 'Mind map',\n mindMapRole: 'mind map',\n untitled: 'Untitled',\n untitledMap: 'Untitled map',\n emptyMap: 'This map is empty',\n emptyMapHint: 'Start it with a # heading or a bullet list',\n mapNotDrawn: 'This map couldn’t be drawn',\n mapNotDrawnReason: 'The map could not be drawn.',\n problemOnLine: 'Line {line}: {message}',\n\n mapPath: 'Map path',\n back: 'Back',\n backTo: 'Back to {name}',\n backToParent: 'Back to the parent node',\n view: 'View',\n focus: 'Focus',\n overview: 'Overview',\n showOutline: 'Show the map as a list',\n zoom: 'Zoom',\n zoomIn: 'Zoom in',\n zoomOut: 'Zoom out',\n fitMap: 'Fit the map',\n scrollToZoom: 'Use {key} + scroll to zoom the map',\n\n outline: 'Map outline',\n overviewAnnouncement: 'Overview of the whole map',\n ideaCount: { one: '{count} item', other: '{count} items' },\n added: 'Added {name}',\n removed: 'Removed {name}',\n moved: 'Moved {name} to {parent}',\n movedToTop: 'Moved {name} to the top',\n anIdea: 'a node',\n\n status: 'status {status}',\n statusLabel: 'Status: {status}',\n has: 'has {list}',\n hasDetails: 'details',\n hasNote: 'note',\n hasImage: 'image',\n hasVideo: 'video',\n hasEmbed: 'embed',\n hasLink: 'link',\n\n textOf: 'Text of {name}',\n newIdeaFor: 'New idea for {name}',\n newIdea: 'New idea',\n addIdeaTo: 'Add an idea to {name}',\n moveHere: 'Move {name} here',\n thisIdea: 'this node',\n theIdea: 'the idea',\n\n ideaActions: '{name} actions',\n ideaActionsUntitled: 'Node actions',\n showDetails: 'Show details',\n viewImage: 'View image',\n viewImageOf: 'View image: {description}',\n playVideo: 'Play video',\n openEmbed: 'Open embed',\n readNote: 'Read note',\n openLink: 'Open link',\n goTo: 'Go to {name}',\n seeIdea: 'See {name}',\n details: 'Details',\n close: 'Close',\n previous: 'Previous',\n next: 'Next',\n present: 'Present',\n priority: 'Priority {priority}',\n expand: 'Expand',\n expandVideo: 'Expand the video',\n\n picture: 'Picture',\n video: 'Video',\n position: '{index} of {total}',\n fitPicture: 'Fit the picture',\n pictureUnavailable: 'This picture can’t be shown.',\n videoUnavailable: 'This video can’t be played.',\n videoUnavailableHere: 'This video can’t be played here.',\n openPictureInNewTab: 'Open the picture in a new tab',\n openVideoInNewTab: 'Open the video in a new tab',\n watchOn: 'Watch on {provider}',\n};\n\nconst SPANISH: OrbitStrings = {\n mindMap: 'Mapa mental',\n mindMapRole: 'mapa mental',\n untitled: 'Sin título',\n untitledMap: 'Mapa sin título',\n emptyMap: 'Este mapa está vacío',\n emptyMapHint: 'Empiézalo con un encabezado # o una lista con viñetas',\n mapNotDrawn: 'No se pudo dibujar este mapa',\n mapNotDrawnReason: 'No se pudo dibujar el mapa.',\n problemOnLine: 'Línea {line}: {message}',\n\n mapPath: 'Ruta del mapa',\n back: 'Atrás',\n backTo: 'Volver a {name}',\n backToParent: 'Volver a la idea superior',\n view: 'Vista',\n focus: 'Enfoque',\n overview: 'Vista general',\n showOutline: 'Mostrar el mapa como lista',\n zoom: 'Zoom',\n zoomIn: 'Acercar',\n zoomOut: 'Alejar',\n fitMap: 'Ajustar el mapa',\n scrollToZoom: 'Usa {key} + desplazamiento para acercar o alejar el mapa',\n\n outline: 'Esquema del mapa',\n overviewAnnouncement: 'Vista general de todo el mapa',\n ideaCount: { one: '{count} idea', many: '{count} ideas', other: '{count} ideas' },\n added: 'Se agregó {name}',\n removed: 'Se eliminó {name}',\n moved: 'Se movió {name} a {parent}',\n movedToTop: 'Se movió {name} al nivel superior',\n anIdea: 'una idea',\n\n status: 'estado {status}',\n statusLabel: 'Estado: {status}',\n has: 'tiene {list}',\n hasDetails: 'detalles',\n hasNote: 'nota',\n hasImage: 'imagen',\n hasVideo: 'video',\n hasEmbed: 'contenido insertado',\n hasLink: 'enlace',\n\n textOf: 'Texto de {name}',\n newIdeaFor: 'Idea nueva en {name}',\n newIdea: 'Idea nueva',\n addIdeaTo: 'Agregar una idea a {name}',\n moveHere: 'Mover {name} aquí',\n thisIdea: 'esta idea',\n theIdea: 'la idea',\n\n ideaActions: 'Acciones de {name}',\n ideaActionsUntitled: 'Acciones de la idea',\n showDetails: 'Ver detalles',\n viewImage: 'Ver imagen',\n viewImageOf: 'Ver imagen: {description}',\n playVideo: 'Reproducir video',\n openEmbed: 'Abrir contenido insertado',\n readNote: 'Leer nota',\n openLink: 'Abrir enlace',\n goTo: 'Ir a {name}',\n seeIdea: 'Ver {name}',\n details: 'Detalles',\n close: 'Cerrar',\n previous: 'Anterior',\n next: 'Siguiente',\n present: 'Presentar',\n priority: 'Prioridad {priority}',\n expand: 'Ampliar',\n expandVideo: 'Ampliar el video',\n\n picture: 'Imagen',\n video: 'Video',\n position: '{index} de {total}',\n fitPicture: 'Ajustar la imagen',\n pictureUnavailable: 'No se puede mostrar esta imagen.',\n videoUnavailable: 'No se puede reproducir este video.',\n videoUnavailableHere: 'Este video no se puede reproducir aquí.',\n openPictureInNewTab: 'Abrir la imagen en una pestaña nueva',\n openVideoInNewTab: 'Abrir el video en una pestaña nueva',\n watchOn: 'Ver en {provider}',\n};\n\nconst BUILT_IN = new Map<string, OrbitStrings>([['en', ENGLISH], ['es', SPANISH]]);\nconst registered = new Map<string, OrbitStrings>(BUILT_IN);\nconst KEYS = Object.keys(ENGLISH) as (keyof OrbitStrings)[];\nconst PLURAL_CATEGORIES = ['zero', 'one', 'two', 'few', 'many', 'other'] as const;\n\n/**\n * Adds a language for every map, by its BCP 47 tag (`fr`, `pt-BR`), or\n * changes some words of one Orbit has. Words it leaves out come from the\n * language it narrows (`pt` for `pt-BR`), then English. Returns a function\n * that puts the language back as it was.\n */\nexport const registerLanguage = (language: string, strings: Partial<OrbitStrings>): () => void => {\n const tag = canonicalTag(language);\n\n if (tag === null) {\n throw new Error(`\"${language}\" isn't a language tag: use one like \"fr\", \"pt-BR\" or \"zh-Hant\".`);\n }\n\n const previous = registered.get(tag);\n const definition: OrbitStrings = { ...(previous ?? registered.get(baseOf(tag)) ?? ENGLISH), ...validStrings(strings, tag) };\n registered.set(tag, definition);\n\n return () => {\n if (registered.get(tag) !== definition) {\n return;\n }\n\n if (previous) {\n registered.set(tag, previous);\n } else {\n registered.delete(tag);\n }\n };\n};\n\n/** The tags of the languages every map can speak: the built-in ones and the registered ones. */\nexport const languageTags = (): string[] => {\n return [...registered.keys()];\n};\n\n/**\n * The language an element is in: the closest `lang` attribute around it,\n * through shadow roots, then the document's. Null when none says.\n */\nexport const languageOf = (element: Element | null | undefined): string | null => {\n let node: Node | null = element ?? null;\n\n while (node) {\n if (node.nodeType === 1) {\n const lang = (node as Element).getAttribute('lang');\n\n if (lang) {\n return lang;\n }\n }\n\n node = node.parentNode ?? ((node as ShadowRoot).host ?? null);\n }\n\n return element?.ownerDocument?.documentElement?.getAttribute('lang') || null;\n};\n\n/** The words of one map: its language's, with the `strings` it was given on top. */\nexport class OrbitWords {\n /** The tag of the language the words come from: `es` for a map asked for `es-MX`. */\n readonly language: string;\n\n /** The tag numbers, plurals and lists are written for: `es-MX` there. */\n readonly locale: string;\n\n private readonly table: OrbitStrings;\n\n constructor(requested?: string | null, strings?: Partial<OrbitStrings>) {\n const tag = requested ? canonicalTag(requested) : null;\n this.language = tag === null ? 'en' : registered.has(tag) ? tag : registered.has(baseOf(tag)) ? baseOf(tag) : 'en';\n this.locale = tag !== null && (tag === this.language || baseOf(tag) === this.language) ? tag : this.language;\n const table = registered.get(this.language) ?? ENGLISH;\n this.table = strings ? { ...table, ...validStrings(strings, 'strings') } : table;\n }\n\n /** Whether these words are the same as `other`'s: the same language and the same table. */\n sameAs(other: OrbitWords | null): boolean {\n return other !== null && other.locale === this.locale && other.table === this.table;\n }\n\n text(key: TextKey, values?: Values): string {\n return this.fill(this.table[key], values);\n }\n\n /** A text with a number in it, in the form the number takes in the language. */\n count(key: CountKey, count: number, values?: Values): string {\n const forms = this.table[key];\n const category = pluralRules(this.locale)?.select(count) ?? (count === 1 ? 'one' : 'other');\n return this.fill(forms[category] ?? forms.other, { ...values, count });\n }\n\n /** Items as the language lists them: \"a, b and c\". */\n list(items: string[]): string {\n const format = listFormat(this.locale);\n return format ? format.format(items) : items.join(', ');\n }\n\n number(value: number): string {\n return numberFormat(this.locale)?.format(value) ?? String(value);\n }\n\n private fill(template: string, values?: Values): string {\n if (!values) {\n return template;\n }\n\n return template.replace(/\\{(\\w+)\\}/g, (placeholder, name: string) => {\n const value = values[name];\n\n if (value === undefined) {\n return placeholder;\n }\n\n return typeof value === 'number' ? this.number(value) : value;\n });\n }\n}\n\n/** The words a map speaks when it's asked for `requested`, or for the language around `element`. */\nexport const wordsFor = (requested: string | undefined, element: Element | null | undefined, strings?: Partial<OrbitStrings>): OrbitWords => {\n return new OrbitWords(requested ?? languageOf(element), strings);\n};\n\n/** Only known keys with the right kind of value: a mistake in one word shouldn't break the map. */\nconst validStrings = (strings: Partial<OrbitStrings>, source: string): Partial<OrbitStrings> => {\n const valid: Partial<Record<keyof OrbitStrings, unknown>> = {};\n\n if (!strings || typeof strings !== 'object') {\n return valid as Partial<OrbitStrings>;\n }\n\n for (const [key, value] of Object.entries(strings)) {\n if (!KEYS.includes(key as keyof OrbitStrings)) {\n warnOnce(`${source}: Orbit has no words called \"${key}\".`);\n continue;\n }\n\n const plural = typeof ENGLISH[key as keyof OrbitStrings] !== 'string';\n\n if (!plural && typeof value === 'string') {\n valid[key as keyof OrbitStrings] = value;\n } else if (plural && isPluralText(value)) {\n valid[key as keyof OrbitStrings] = pluralText(value);\n } else if (plural && typeof value === 'string') {\n valid[key as keyof OrbitStrings] = { other: value };\n } else {\n warnOnce(`${source}: \"${key}\" should be ${plural ? 'an object of plural forms with at least \"other\"' : 'a string'}.`);\n }\n }\n\n return valid as Partial<OrbitStrings>;\n};\n\nconst isPluralText = (value: unknown): value is OrbitPluralText => {\n return typeof value === 'object' && value !== null && typeof (value as OrbitPluralText).other === 'string';\n};\n\nconst pluralText = (value: OrbitPluralText): OrbitPluralText => {\n const forms: OrbitPluralText = { other: value.other };\n\n for (const category of PLURAL_CATEGORIES) {\n if (typeof value[category] === 'string') {\n forms[category] = value[category];\n }\n }\n\n return forms;\n};\n\nconst canonicalTag = (language: string): string | null => {\n if (typeof language !== 'string' || language.trim() === '') {\n return null;\n }\n\n try {\n const [tag] = Intl.getCanonicalLocales(language.trim().replace(/_/g, '-'));\n return tag ?? null;\n } catch {\n return null;\n }\n};\n\nconst baseOf = (tag: string): string => {\n return tag.split('-')[0];\n};\n\nconst warned = new Set<string>();\n\nconst warnOnce = (message: string): void => {\n if (!warned.has(message)) {\n warned.add(message);\n console.warn(`[orbit] ${message}`);\n }\n};\n\nconst pluralRulesCache = new Map<string, Intl.PluralRules | null>();\nconst numberFormatCache = new Map<string, Intl.NumberFormat | null>();\nconst listFormatCache = new Map<string, Intl.ListFormat | null>();\n\nconst pluralRules = (locale: string): Intl.PluralRules | null => {\n return cached(pluralRulesCache, locale, () => new Intl.PluralRules(locale));\n};\n\nconst numberFormat = (locale: string): Intl.NumberFormat | null => {\n return cached(numberFormatCache, locale, () => new Intl.NumberFormat(locale));\n};\n\nconst listFormat = (locale: string): Intl.ListFormat | null => {\n return cached(listFormatCache, locale, () => (typeof Intl.ListFormat === 'function' ? new Intl.ListFormat(locale, { type: 'conjunction' }) : null));\n};\n\nconst cached = <Value>(cache: Map<string, Value | null>, locale: string, make: () => Value | null): Value | null => {\n if (!cache.has(locale)) {\n try {\n cache.set(locale, make());\n } catch {\n cache.set(locale, null);\n }\n }\n\n return cache.get(locale) ?? null;\n};\n",
|
|
26
|
+
"/**\n * A small, safe markdown renderer for notes. It builds DOM nodes directly\n * (never `innerHTML`), so note text can't inject markup, and links and\n * images go through the same URL guard as the rest of the map.\n *\n * Supported: paragraphs, headings, bullet and numbered lists (nested by\n * indentation), blockquotes, fenced code, **bold**, *italic*, ~~strike~~,\n * `code`, [links](https://…), <https://autolinks> and .\n */\n\nimport { isNodeLink } from '../node-links.js';\nimport { guardUrl, resolveUrl } from '../url-guard.js';\n\nexport interface NoteRenderContext {\n /** Where relative links and pictures resolve from: the map's `baseUrl`. */\n baseUrl?: string;\n\n /** Whether a `#id` link points at a node of the map; links to missing nodes show as text. */\n resolveLink?: (href: string) => unknown;\n}\n\n/** A note as DOM nodes, the way the detail sheet shows it: for pages that show notes in their own UI. */\nexport const renderNoteMarkdown = (markdown: string, context: NoteRenderContext = {}): DocumentFragment => {\n return renderBlocks(withoutComments(markdown), context, 0);\n};\n\n/** Code, kept as written, or an HTML comment, hidden as markdown hides it. */\nconst CODE_OR_COMMENT = /(```[\\s\\S]*?```|~~~[\\s\\S]*?~~~|`[^`\\n]*`)|<!--[\\s\\S]*?-->/g;\n\n/** The note without its HTML comments, which stay in the map's file; code shows them as written. */\nconst withoutComments = (markdown: string): string => {\n return markdown.replace(CODE_OR_COMMENT, (_match, code: string | undefined) => code ?? '');\n};\n\n/** Quotes and lists nest at most this deep; deeper lines show as their text, so a note of nothing but `>` degrades instead of stalling or blowing the stack. */\nconst MAX_NESTING = 100;\n\nconst renderBlocks = (markdown: string, context: NoteRenderContext, depth: number): DocumentFragment => {\n const fragment = document.createDocumentFragment();\n const lines = markdown.replace(/\\r\\n?/g, '\\n').split('\\n');\n let index = 0;\n\n while (index < lines.length) {\n const line = lines[index];\n\n if (line.trim() === '') {\n index += 1;\n continue;\n }\n\n const fence = /^\\s*(```|~~~)/.exec(line);\n\n if (fence) {\n const code: string[] = [];\n index += 1;\n\n while (index < lines.length && !lines[index].trimStart().startsWith(fence[1])) {\n code.push(lines[index]);\n index += 1;\n }\n\n index += 1;\n const pre = document.createElement('pre');\n const element = document.createElement('code');\n element.textContent = code.join('\\n');\n pre.appendChild(element);\n fragment.appendChild(pre);\n continue;\n }\n\n const heading = /^\\s{0,3}(#{1,6})\\s+(.*?)\\s*#*\\s*$/.exec(line);\n\n if (heading) {\n const level = Math.min(5, Math.max(3, heading[1].length + 2));\n const element = document.createElement(`h${level}`);\n appendInline(element, heading[2], context);\n fragment.appendChild(element);\n index += 1;\n continue;\n }\n\n if (/^\\s*>/.test(line)) {\n const quoted: string[] = [];\n\n while (index < lines.length && /^\\s*>/.test(lines[index])) {\n quoted.push(lines[index].replace(/^\\s*>\\s?/, ''));\n index += 1;\n }\n\n const blockquote = document.createElement('blockquote');\n\n if (depth >= MAX_NESTING) {\n const paragraph = document.createElement('p');\n appendInline(paragraph, quoted.join(' '), context);\n blockquote.appendChild(paragraph);\n } else {\n blockquote.appendChild(renderBlocks(quoted.join('\\n'), context, depth + 1));\n }\n\n fragment.appendChild(blockquote);\n continue;\n }\n\n if (LIST_ITEM.test(line)) {\n const [list, next] = readList(lines, index, context, depth);\n fragment.appendChild(list);\n index = next;\n continue;\n }\n\n const paragraph: string[] = [];\n\n while (\n index < lines.length\n && lines[index].trim() !== ''\n && !/^\\s*(```|~~~|>|#{1,6}\\s)/.test(lines[index])\n && !LIST_ITEM.test(lines[index])\n ) {\n paragraph.push(lines[index].trim());\n index += 1;\n }\n\n const element = document.createElement('p');\n appendInline(element, paragraph.join(' '), context);\n fragment.appendChild(element);\n }\n\n return fragment;\n};\n\nconst LIST_ITEM = /^(\\s*)([-*+]|\\d{1,9}[.)])\\s+(.*)$/;\n\nconst readList = (lines: string[], start: number, context: NoteRenderContext, depth: number): [HTMLElement, number] => {\n const first = LIST_ITEM.exec(lines[start])!;\n const indent = first[1].length;\n const ordered = /\\d/.test(first[2]);\n const list = document.createElement(ordered ? 'ol' : 'ul');\n let index = start;\n let current: HTMLLIElement | null = null;\n\n while (index < lines.length) {\n const line = lines[index];\n\n if (line.trim() === '') {\n index += 1;\n continue;\n }\n\n const item = LIST_ITEM.exec(line);\n const lineIndent = line.length - line.trimStart().length;\n\n if (item && item[1].length === indent && /\\d/.test(item[2]) !== ordered) {\n break;\n }\n\n if (item && item[1].length === indent) {\n current = document.createElement('li');\n appendInline(current, item[3], context);\n list.appendChild(current);\n index += 1;\n continue;\n }\n\n if (item && item[1].length > indent && current) {\n if (depth >= MAX_NESTING) {\n // Past the nesting cap the item's text joins its parent's.\n current.appendChild(document.createTextNode(` ${line.trim()}`));\n index += 1;\n continue;\n }\n\n const [nested, next] = readList(lines, index, context, depth + 1);\n current.appendChild(nested);\n index = next;\n continue;\n }\n\n if (!item && lineIndent > indent && current) {\n current.appendChild(document.createTextNode(` ${line.trim()}`));\n index += 1;\n continue;\n }\n\n break;\n }\n\n return [list, index];\n};\n\n// URLs may contain one level of balanced parentheses: [x](https://en.wikipedia.org/wiki/Orbit_(film)).\nconst URL_IN_PARENTHESES = String.raw`\\(((?:[^()\\s]|\\([^()\\s]*\\))+)\\)`;\nconst INLINE = new RegExp(\n String.raw`(` + '`' + String.raw`+)([\\s\\S]*?)\\1|!\\[([^\\]]*)\\]` + URL_IN_PARENTHESES\n + String.raw`|\\[([^\\]]+)\\]` + URL_IN_PARENTHESES\n + String.raw`|<(https?:\\/\\/[^>\\s]+|mailto:[^>\\s]+)>|(\\*\\*|__)([\\s\\S]+?)\\8|~~([\\s\\S]+?)~~|(\\*|_)([^\\s*_][\\s\\S]*?)\\11`,\n 'g',\n);\n\nconst appendInline = (parent: HTMLElement, text: string, context: NoteRenderContext): void => {\n let last = 0;\n\n for (const match of text.matchAll(INLINE)) {\n const index = match.index ?? 0;\n\n if (index > last) {\n parent.appendChild(document.createTextNode(text.slice(last, index)));\n }\n\n last = index + match[0].length;\n\n if (match[1] !== undefined) {\n const code = document.createElement('code');\n code.textContent = match[2].trim();\n parent.appendChild(code);\n } else if (match[4] !== undefined) {\n const source = guardUrl(match[4], 'image');\n\n if (source) {\n const image = document.createElement('img');\n image.src = resolveUrl(source, context.baseUrl);\n image.alt = match[3];\n image.loading = 'lazy';\n parent.appendChild(image);\n } else {\n parent.appendChild(document.createTextNode(match[3]));\n }\n } else if (match[6] !== undefined) {\n parent.appendChild(createLink(match[6], match[5], context));\n } else if (match[7] !== undefined) {\n parent.appendChild(createLink(match[7], match[7], context));\n } else if (match[9] !== undefined) {\n const strong = document.createElement('strong');\n appendInline(strong, match[9], context);\n parent.appendChild(strong);\n } else if (match[10] !== undefined) {\n const deleted = document.createElement('del');\n appendInline(deleted, match[10], context);\n parent.appendChild(deleted);\n } else if (match[12] !== undefined) {\n const emphasis = document.createElement('em');\n appendInline(emphasis, match[12], context);\n parent.appendChild(emphasis);\n }\n }\n\n if (last < text.length) {\n parent.appendChild(document.createTextNode(text.slice(last)));\n }\n};\n\nconst createLink = (url: string, label: string, context: NoteRenderContext): Node => {\n if (isNodeLink(url)) {\n // A link to another node of the map: the detail sheet flies there.\n const resolved = !context.resolveLink || context.resolveLink(url);\n const element = document.createElement(resolved ? 'a' : 'span');\n\n if (element instanceof HTMLAnchorElement) {\n element.href = url;\n }\n\n appendInline(element, label, context);\n return element;\n }\n\n const safe = guardUrl(url, 'link');\n\n if (!safe) {\n return document.createTextNode(label);\n }\n\n const link = document.createElement('a');\n link.href = resolveUrl(safe, context.baseUrl);\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n appendInline(link, label, context);\n return link;\n};\n\n/** The note as plain text, for tooltips: markdown syntax removed, whitespace collapsed. */\nexport const noteToPlainText = (markdown: string): string => {\n return withoutComments(markdown)\n .replace(/```[\\s\\S]*?```/g, ' ')\n .replace(/!\\[([^\\]]*)\\]\\([^)]*\\)/g, '$1')\n .replace(/\\[([^\\]]+)\\]\\([^)]*\\)/g, '$1')\n .replace(/<(https?:\\/\\/[^>]+)>/g, '$1')\n .replace(/(\\*\\*|__|~~|`)/g, '')\n .replace(/([*_])(\\S(?:[\\s\\S]*?\\S)?)\\1/g, '$2')\n .replace(/^\\s*(#{1,6}|>|[-*+]|\\d{1,9}[.)])\\s+/gm, '')\n .replace(/\\s+/g, ' ')\n .trim();\n};\n",
|
|
27
|
+
"/**\n * One icon set for every control: a 24 px grid, 1.75 px strokes with round\n * caps and joins. Each icon is a list of SVG path commands.\n */\n\nexport type IconName =\n | 'back' | 'home' | 'chevron' | 'focus' | 'overview' | 'zoom-in' | 'zoom-out' | 'fit'\n | 'image' | 'video' | 'embed' | 'note' | 'link' | 'goto' | 'info' | 'close' | 'previous' | 'next' | 'list' | 'expand';\n\nconst ICONS: Record<IconName, string[]> = {\n back: ['M19 12H5', 'M11 6l-6 6 6 6'],\n home: ['M4 11l8-7 8 7', 'M6 9.5V20h4.5v-5h3v5H18V9.5'],\n chevron: ['M9.5 6l6 6-6 6'],\n focus: ['M4 9V6a2 2 0 0 1 2-2h3', 'M15 4h3a2 2 0 0 1 2 2v3', 'M20 15v3a2 2 0 0 1-2 2h-3', 'M9 20H6a2 2 0 0 1-2-2v-3', 'M12 9.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 1 0 0-5z'],\n overview: ['M12 4.5a2 2 0 1 0 0 4 2 2 0 1 0 0-4z', 'M5.5 15.5a2 2 0 1 0 0 4 2 2 0 1 0 0-4z', 'M18.5 15.5a2 2 0 1 0 0 4 2 2 0 1 0 0-4z', 'M10.9 8.3l-4.3 7.4', 'M13.1 8.3l4.3 7.4', 'M7.5 17.5h9'],\n 'zoom-in': ['M12 5v14', 'M5 12h14'],\n 'zoom-out': ['M5 12h14'],\n fit: ['M4 9V4h5', 'M20 9V4h-5', 'M4 15v5h5', 'M20 15v5h-5'],\n image: ['M5 4h14a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z', 'M20 15l-4.5-4.5L6 20', 'M9 7.5a1.5 1.5 0 1 0 0 3 1.5 1.5 0 1 0 0-3z'],\n video: ['M8 5.5v13l10.5-6.5z'],\n embed: ['M8.5 8l-4 4 4 4', 'M15.5 8l4 4-4 4', 'M13.5 5l-3 14'],\n note: ['M6 4h9l4 4v11a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z', 'M15 4v4h4', 'M8.5 12.5h7', 'M8.5 16h5'],\n link: ['M14 4h6v6', 'M20 4l-9 9', 'M18 14v4a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4'],\n goto: ['M4 12h12', 'M12 7l5 5-5 5', 'M20 5v14'],\n info: ['M12 3.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 1 0 0-17z', 'M12 11v5.5', 'M12 7.75h.01'],\n close: ['M6 6l12 12', 'M18 6L6 18'],\n previous: ['M14.5 6l-6 6 6 6'],\n next: ['M9.5 6l6 6-6 6'],\n list: ['M9 6h11', 'M9 12h11', 'M9 18h11', 'M4.5 6h.01', 'M4.5 12h.01', 'M4.5 18h.01'],\n expand: ['M14.5 4H20v5.5', 'M20 4l-6.5 6.5', 'M9.5 20H4v-5.5', 'M4 20l6.5-6.5'],\n};\n\nconst SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n\n/** An inline, decorative icon element for HTML controls. */\nexport const createIcon = (name: IconName): SVGSVGElement => {\n const svg = document.createElementNS(SVG_NAMESPACE, 'svg');\n svg.setAttribute('viewBox', '0 0 24 24');\n svg.setAttribute('aria-hidden', 'true');\n svg.setAttribute('focusable', 'false');\n svg.classList.add('orbit-icon');\n\n for (const commands of ICONS[name]) {\n const path = document.createElementNS(SVG_NAMESPACE, 'path');\n path.setAttribute('d', commands);\n svg.appendChild(path);\n }\n\n if (name === 'video') {\n svg.classList.add('orbit-icon--filled');\n }\n\n return svg;\n};\n\nexport const iconPaths = (name: IconName): readonly string[] => {\n return ICONS[name];\n};\n\nconst isIconName = (name: string): name is IconName => {\n return Object.prototype.hasOwnProperty.call(ICONS, name);\n};\n\n/**\n * The icon for one of your actions: one of these icons by name, SVG path\n * data on the same 24-unit grid (`'M4 20h4L20 8l-4-4L4 16z'`), or an emoji\n * or short symbol. Without one, the label's first letter.\n */\nexport const createActionIcon = (icon: string | undefined, label: string): Element => {\n if (icon && isIconName(icon)) {\n return createIcon(icon);\n }\n\n if (icon && /^[Mm]\\s*-?[\\d.]/.test(icon)) {\n const svg = createIcon('note');\n svg.replaceChildren();\n const path = document.createElementNS(SVG_NAMESPACE, 'path');\n path.setAttribute('d', icon);\n svg.appendChild(path);\n return svg;\n }\n\n const glyph = document.createElement('span');\n glyph.className = 'orbit-icon orbit-icon--glyph';\n glyph.setAttribute('aria-hidden', 'true');\n glyph.textContent = icon || Array.from(label.trim())[0]?.toUpperCase() || '•';\n return glyph;\n};\n",
|
|
28
|
+
"/**\n * Frames for the detail sheet and the media viewer: another site's page\n * (an embed), and YouTube's and Vimeo's players.\n */\n\nimport { guardUrl, resolveUrl } from '../url-guard.js';\n\n/** A page shown in a frame, or null when its URL isn't allowed in one. */\nexport const embedFrame = (url: string, baseUrl: string | undefined, title: string): HTMLIFrameElement | null => {\n const guarded = guardUrl(url, 'embed');\n\n if (!guarded) {\n return null;\n }\n\n const frame = document.createElement('iframe');\n const source = resolveUrl(guarded, baseUrl);\n frame.src = source;\n frame.title = title;\n // Another site's page keeps its own origin, which it needs for its cookies\n // and storage. A page from the map's own site gets none: with scripts and\n // its real origin, it could reach into the page around the map.\n frame.setAttribute('sandbox', sameOrigin(source) ? 'allow-scripts allow-presentation allow-popups' : 'allow-scripts allow-same-origin allow-presentation allow-popups');\n frame.setAttribute('referrerpolicy', 'no-referrer');\n frame.setAttribute('allow', 'fullscreen; picture-in-picture');\n frame.setAttribute('allowfullscreen', '');\n return frame;\n};\n\n/**\n * YouTube's or Vimeo's player in a frame, from an embed URL made by\n * `toVideoEmbedUrl`, or null when its URL isn't allowed in one.\n */\nexport const playerFrame = (src: string, title: string): HTMLIFrameElement | null => {\n const guarded = guardUrl(src, 'embed');\n\n if (!guarded) {\n return null;\n }\n\n const frame = document.createElement('iframe');\n frame.src = guarded;\n frame.title = title;\n frame.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-presentation allow-popups allow-popups-to-escape-sandbox');\n // YouTube's player won't play without knowing which site it's on (its\n // \"Error 153\"), and some pages send no referrer by default: send the\n // page's origin, never its address.\n frame.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin');\n frame.setAttribute('allow', 'autoplay; fullscreen; picture-in-picture; encrypted-media');\n frame.setAttribute('allowfullscreen', '');\n return frame;\n};\n\n/** Whether a URL is on the page's own origin; relative URLs are. */\nconst sameOrigin = (url: string): boolean => {\n if (typeof location === 'undefined') {\n return false;\n }\n\n try {\n return new URL(url, document.baseURI).origin === location.origin;\n } catch {\n return true;\n }\n};\n",
|
|
29
|
+
"/**\n * The detail sheet: a node's media, note, status, tags and link. A native\n * `<dialog>` opened as a modal, so it sits in the top layer, traps focus,\n * closes with Esc and makes the page behind it inert. Phones get a bottom\n * sheet that can be swiped down to close.\n */\n\nimport type { OrbitNode } from '../types.js';\nimport { OrbitWords } from '../languages.js';\nimport { guardUrl, resolveUrl } from '../url-guard.js';\nimport { hasMediaSource, isNativeVideoUrl, toVideoEmbedUrl } from '../media.js';\nimport { createActionIcon, createIcon } from './icons.js';\nimport { embedFrame, playerFrame } from './frames.js';\nimport { renderNoteMarkdown } from './note-markdown.js';\nimport { isNodeLink } from '../node-links.js';\n\nexport type DetailSection = 'details' | 'image' | 'video' | 'embed' | 'note';\n\n/** What the map tells the sheet about the node it shows, beyond its content: its type, actions and status look. */\nexport interface SheetExtensions {\n icon(node: OrbitNode): string | undefined;\n typeLabel(node: OrbitNode): string | undefined;\n\n /** Draws the node type's section, if it has one. */\n details(node: OrbitNode): ((element: HTMLElement) => void) | undefined;\n\n actions(node: OrbitNode): { id: string; label: string; icon?: string }[];\n runAction(node: OrbitNode, action: string, event: MouseEvent): void;\n status(word: string): { tone: string; color?: string };\n}\n\nexport interface DetailRequest {\n node: OrbitNode;\n\n /** Ancestors from the root, for the path above the title. */\n path: OrbitNode[];\n\n /** Siblings to step through with the previous / next buttons and arrow keys. */\n siblings: OrbitNode[];\n\n section?: DetailSection;\n baseUrl?: string;\n noteRenderer?: (note: string, context: { node: OrbitNode; format: 'markdown' | 'plain' }) => string;\n\n /** Called when the reader steps to a sibling. */\n onNavigate?: (node: OrbitNode) => void;\n\n /** The node a `#id` link points at, if the map has it. */\n resolveLink?: (href: string) => OrbitNode | null;\n\n /** Called, after the sheet closes, when the reader follows a link to another node. */\n onFollowLink?: (node: OrbitNode) => void;\n\n /** The map's node types, actions and status words. */\n extensions?: SheetExtensions;\n\n /**\n * Opens the media viewer on the node's picture or video: with it, the\n * picture is a button and the video gets one. `startAt` is where the\n * sheet's own player of a video file was.\n */\n onViewMedia?: (node: OrbitNode, kind: 'image' | 'video', event: MouseEvent, startAt?: number) => void;\n\n /** The map's words, in its language. Default: English. */\n words?: OrbitWords;\n}\n\nconst SWIPE_CLOSE_DISTANCE = 80;\nconst ENGLISH = new OrbitWords('en');\n\nexport class DetailSheet {\n private readonly host: HTMLElement;\n private dialog: HTMLDialogElement | null = null;\n private request: DetailRequest | null = null;\n private returnFocus: HTMLElement | SVGElement | null = null;\n\n constructor(host: HTMLElement) {\n this.host = host;\n }\n\n get isOpen(): boolean {\n return this.dialog?.open ?? false;\n }\n\n /** The words of the map that opened the sheet. */\n private get words(): OrbitWords {\n return this.request?.words ?? ENGLISH;\n }\n\n /** The node being shown, if the sheet is open. */\n get node(): OrbitNode | null {\n return this.isOpen ? this.request?.node ?? null : null;\n }\n\n open(request: DetailRequest): void {\n const active = (this.host.ownerDocument ?? document).activeElement;\n\n if (!this.isOpen && (active instanceof HTMLElement || active instanceof SVGElement)) {\n this.returnFocus = active;\n }\n\n this.request = request;\n const dialog = this.ensureDialog();\n dialog.replaceChildren(...this.buildContent(request));\n dialog.setAttribute('aria-label', request.node.text || this.words.text('details'));\n\n if (!dialog.open) {\n if (typeof dialog.showModal === 'function') {\n dialog.showModal();\n } else {\n dialog.setAttribute('open', '');\n }\n }\n\n const target = request.section ? dialog.querySelector(`[data-section=\"${request.section}\"]`) : null;\n target?.scrollIntoView?.({ block: 'nearest' });\n dialog.querySelector<HTMLButtonElement>('.orbit-sheet__close')?.focus();\n }\n\n close(): void {\n const dialog = this.dialog;\n\n if (!dialog || !dialog.open) {\n return;\n }\n\n if (typeof dialog.close === 'function') {\n dialog.close();\n } else {\n dialog.removeAttribute('open');\n }\n\n this.restoreFocus();\n }\n\n /** Closes the sheet, then hands the linked node to the map to fly to. */\n private followLink(node: OrbitNode): void {\n const follow = this.request?.onFollowLink;\n this.close();\n follow?.(node);\n }\n\n destroy(): void {\n this.close();\n this.dialog?.remove();\n this.dialog = null;\n this.request = null;\n }\n\n private restoreFocus(): void {\n const target = this.returnFocus;\n this.returnFocus = null;\n\n if (target && target.isConnected) {\n target.focus({ preventScroll: true });\n }\n }\n\n private ensureDialog(): HTMLDialogElement {\n if (this.dialog) {\n return this.dialog;\n }\n\n const dialog = document.createElement('dialog');\n dialog.className = 'orbit-sheet';\n dialog.addEventListener('close', () => this.restoreFocus());\n\n // A click on the dialog box itself (outside its content) is a backdrop click.\n dialog.addEventListener('click', (event) => {\n if (event.target === dialog) {\n const box = dialog.getBoundingClientRect();\n const inside = event.clientX >= box.left && event.clientX <= box.right && event.clientY >= box.top && event.clientY <= box.bottom;\n\n if (!inside || (box.width === 0 && box.height === 0)) {\n this.close();\n }\n }\n });\n\n dialog.addEventListener('keydown', (event) => {\n if (event.key === 'Escape' && typeof dialog.showModal !== 'function') {\n this.close();\n return;\n }\n\n if ((event.key === 'ArrowLeft' || event.key === 'ArrowRight') && !isEditable(event.target)) {\n if (this.step(event.key === 'ArrowRight' ? 1 : -1)) {\n event.preventDefault();\n }\n }\n });\n\n this.enableSwipeToClose(dialog);\n this.host.appendChild(dialog);\n this.dialog = dialog;\n return dialog;\n }\n\n private step(direction: 1 | -1): boolean {\n const request = this.request;\n\n if (!request) {\n return false;\n }\n\n const index = request.siblings.findIndex((sibling) => sibling.id === request.node.id);\n const next = request.siblings[index + direction];\n\n if (index === -1 || !next) {\n return false;\n }\n\n request.onNavigate?.(next);\n this.open({ ...request, node: next, section: undefined });\n return true;\n }\n\n private enableSwipeToClose(dialog: HTMLDialogElement): void {\n let startY: number | null = null;\n\n dialog.addEventListener('pointerdown', (event) => {\n const handle = (event.target as Element).closest?.('.orbit-sheet__handle, .orbit-sheet__header');\n\n if (handle && event.pointerType !== 'mouse') {\n startY = event.clientY;\n }\n });\n\n dialog.addEventListener('pointermove', (event) => {\n if (startY === null) {\n return;\n }\n\n const distance = Math.max(0, event.clientY - startY);\n dialog.style.transform = distance > 0 ? `translateY(${distance}px)` : '';\n });\n\n const finish = (event: PointerEvent) => {\n if (startY === null) {\n return;\n }\n\n const distance = event.clientY - startY;\n startY = null;\n dialog.style.transform = '';\n\n if (distance > SWIPE_CLOSE_DISTANCE) {\n this.close();\n }\n };\n\n dialog.addEventListener('pointerup', finish);\n dialog.addEventListener('pointercancel', finish);\n }\n\n private buildContent(request: DetailRequest): HTMLElement[] {\n const { node } = request;\n const handle = element('div', 'orbit-sheet__handle');\n\n const header = element('header', 'orbit-sheet__header');\n const heading = element('div', 'orbit-sheet__heading');\n\n if (request.path.length > 0) {\n const path = element('p', 'orbit-sheet__path');\n path.textContent = request.path.map((ancestor) => ancestor.text).join(' › ');\n heading.appendChild(path);\n }\n\n const title = element('h2', 'orbit-sheet__title');\n title.textContent = [request.extensions ? request.extensions.icon(node) : node.icon, node.text].filter(Boolean).join(' ');\n heading.appendChild(title);\n const chips = this.buildChips(node, request.extensions);\n\n if (chips) {\n heading.appendChild(chips);\n }\n\n const close = element('button', 'orbit-button orbit-button--icon orbit-sheet__close');\n close.type = 'button';\n close.setAttribute('aria-label', this.words.text('close'));\n close.appendChild(createIcon('close'));\n close.addEventListener('click', () => this.close());\n header.append(heading, close);\n\n const body = element('div', 'orbit-sheet__body');\n\n for (const media of this.buildMedia(request)) {\n body.appendChild(media);\n }\n\n const details = request.extensions?.details(node);\n\n if (details) {\n const section = element('section', 'orbit-sheet__details');\n section.dataset.section = 'details';\n details(section);\n body.appendChild(section);\n }\n\n if (node.note) {\n const note = element('div', 'orbit-sheet__note');\n note.dataset.section = 'note';\n const format = node.noteFormat ?? 'markdown';\n\n if (request.noteRenderer) {\n // Documented: a custom renderer's HTML is inserted as-is.\n note.innerHTML = request.noteRenderer(node.note, { node, format });\n } else if (format === 'plain') {\n const paragraph = element('p', '');\n paragraph.style.whiteSpace = 'pre-wrap';\n paragraph.textContent = node.note;\n note.appendChild(paragraph);\n } else {\n note.appendChild(renderNoteMarkdown(node.note, { baseUrl: request.baseUrl, resolveLink: request.resolveLink }));\n }\n\n // `#id` links, from the markdown or a custom renderer, go to that node.\n note.addEventListener('click', (event) => {\n const anchor = event.target instanceof Element ? event.target.closest('a[href^=\"#\"]') : null;\n const linked = anchor ? request.resolveLink?.(anchor.getAttribute('href') ?? '') : null;\n\n if (linked) {\n event.preventDefault();\n this.followLink(linked);\n }\n });\n\n body.appendChild(note);\n }\n\n const footer = element('footer', 'orbit-sheet__footer');\n const navigation = element('div', '');\n const index = request.siblings.findIndex((sibling) => sibling.id === node.id);\n\n if (request.siblings.length > 1 && index !== -1) {\n navigation.append(\n this.stepButton('previous', this.words.text('previous'), index > 0, -1),\n this.stepButton('next', this.words.text('next'), index < request.siblings.length - 1, 1),\n );\n }\n\n footer.appendChild(navigation);\n const actions = request.extensions?.actions(node) ?? [];\n\n if (actions.length > 0) {\n const group = element('div', 'orbit-sheet__actions');\n\n for (const action of actions) {\n const button = element('button', 'orbit-sheet__action');\n button.type = 'button';\n button.dataset.action = action.id;\n button.append(createActionIcon(action.icon, action.label), document.createTextNode(action.label));\n\n // The sheet closes first, so what the action opens isn't behind it.\n button.addEventListener('click', (event) => {\n const run = request.extensions?.runAction;\n this.close();\n run?.(node, action.id, event);\n });\n\n group.appendChild(button);\n }\n\n footer.appendChild(group);\n }\n\n const linked = isNodeLink(node.link) ? request.resolveLink?.(node.link) ?? null : null;\n const link = node.link && !isNodeLink(node.link) ? guardUrl(node.link, 'link') : null;\n\n if (linked) {\n const button = element('button', 'orbit-sheet__link');\n button.type = 'button';\n button.textContent = `${this.words.text('goTo', { name: linked.text || this.words.text('theIdea') })} →`;\n button.addEventListener('click', () => this.followLink(linked));\n footer.appendChild(button);\n } else if (link) {\n const anchor = element('a', 'orbit-sheet__link');\n anchor.href = resolveUrl(link, request.baseUrl);\n anchor.target = '_blank';\n anchor.rel = 'noopener noreferrer';\n anchor.textContent = `${this.words.text('openLink')} ↗`;\n footer.appendChild(anchor);\n }\n\n const parts = [handle, header, body];\n\n if (navigation.childElementCount > 0 || link || linked || actions.length > 0) {\n parts.push(footer);\n }\n\n return parts;\n }\n\n private stepButton(icon: 'previous' | 'next', label: string, enabled: boolean, direction: 1 | -1): HTMLButtonElement {\n const button = element('button', 'orbit-button orbit-button--icon');\n button.type = 'button';\n button.setAttribute('aria-label', label);\n button.disabled = !enabled;\n button.appendChild(createIcon(icon));\n button.addEventListener('click', () => this.step(direction));\n return button;\n }\n\n private buildChips(node: OrbitNode, extensions: SheetExtensions | undefined): HTMLElement | null {\n const chips: HTMLElement[] = [];\n const typeLabel = extensions?.typeLabel(node);\n\n if (typeLabel) {\n const chip = element('span', 'orbit-sheet__chip orbit-sheet__chip--type');\n chip.textContent = typeLabel;\n chips.push(chip);\n }\n\n if (node.status) {\n const chip = element('span', 'orbit-sheet__chip orbit-sheet__chip--status');\n chip.textContent = node.status;\n const look = extensions?.status(node.status) ?? { tone: statusTone(node.status) };\n chip.style.setProperty('--orbit-chip-dot', look.color ?? `var(--_orbit-status-${look.tone})`);\n chips.push(chip);\n }\n\n if (node.priority !== undefined) {\n const chip = element('span', 'orbit-sheet__chip');\n chip.textContent = this.words.text('priority', { priority: node.priority });\n chips.push(chip);\n }\n\n for (const tag of node.tags ?? []) {\n const chip = element('span', 'orbit-sheet__chip');\n chip.textContent = `#${tag}`;\n chips.push(chip);\n }\n\n if (chips.length === 0) {\n return null;\n }\n\n const container = element('div', 'orbit-sheet__chips');\n container.append(...chips);\n return container;\n }\n\n private buildMedia(request: DetailRequest): HTMLElement[] {\n const { node, baseUrl, onViewMedia } = request;\n const figures: HTMLElement[] = [];\n\n if (hasMediaSource(node.image)) {\n const source = guardUrl(node.image.src, 'image');\n\n if (source) {\n const figure = this.figure('image', node.image.caption);\n const image = document.createElement('img');\n image.src = resolveUrl(source, baseUrl);\n image.alt = node.image.alt ?? '';\n\n if (onViewMedia) {\n const button = element('button', 'orbit-sheet__picture');\n button.type = 'button';\n button.setAttribute('aria-label', image.alt ? this.words.text('viewImageOf', { description: image.alt }) : this.words.text('viewImage'));\n button.appendChild(image);\n button.addEventListener('click', (event) => onViewMedia(node, 'image', event));\n figure.prepend(button);\n } else {\n figure.prepend(image);\n }\n\n figures.push(figure);\n }\n }\n\n if (hasMediaSource(node.video)) {\n const source = guardUrl(node.video.src, 'video');\n\n if (source) {\n const resolved = resolveUrl(source, baseUrl);\n // The same rule the media viewer's createPlayer applies: files, blob: URLs and provider 'native' play in a <video>.\n let player: HTMLVideoElement | HTMLIFrameElement | null = null;\n\n if (node.video.provider === 'native' || isNativeVideoUrl(resolved) || /^blob:/i.test(resolved)) {\n const video = document.createElement('video');\n video.src = resolved;\n video.controls = true;\n video.preload = 'metadata';\n player = video;\n } else {\n const embed = toVideoEmbedUrl(resolved, node.video.provider);\n player = embed ? playerFrame(embed, node.text) : embedFrame(resolved, baseUrl, node.text);\n\n if (player) {\n player.loading = 'lazy';\n }\n }\n\n if (player) {\n const figure = this.figure('video', node.video.caption);\n figure.prepend(player);\n\n if (onViewMedia) {\n figure.appendChild(this.expandButton(figure, (event, startAt) => onViewMedia(node, 'video', event, startAt)));\n }\n\n figures.push(figure);\n }\n }\n }\n\n if (hasMediaSource(node.embed) && !hasMediaSource(node.video)) {\n const frame = embedFrame(node.embed.src, baseUrl, node.text);\n\n if (frame) {\n frame.loading = 'lazy';\n const figure = this.figure('embed', node.embed.caption);\n figure.prepend(frame);\n figures.push(figure);\n }\n }\n\n return figures;\n }\n\n /**\n * The button that moves a video to the media viewer. The sheet's own\n * player stops first; a video file goes on from where it was.\n */\n private expandButton(figure: HTMLElement, expand: (event: MouseEvent, startAt?: number) => void): HTMLButtonElement {\n const button = element('button', 'orbit-sheet__expand');\n button.type = 'button';\n button.setAttribute('aria-label', this.words.text('expandVideo'));\n button.append(createIcon('expand'), document.createTextNode(this.words.text('expand')));\n\n button.addEventListener('click', (event) => {\n let startAt: number | undefined;\n const video = figure.querySelector('video');\n\n if (video) {\n startAt = video.currentTime > 0 ? video.currentTime : undefined;\n video.pause();\n }\n\n // A frame stops playing only by loading again.\n const frame = figure.querySelector('iframe');\n frame?.replaceWith(frame.cloneNode(true));\n expand(event, startAt);\n });\n\n return button;\n }\n\n private figure(section: DetailSection, caption: string | undefined): HTMLElement {\n const figure = element('figure', 'orbit-sheet__media');\n figure.dataset.section = section;\n\n if (caption) {\n const text = element('figcaption', '');\n text.textContent = caption;\n figure.appendChild(text);\n }\n\n return figure;\n }\n}\n\n/** Maps a free-text status onto a theme color: active, done, blocked, todo or neutral. */\nexport const statusTone = (status: string): 'active' | 'done' | 'blocked' | 'todo' | 'neutral' => {\n const value = status.trim().toLowerCase();\n\n if (/^(done|complete|completed|shipped|finished|closed)$/.test(value)) {\n return 'done';\n }\n\n if (/^(active|doing|in[ -]?progress|wip|started|ongoing)$/.test(value)) {\n return 'active';\n }\n\n if (/^(blocked|stuck|at[ -]?risk|failed)$/.test(value)) {\n return 'blocked';\n }\n\n if (/^(todo|to[ -]?do|planned|backlog|next|open)$/.test(value)) {\n return 'todo';\n }\n\n return 'neutral';\n};\n\nconst element = <Name extends keyof HTMLElementTagNameMap>(name: Name, className: string): HTMLElementTagNameMap[Name] => {\n const created = document.createElement(name);\n\n if (className) {\n created.className = className;\n }\n\n return created;\n};\n\nconst isEditable = (target: EventTarget | null): boolean => {\n return target instanceof HTMLElement && (target.isContentEditable || /^(INPUT|TEXTAREA|SELECT|IFRAME|VIDEO)$/.test(target.tagName));\n};\n",
|
|
30
|
+
"/**\n * Ways to extend Orbit: node types, actions and status words. Each works for\n * one map, through its options, or for every map once registered, which also\n * covers `<orbit-map>` elements and maps in markdown pages. A map's own\n * options win over registered ones.\n */\n\nimport type { OrbitNode } from './types.js';\nimport type { OrbitThemeToken } from './themes.js';\nimport { statusTone } from './ui/detail-sheet.js';\n\n/** The colored dots statuses get. */\nexport type OrbitStatusTone = 'active' | 'done' | 'blocked' | 'todo' | 'neutral';\n\n/** How a status word looks: one of the dot tones, or any CSS color. */\nexport type OrbitStatusStyle = OrbitStatusTone | (string & {});\n\n/** A button under the focused node and in its detail sheet. */\nexport interface OrbitAction {\n /** Names the action in the `action` event: `event.action === 'assign'`. */\n id: string;\n\n /** The button's name, read by screen readers, shown as its tooltip and in the detail sheet. */\n label: string | ((node: OrbitNode) => string);\n\n /**\n * The icon: an emoji or short symbol (`'✏️'`), SVG path data on a 24-unit\n * grid (`'M4 20h4L20 8l-4-4L4 16z'`), or one of Orbit's icons (`'note'`,\n * `'link'`, `'goto'`, `'image'`, `'video'`, `'list'`). Default: the\n * label's first letter.\n */\n icon?: string;\n\n /** Which nodes offer the action. Default: every node. */\n when?: (node: OrbitNode) => boolean;\n\n /** Runs when the button is pressed, unless an `action` listener prevents it. */\n run: (node: OrbitNode, event: MouseEvent | KeyboardEvent) => void;\n}\n\n/** How nodes of one type look and behave. Nodes pick a type with `type: name`. */\nexport interface OrbitNodeType {\n /** The type's name for people, shown in the detail sheet and the tooltip: `'Milestone'`. */\n label?: string;\n\n /** The icon these nodes get unless they set their own. */\n icon?: string;\n\n /** The color these nodes get unless they set their own; their children take shades of it. */\n color?: string;\n\n /**\n * Theme tokens for these nodes only, without `--orbit-`: their rim,\n * shadow, glow, label and status colors, such as\n * `{ 'node-stroke': '#B45309', 'node-stroke-width': '3' }`.\n */\n tokens?: Partial<Record<OrbitThemeToken, string>>;\n\n /**\n * Draws inside the node, the way a picture does: `element` is a 100 × 100 px\n * box clipped to the node's circle and scaled with it, and the label moves\n * outside. Return a function to clean up when the node leaves the map.\n */\n render?: (node: OrbitNode, element: HTMLElement) => void | (() => void);\n\n /** Adds a section to the detail sheet, above the note; the node gets a \"Details\" button. */\n details?: (node: OrbitNode, element: HTMLElement) => void;\n\n /** Actions only nodes of this type offer, after the map's own. */\n actions?: OrbitAction[];\n\n /**\n * The version of the fields these nodes keep in their attributes, once\n * the type changes them: 1 at first. Nodes say which version they were\n * written for (`type: task@2`; none means 1), and older ones are brought\n * up to date with `upgrade` when a map is drawn.\n */\n version?: number;\n\n /**\n * Brings a node written for an older version of the type up to date:\n * renames or reshapes its attributes, in place. `from` is the version it\n * was written for. Runs once per node when a map is drawn (or with\n * `upgradeNodeTypes`), and the next save writes the node as upgraded.\n * Nodes written for a newer version than this one are left as they are.\n */\n upgrade?: (node: OrbitNode, from: number) => void;\n}\n\n/** The extensions a map is created with, before the registered ones. */\nexport interface OrbitExtensionOptions {\n /** Node types by name. */\n nodeTypes?: Record<string, OrbitNodeType>;\n\n /** Actions every node offers (or the ones `when` picks). */\n actions?: OrbitAction[];\n\n /** Status words and how they look: `{ review: 'active', 'on hold': '#A855F7' }`. */\n statuses?: Record<string, OrbitStatusStyle>;\n\n /**\n * The type a node is drawn as when it names none: its look, content and\n * actions, as if it said `type: name`, for display only. Orbit never writes\n * it to the map, never upgrades a node for it, and asks again whenever it\n * draws, so return undefined to draw the node as it is. Called often: keep\n * it quick.\n */\n nodeTypeFor?: (node: OrbitNode) => string | undefined;\n}\n\nconst registeredTypes = new Map<string, OrbitNodeType>();\nconst registeredActions = new Map<string, OrbitAction>();\nconst registeredStatuses = new Map<string, OrbitStatusStyle>();\n\n/**\n * Defines a node type for every map: nodes with `type: name` (any case) take\n * it. Returns a function that removes it again.\n */\nexport const registerNodeType = (name: string, definition: OrbitNodeType): () => void => {\n return register(registeredTypes, wordKey(name), definition);\n};\n\n/** Adds an action to every map. Returns a function that removes it again. */\nexport const registerAction = (action: OrbitAction): () => void => {\n return register(registeredActions, action.id, action);\n};\n\n/**\n * Gives a status word its look on every map: one of the tones (`active`,\n * `done`, `blocked`, `todo`, `neutral`) or any CSS color. Returns a function\n * that removes it again.\n */\nexport const registerStatus = (word: string, style: OrbitStatusStyle): () => void => {\n return register(registeredStatuses, wordKey(word), style);\n};\n\nconst register = <Value>(registry: Map<string, Value>, key: string, value: Value): () => void => {\n registry.set(key, value);\n\n return () => {\n if (registry.get(key) === value) {\n registry.delete(key);\n }\n };\n};\n\n/** Types and status words match whatever their case and surrounding spaces. */\nconst wordKey = (word: string): string => {\n return word.trim().toLowerCase();\n};\n\nconst TONES = new Set<string>(['active', 'done', 'blocked', 'todo', 'neutral']);\n\n/** How a status looks on a map: its tone, and its own color when it has one. */\nexport interface StatusLook {\n tone: OrbitStatusTone;\n color?: string;\n}\n\n/**\n * One map's view of the extensions: its own node types, actions and status\n * words first, then the registered ones. Lookups read the registries each\n * time, so a type registered after the map was created applies on its next\n * redraw.\n */\nexport class MapExtensions {\n private readonly types = new Map<string, OrbitNodeType>();\n private readonly statuses = new Map<string, OrbitStatusStyle>();\n private readonly actionList: OrbitAction[];\n private readonly typeFor: ((node: OrbitNode) => string | undefined) | undefined;\n\n /** `nodeTypeFor` threw: it's asked on every frame, so the console hears of it once. */\n private typeForFailed = false;\n\n constructor(options: OrbitExtensionOptions = {}) {\n for (const [name, definition] of Object.entries(options.nodeTypes ?? {})) {\n this.types.set(wordKey(name), definition);\n }\n\n for (const [word, style] of Object.entries(options.statuses ?? {})) {\n this.statuses.set(wordKey(word), style);\n }\n\n this.actionList = options.actions ?? [];\n this.typeFor = options.nodeTypeFor;\n }\n\n /**\n * The name of the type the node is drawn as: its own `type`, or for a node\n * that names none, the one `nodeTypeFor` gives it for display.\n */\n typeName(node: OrbitNode): string | undefined {\n if (node.type) {\n return node.type;\n }\n\n const typeFor = this.typeFor;\n\n if (!typeFor) {\n return undefined;\n }\n\n let name: string | undefined;\n\n try {\n name = typeFor(node);\n } catch (error) {\n if (!this.typeForFailed) {\n this.typeForFailed = true;\n console.error('[orbit] nodeTypeFor() threw:', error);\n }\n\n return undefined;\n }\n\n return typeof name === 'string' && name.trim() !== '' ? name : undefined;\n }\n\n /** The type the node is drawn as, if this map knows it: its own, or one given for display (see `typeName`). */\n nodeType(node: OrbitNode): OrbitNodeType | undefined {\n const name = this.typeName(node);\n return name === undefined ? undefined : this.typeNamed(name);\n }\n\n /** The node's own type (`type`), never one given for display: what upgrades go by. */\n ownType(node: OrbitNode): OrbitNodeType | undefined {\n return node.type ? this.typeNamed(node.type) : undefined;\n }\n\n private typeNamed(name: string): OrbitNodeType | undefined {\n const key = wordKey(name);\n return this.types.get(key) ?? registeredTypes.get(key);\n }\n\n /** The node's icon: its own, or its type's. */\n icon(node: OrbitNode): string | undefined {\n return node.icon ?? this.nodeType(node)?.icon;\n }\n\n /** The node's own color, or its type's. */\n color(node: OrbitNode): string | undefined {\n return node.color ?? this.nodeType(node)?.color;\n }\n\n /** The actions a node offers: the map's, the registered ones, then its type's, each id once. */\n actions(node: OrbitNode): OrbitAction[] {\n const seen = new Set<string>();\n const offered: OrbitAction[] = [];\n\n for (const action of [...this.actionList, ...registeredActions.values(), ...(this.nodeType(node)?.actions ?? [])]) {\n if (seen.has(action.id)) {\n continue;\n }\n\n seen.add(action.id);\n\n if (!action.when || guarded(`the \"${action.id}\" action's when()`, false, () => action.when!(node))) {\n offered.push(action);\n }\n }\n\n return offered;\n }\n\n /** How a status looks: a word this map or a registration names, or one of the built-in words. */\n status(word: string): StatusLook {\n const key = wordKey(word);\n const style = this.statuses.get(key) ?? registeredStatuses.get(key);\n\n if (style === undefined) {\n return { tone: statusTone(word) };\n }\n\n return TONES.has(style) ? { tone: style as OrbitStatusTone } : { tone: 'neutral', color: style };\n }\n}\n\n/**\n * Brings nodes written for older versions of their types up to date (see\n * `OrbitNodeType.version`), with the types `nodeTypes` defines or the\n * registered ones. Maps do this when they're drawn; this is for documents\n * read without one, on a server or in a script. Returns how many nodes\n * were upgraded.\n */\nexport const upgradeNodeTypes = (root: OrbitNode, nodeTypes?: Record<string, OrbitNodeType>): number => {\n return upgradeTypes(root, new MapExtensions({ nodeTypes }));\n};\n\n/** Upgrades the nodes under `root` with the types `extensions` knows. */\nexport const upgradeTypes = (root: OrbitNode, extensions: MapExtensions): number => {\n let upgraded = 0;\n\n const visit = (node: OrbitNode): void => {\n // Only a type the node names: one given for display is never written, so there's nothing to upgrade.\n const type = extensions.ownType(node);\n const from = node.typeVersion ?? 1;\n\n if (type?.version !== undefined && type.upgrade && from < type.version) {\n const upgrade = type.upgrade;\n\n const done = guarded(`the \"${node.type}\" type's upgrade()`, false, () => {\n upgrade(node, from);\n return true;\n });\n\n if (done) {\n node.typeVersion = type.version;\n upgraded += 1;\n }\n }\n\n node.children.forEach(visit);\n };\n\n visit(root);\n return upgraded;\n};\n\n/** An action's label for a node. */\nexport const actionLabel = (action: OrbitAction, node: OrbitNode): string => {\n return typeof action.label === 'function' ? guarded(`the \"${action.id}\" action's label()`, action.id, () => (action.label as (node: OrbitNode) => string)(node)) : action.label;\n};\n\n/**\n * Runs code a map was extended with. If it throws, the map carries on and\n * the console says which extension failed.\n */\nexport const guarded = <Result>(what: string, fallback: Result, run: () => Result): Result => {\n try {\n return run();\n } catch (error) {\n console.error(`[orbit] ${what} threw:`, error);\n return fallback;\n }\n};\n",
|
|
31
|
+
"/**\n * Framework-agnostic types for Orbit.\n */\n\nimport type { OrbitStrings } from './languages.js';\nimport type { OrbitDiagnostic } from './diagnostics.js';\nimport type { OrbitThemeName, OrbitThemeToken } from './themes.js';\nimport type { OrbitAction, OrbitNodeType, OrbitStatusStyle } from './extensions.js';\n\n/** One node of a map, as the parsers produce it. */\nexport interface OrbitNode {\n /** Unique within the map: a slug of the text (`Product roadmap` becomes `product-roadmap`), or the `id` attribute. */\n id: string;\n\n /** The node's label, without its icon. */\n text: string;\n\n /** Depth in the tree: 0 for the root. */\n level: number;\n\n /** Any CSS color. Without one, the node takes its branch's color from the theme or `palette`. */\n color?: string;\n\n /**\n * Which of the palette's colors the node takes when it has no `color` of\n * its own: `1` is the first after the root's, cycling. Without one, a\n * top-level node takes the next in turn and a deeper node a shade of its\n * branch's. Edits on the map write it to keep a top-level node's color\n * when the nodes around it change.\n */\n paletteColor?: number;\n\n /** An emoji (or any short symbol) shown before the text. */\n icon?: string;\n\n /** Hide the node's children until it is opened. */\n collapsed?: boolean;\n\n /**\n * The node's type, such as `milestone`. A type defined in the `nodeTypes`\n * option or with `registerNodeType` sets its look, content and actions.\n */\n type?: string;\n\n /**\n * The version of its type the node was written for, when the type has\n * changed its fields since its first one: `type: task@2`. Not written\n * means 1. See `OrbitNodeType.version`.\n */\n typeVersion?: number;\n\n /**\n * A URL the node links to, offered as a button when the node is in focus.\n * `#id` links to another node of the map: the button flies there.\n */\n link?: string;\n\n /** Longer text, shown in the detail sheet: markdown unless `noteFormat` is `plain`. */\n note?: string;\n\n noteFormat?: 'markdown' | 'plain';\n tags?: string[];\n\n /**\n * Free text. Some words get a colored dot: `active` (also `doing`, `in progress`),\n * `done` (`complete`, `shipped`), `blocked` (`stuck`, `at risk`), `todo` (`planned`, `next`).\n */\n status?: string;\n\n priority?: number;\n\n /** A picture shown inside the node and in the detail sheet. */\n image?: { src: string; alt?: string; caption?: string };\n\n /** A video (YouTube, Vimeo or a file) played in the detail sheet. */\n video?: { src: string; provider?: 'youtube' | 'vimeo' | 'native'; thumbnail?: string; caption?: string };\n\n /** A page shown in a frame in the detail sheet. */\n embed?: { src: string; caption?: string };\n\n /** Attributes Orbit doesn't use itself, kept for your own code (`<!-- orbit owner: Ana -->`). */\n attrs?: Record<string, unknown>;\n\n /** Where the node comes from in a markdown source. */\n source?: {\n line: number;\n raw: string;\n };\n\n children: OrbitNode[];\n\n /** The parent node. Set by the parsers as a non-enumerable property, so trees stay JSON-serializable. */\n parent?: OrbitNode;\n}\n\n/** Orbit's own buttons for a node: its picture, video, embed, note, link, and its type's details. */\nexport type OrbitContentAction = 'image' | 'video' | 'embed' | 'note' | 'link' | 'details';\n\n/** A button pressed under the focused node or in its detail sheet. */\nexport interface OrbitActionEvent {\n node: OrbitNode;\n\n /** One of Orbit's buttons, or the `id` of one of your actions. */\n action: OrbitContentAction | (string & {});\n\n sourceEvent: MouseEvent | KeyboardEvent;\n}\n\n/** The `action` event: call `preventDefault()` to skip what the button does (the detail sheet, the link, or your action's `run`). */\nexport interface OrbitActionDetail extends OrbitActionEvent {\n preventDefault(): void;\n readonly defaultPrevented: boolean;\n}\n\n/**\n * What a map reports, by event name. Listen with `renderer.on(name, listener)`,\n * or for `orbit-<name>` DOM events, which bubble from the map's container\n * (and out of `<orbit-map>`).\n */\nexport interface OrbitEventMap {\n /** The focused node changed. `path` runs from the root to `node`. */\n 'focus-change': { node: OrbitNode; path: OrbitNode[] };\n\n /** The map switched between focus mode and the overview. */\n 'view-mode-change': { mode: ViewMode };\n\n /** A node was clicked or activated with the keyboard, before the map reacts. */\n 'node-click': { node: OrbitNode };\n\n /** A content button under the focused node was pressed. */\n action: OrbitActionDetail;\n\n /** A spun orbit came to rest, with this planet on top. */\n 'spin-settle': { planet: OrbitNode };\n\n /**\n * A node was long-pressed, right-clicked, or chosen with the context menu\n * key: the place for a menu of things to do with it. A DOM listener calls\n * `preventDefault()` to take the press (see `onNodeContext`).\n */\n 'node-context': OrbitNodeContextEvent;\n\n /** The map was edited with `addNode`, `updateNode`, `removeNode` or `moveNode`. */\n edit: OrbitEdit;\n\n /** The field for typing on the map opened: on a node, or in the orbit for a new idea. */\n 'editor-open': OrbitEditorEvent;\n\n /** The field for typing on the map closed. */\n 'editor-close': OrbitEditorEvent;\n\n /** A node is dragged somewhere else on an editable map: lifted, carried over a place, or let go (see `phase`). */\n 'node-drag': OrbitNodeDragEvent;\n\n /** The media viewer opened, or stepped to another picture or video. */\n 'media-open': OrbitMediaEvent;\n\n /** The media viewer closed. */\n 'media-close': OrbitMediaEvent;\n\n /** The video in the media viewer started, paused, moved on, ended or was muted; while it plays, its time a few times a second. */\n 'media-state': OrbitMediaState;\n}\n\n/** A node's picture or video in the media viewer. */\nexport interface OrbitMediaEvent {\n node: OrbitNode;\n\n /** `image`, the node's picture, or `video`, its video. */\n kind: 'image' | 'video';\n\n /** Its place among the map's pictures and videos, in reading order, from 0. */\n index: number;\n\n /** How many pictures and videos the viewer steps through. */\n total: number;\n}\n\n/** What `openMedia` shows. */\nexport interface OrbitMediaOptions {\n /** For a node with a picture and a video: which to show. Default: the picture. */\n kind?: 'image' | 'video';\n\n /** Start a video playing as it opens. Default true. */\n autoplay?: boolean;\n\n /** Start a video this many seconds in. YouTube and Vimeo start at the whole second. Default 0. */\n startAt?: number;\n}\n\n/** The video in the media viewer, as it plays (see the `media-state` event). */\nexport interface OrbitMediaState {\n node: OrbitNode;\n\n /** Playing, rather than paused, not started yet, or ended. */\n playing: boolean;\n\n /** Where it is, in seconds from the start. */\n time: number;\n\n /** How long it is, in seconds, once known. */\n duration: number | null;\n\n /** It played to the end. */\n ended: boolean;\n\n /**\n * Its sound is off. Browsers let a video start with sound only once the\n * reader has interacted with the page; a video started before that plays\n * muted.\n */\n muted: boolean;\n}\n\n/**\n * A node dragged somewhere else (see `editable`). `start` as it leaves its\n * place under the finger, the moment to close a menu the long press opened;\n * `over` whenever where it would go changes; `end` when it's let go, after\n * the `edit` that moved it, if it moved.\n */\nexport interface OrbitNodeDragEvent {\n phase: 'start' | 'over' | 'end';\n node: OrbitNode;\n\n /**\n * Where it would go, or (on `end`) went: into `parent`, at `index` among\n * its children (null: after the last). On `start`, where it was; null over\n * no place, and on an `end` that put it back.\n */\n parent: OrbitNode | null;\n\n index: number | null;\n}\n\n/** The field for typing a node's text on the map (see `editable`, `editNode` and `editNewNode`). */\nexport interface OrbitEditorEvent {\n /** The node whose text is typed, or null for a new idea. */\n node: OrbitNode | null;\n\n /** For a new idea, the node it goes under. */\n parent: OrbitNode | null;\n}\n\n/** A long press, right click or context menu key on a node. */\nexport interface OrbitNodeContextEvent {\n node: OrbitNode;\n\n /** Where, in CSS pixels from the map's top left corner: the press, or the node's center for the keyboard. */\n x: number;\n\n y: number;\n}\n\n/** An edit to the map, as the `edit` event and `onEdit` report it. */\nexport interface OrbitEdit {\n kind: 'add' | 'update' | 'remove' | 'move';\n\n /** The node added, changed, removed or moved. */\n node: OrbitNode;\n\n /** The whole tree after the edit. `renderer.toMarkdown()` writes it as orbit-md. */\n tree: OrbitNode;\n}\n\n/** What `addNode` and `updateNode` take: a node's text and attributes. */\nexport type OrbitNodeInput = Partial<Pick<\n OrbitNode,\n 'text' | 'icon' | 'color' | 'paletteColor' | 'status' | 'priority' | 'tags' | 'collapsed' | 'link' | 'note' | 'noteFormat' | 'image' | 'video' | 'embed' | 'type' | 'typeVersion' | 'attrs'\n>>;\n\n/** What `addNode` takes: a node's text and attributes, and the nodes to add under it, as many levels down as you like. */\nexport type OrbitNewNode = OrbitNodeInput & { text: string; children?: OrbitNewNode[] };\n\nexport type OrbitEventName = keyof OrbitEventMap;\n\n/** `focus`: one node at the center with its children around it. `all`: the overview of the whole tree. */\nexport type ViewMode = 'focus' | 'all';\n\n/** A built-in theme, or `auto` for `paper` or `night` following the reader's light or dark preference. */\nexport type OrbitThemePreset = OrbitThemeName | 'auto';\n\nexport interface ContainerSize {\n width: number;\n height: number;\n}\n\n/** Options a document sets in its frontmatter (markdown) or top-level keys (YAML). */\nexport interface OrbitDocumentOptions {\n /** The map's accessible name and SVG title. */\n title?: string;\n\n /** A theme name, as written (unknown names are reported and ignored). */\n theme?: string;\n\n /** Written `view:` in the document. */\n viewMode?: ViewMode;\n\n showRings?: boolean;\n interactive?: boolean;\n\n /** Written `animation:` in the document. */\n orbitAnimation?: boolean;\n\n /** Written `speed:` in the document: seconds per turn of the orbit's drift. */\n orbitSpeed?: number;\n\n palette?: string[];\n\n /** Height in pixels, used by `<orbit-map>` elements and marked placeholders. */\n height?: number;\n\n maxDepth?: number;\n className?: string;\n baseUrl?: string;\n\n /** The format version the document is written for. */\n schemaVersion?: number;\n}\n\n/** A parsed map: its tree, its options and the problems the parser worked around. */\nexport interface OrbitDocument {\n root: OrbitNode;\n options: OrbitDocumentOptions;\n\n /**\n * Frontmatter or top-level YAML keys Orbit doesn't read (another app's,\n * or a newer Orbit's), as written. Both serializers write them back, so\n * nothing a document says is lost by reading and saving it.\n */\n extra?: Record<string, unknown>;\n\n /** Problems the parser recovered from, one line each (\"Line 4: …\"). */\n warnings: string[];\n\n /** The same problems with a code, line and severity. Always set on parse results. */\n diagnostics?: OrbitDiagnostic[];\n}\n\n/** A document as the parsers return it, with its diagnostics always set. */\nexport type ParsedOrbitDocument = OrbitDocument & { diagnostics: OrbitDiagnostic[] };\n\n/**\n * A theme with your own values: `{ preset: 'night', tokens: { surface: '#0b1020', 'ring-dash': 'none' } }`.\n * Each token sets the matching `--orbit-*` CSS custom property on the map,\n * so a value the page sets in its own CSS still wins.\n */\nexport interface OrbitRendererTheme {\n /** The theme to start from: a built-in one or one registered with `registerTheme`. Without one, the document's theme (or `paper`). */\n preset?: OrbitThemePreset | (string & {});\n\n /** Token values by name, as listed in `THEME_TOKENS` (`surface`, `color-1`, `ring-dash`, …). */\n tokens?: Partial<Record<OrbitThemeToken, string>>;\n}\n\n/** How a flicked orbit spins in focus mode. */\nexport interface OrbitSpinOptions {\n /** Seconds for a free spin to lose about two thirds of its speed. Default 1.4. */\n decay?: number;\n\n /** Fastest spin, in degrees per second. Default 1440 (four turns a second). */\n maxSpeed?: number;\n\n /** Bring the nearest planet to the top as a spin comes to rest. Off by default. */\n snap?: 'planet' | false;\n\n /** Vibrate briefly as planets pass the top, on devices that support it. Off by default. */\n haptics?: boolean;\n}\n\n/** How the map responds to the wheel, trackpads and pinches. */\nexport interface OrbitZoomOptions {\n /**\n * `auto` (default): the wheel zooms freely when the map is the whole page\n * and needs Ctrl or ⌘ when the page scrolls; `always`; `modifier`; or\n * `false` to ignore the wheel.\n */\n wheel?: 'auto' | 'always' | 'modifier' | false;\n\n /** Smallest zoom, relative to the fitted view. Default 0.4. */\n minimum?: number;\n\n /** Largest zoom, relative to the fitted view. Default 6. */\n maximum?: number;\n}\n\n/**\n * How a map looks and behaves. Every option is optional; options passed to\n * the renderer win over the document's frontmatter.\n */\n/** Room the page's own controls take at the map's edges, in px (see `RendererOptions.insets`). */\nexport interface OrbitInsets {\n top?: number;\n right?: number;\n bottom?: number;\n left?: number;\n}\n\nexport interface RendererOptions {\n /** The first view: `focus` (default) or `all`, the overview. */\n viewMode?: ViewMode;\n\n /**\n * The node in focus when the map first draws, by id: to open a map where\n * the reader left it. Default: the root. Later renders keep the reader's place.\n */\n focus?: string;\n\n /** Draw the dashed orbit rings. Default true. */\n showRings?: boolean;\n\n /** `false` draws a still picture: no clicks, drags, zoom or keyboard. Default true. */\n interactive?: boolean;\n\n /** Keep the orbit turning slowly on its own. */\n orbitAnimation?: boolean;\n\n /** Seconds per revolution of `orbitAnimation`. */\n orbitSpeed?: number;\n\n /** Levels below the root to render (1 = root + direct children). */\n maxDepth?: number;\n\n /** Node colors: the first for the root, then one per top-level branch (cycling). Default: the theme's. */\n palette?: string[];\n\n /**\n * A theme name (`'night'`, `'cosmos'`, or one registered with\n * `registerTheme`) or a theme object. An object without a `preset` keeps\n * the document's theme and changes the tokens it names.\n */\n theme?: OrbitThemePreset | (string & {}) | OrbitRendererTheme;\n\n /** The map's accessible name. Default: the document's `title`. */\n ariaLabel?: string;\n\n /**\n * The language of the map's controls, sheets and announcements: a BCP 47\n * tag such as `es` or `pt-BR`. Default: the language the map's element is\n * in (the closest `lang` attribute), then English. Orbit speaks English and\n * Spanish; `registerLanguage` adds others.\n */\n language?: string;\n\n /** Words to change on this map only, over its language's: `{ zoomIn: 'Closer' }`. */\n strings?: Partial<OrbitStrings>;\n\n /** Breadcrumbs, the view switch, the list button and zoom buttons. Default true. */\n showControls?: boolean;\n\n /** How a flicked orbit spins. */\n spin?: OrbitSpinOptions;\n\n /** How the wheel, trackpads and pinches zoom. */\n zoom?: OrbitZoomOptions;\n\n /** Navigation flight length in milliseconds, or `auto` to scale with the distance travelled. */\n transitionDuration?: 'auto' | number;\n\n /** A node was clicked or activated with the keyboard, before the map reacts. */\n onNodeClick?: (node: OrbitNode) => void;\n\n onViewModeChange?: (mode: ViewMode) => void;\n\n /** A button was pressed. Return `false` to skip what it does (the detail sheet, the link, or your action's `run`). */\n onAction?: (event: OrbitActionEvent) => void | false;\n\n /** A new node is in focus. */\n onFocusChange?: (node: OrbitNode) => void;\n\n /**\n * A node was long-pressed, right-clicked or chosen with the context menu\n * key: show a menu of things to do with it at (`x`, `y`). With this\n * callback or a `node-context` listener, the press is yours: it doesn't\n * open the node, and the browser's own menu stays closed.\n */\n onNodeContext?: (event: OrbitNodeContextEvent) => void;\n\n /** The map was edited with `addNode`, `updateNode`, `removeNode` or `moveNode`; save `renderer.toMarkdown()` to keep it. */\n onEdit?: (edit: OrbitEdit) => void;\n\n /** The field for typing on the map opened. */\n onEditorOpen?: (event: OrbitEditorEvent) => void;\n\n /** The field for typing on the map closed. */\n onEditorClose?: (event: OrbitEditorEvent) => void;\n\n /** A node is dragged somewhere else (see `editable` and the `node-drag` event). */\n onNodeDrag?: (event: OrbitNodeDragEvent) => void;\n\n /**\n * How long (ms) a finger or pen holds still on a node before it counts as\n * a long press (see `onNodeContext`). Default 500; apps can pass their\n * platform's own, such as Android's 400.\n */\n longPressDelay?: number;\n\n /**\n * The parts of the map the page covers with its own controls, such as a\n * toolbar floating over its bottom edge, in px from each edge. Views are\n * fitted into what's left, and the map still draws under the controls.\n * Changing them glides a fitted view to its new place.\n */\n insets?: OrbitInsets;\n\n /**\n * Build the map on the map: a + in the orbit adds an idea, typed right\n * in its new planet, and a long press, a right click or F2 edits a\n * node's text where it is. A node held still, by a long press or the\n * mouse, lifts: drag it onto another node to move it there, or to a place\n * in the orbit to put it there. Default false.\n */\n editable?: boolean;\n\n /**\n * Keys for building an editable map at speed, as in mind-map apps. On a\n * node with keyboard focus, Tab (or Insert) adds an idea under it,\n * Shift+Enter adds one beside it, and Delete removes it. While typing,\n * Tab keeps what was typed and goes on a level down, under it; with\n * nothing typed, it moves the field under the idea before. Shift+Tab goes\n * on a level up, beside the parent. Tab then stays in the map; Shift+Tab\n * from a node still leaves it. Default false.\n */\n editingKeys?: boolean;\n\n /** Called when a flicked orbit comes to rest, with the planet nearest the top. */\n onSpinSettle?: (planet: OrbitNode) => void;\n\n /** Buttons under the focused node for its note, media, link and actions. Default true. */\n showActionButtons?: boolean;\n\n /** Open the built-in detail sheet for notes, embeds and the details of a node's type. Default true. */\n showDetailSheet?: boolean;\n\n /**\n * Show pictures and videos in the media viewer, over the whole window:\n * \"View image\" and \"Play video\" open it, and so do the pictures and\n * videos in the detail sheet. Default true. With `false`, those buttons\n * open the detail sheet instead (unless `showDetailSheet` is `false` too).\n * `openMedia` opens the viewer either way.\n */\n mediaViewer?: boolean;\n\n /** The media viewer opened, or stepped to another picture or video. */\n onMediaOpen?: (event: OrbitMediaEvent) => void;\n\n /** The media viewer closed. */\n onMediaClose?: (event: OrbitMediaEvent) => void;\n\n /** The video in the media viewer started, paused, moved on, ended or was muted; while it plays, its time a few times a second. */\n onMediaState?: (state: OrbitMediaState) => void;\n\n /** Renders a note to HTML yourself. The HTML is used as-is: sanitize untrusted notes. */\n noteRenderer?: (note: string, context: { node: OrbitNode; format: 'markdown' | 'plain' }) => string;\n\n /** Resolves relative image, video and link URLs. */\n baseUrl?: string;\n\n /**\n * Node types by name: what nodes with `type: name` look like, draw inside\n * them, show in the detail sheet and offer as actions. They come before the\n * ones registered with `registerNodeType`.\n */\n nodeTypes?: Record<string, OrbitNodeType>;\n\n /** Your own buttons under the focused node and in its detail sheet, before the registered ones. */\n actions?: OrbitAction[];\n\n /**\n * Status words and how they look: a dot tone (`active`, `done`, `blocked`,\n * `todo`, `neutral`) or any CSS color, as in `{ review: 'active', 'on hold': '#A855F7' }`.\n */\n statuses?: Record<string, OrbitStatusStyle>;\n\n /**\n * The type a node that names none is drawn as, for display only: as if it\n * said `type: name`, with that type's look, content and actions. Orbit never\n * writes it to the map, and asks again whenever it draws; return undefined\n * to draw the node as it is. Called often: keep it quick.\n */\n nodeTypeFor?: (node: OrbitNode) => string | undefined;\n}\n\nexport const DEFAULT_OPTIONS: Required<Pick<RendererOptions, 'viewMode' | 'showRings' | 'interactive' | 'orbitAnimation' | 'orbitSpeed' | 'showControls'>> = {\n viewMode: 'focus',\n showRings: true,\n interactive: true,\n orbitAnimation: false,\n orbitSpeed: 90,\n showControls: true,\n};\n",
|
|
32
|
+
"/**\n * Changes to a map's tree, behind the renderer's `addNode`, `updateNode`,\n * `removeNode` and `moveNode`, and the map tools, which make them on a map\n * that isn't drawn too. Ids follow the parsers' rules, so a map saved with\n * `toMarkdown()` reads back with the same ids. Given the palette's rules,\n * each change keeps the colors of the top-level nodes it doesn't change\n * (see `keepBranchColors`).\n */\n\nimport type { OrbitNewNode, OrbitNode, OrbitNodeInput } from './types.js';\nimport { branchColorsBefore, keepBranchColors, type BranchColorRules } from './branch-colors.js';\nimport { findIndexedLinkedNode, indexNodes, nodeLinksOf } from './node-links.js';\nimport { findNodeById, getNodePath, nodeSlug, setParent } from './utils.js';\n\n/** The attributes `addNode` and `updateNode` set, in the order nodes list them. */\nconst ATTRIBUTE_KEYS = [\n 'icon', 'color', 'paletteColor', 'status', 'priority', 'tags', 'collapsed', 'type', 'typeVersion', 'link', 'note', 'noteFormat', 'image', 'video', 'embed', 'attrs',\n] as const satisfies readonly Exclude<keyof OrbitNodeInput, 'text'>[];\n\n/** Every id in the tree. */\nexport const nodeIds = (root: OrbitNode): Set<string> => {\n const ids = new Set<string>();\n\n const visit = (node: OrbitNode): void => {\n ids.add(node.id);\n\n for (const child of node.children) {\n visit(child);\n }\n };\n\n visit(root);\n return ids;\n};\n\n/** `base` when no node has it, otherwise `base-2`, `base-3`…, the way the parsers number repeated titles. */\nexport const uniqueId = (base: string, taken: ReadonlySet<string>): string => {\n if (!taken.has(base)) {\n return base;\n }\n\n let suffix = 2;\n\n while (taken.has(`${base}-${suffix}`)) {\n suffix += 1;\n }\n\n return `${base}-${suffix}`;\n};\n\n/**\n * A new node with `input`'s text, attributes and children, each with an id\n * from its text that no node in `taken` has, numbered in reading order as\n * the parsers number repeated titles.\n */\nexport const createNode = (input: OrbitNewNode, taken: ReadonlySet<string>): OrbitNode => {\n const ids = new Set(taken);\n\n const create = (entry: OrbitNewNode): OrbitNode => {\n const node: OrbitNode = { id: '', text: '', level: 0, children: [] };\n assignAttributes(node, { ...entry, text: typeof entry.text === 'string' ? entry.text : '' });\n node.id = uniqueId(nodeSlug(node.text), ids);\n ids.add(node.id);\n node.children = (entry.children ?? []).map(create);\n return node;\n };\n\n return create(input);\n};\n\n/** What `createNode` takes to add a copy of `node`: its text, attributes and children, without its id or its place in a source. */\nexport const newNodeFrom = (node: OrbitNode): OrbitNewNode => {\n const copy: OrbitNewNode = { text: node.text };\n const source = node as unknown as Record<string, unknown>;\n const target = copy as unknown as Record<string, unknown>;\n\n for (const key of ATTRIBUTE_KEYS) {\n if (source[key] !== undefined) {\n target[key] = source[key];\n }\n }\n\n if (node.children.length > 0) {\n copy.children = node.children.map(newNodeFrom);\n }\n\n return copy;\n};\n\n/** Sets the text and attributes `changes` names. An attribute set to `undefined` is removed. */\nexport const assignAttributes = (node: OrbitNode, changes: OrbitNodeInput): void => {\n if (typeof changes.text === 'string') {\n // A title is one line: a line break would end the heading in the saved map.\n node.text = changes.text.replace(/\\s*[\\r\\n]+\\s*/g, ' ').trim();\n }\n\n const target = node as unknown as Record<string, unknown>;\n\n for (const key of ATTRIBUTE_KEYS) {\n if (!(key in changes)) {\n continue;\n }\n\n const value: unknown = changes[key];\n\n if (value === undefined) {\n delete target[key];\n } else if (Array.isArray(value)) {\n target[key] = [...value];\n } else if (typeof value === 'object' && value !== null) {\n target[key] = { ...value };\n } else {\n target[key] = value;\n }\n }\n};\n\n/**\n * Whether the node's id was made from its text, as the parsers make ids,\n * rather than set with an `id` attribute: `research`, or `research-2` for\n * a second \"Research\". Suffixes start at 2 (the parsers never make `-1`),\n * so a hand-set `foo-1` is explicit.\n */\nexport const hasTextId = (node: OrbitNode): boolean => {\n const base = nodeSlug(node.text);\n\n if (node.id === base) {\n return true;\n }\n\n const suffix = node.id.startsWith(`${base}-`) ? node.id.slice(base.length + 1) : '';\n return /^[1-9]\\d*$/.test(suffix) && Number(suffix) >= 2;\n};\n\n/** Whether a link in the map, a node's link or one in a note, points at `node`. */\nexport const isLinkedTo = (root: OrbitNode, node: OrbitNode): boolean => {\n const nodes = indexNodes(root);\n const visit = (current: OrbitNode): boolean =>\n nodeLinksOf(current).some((href) => findIndexedLinkedNode(nodes, href) === node) || current.children.some(visit);\n return visit(root);\n};\n\n/** Puts `node` among `parent`'s children at `index` (clamped; default last), with its levels and parent links. */\nexport const insertChild = (parent: OrbitNode, node: OrbitNode, parentLevel: number, index?: number): void => {\n const count = parent.children.length;\n const position = index === undefined || !Number.isFinite(index) ? count : Math.min(count, Math.max(0, Math.trunc(index)));\n parent.children.splice(position, 0, node);\n place(node, parent, parentLevel + 1);\n};\n\n/** Sets `level` through a subtree, and each node's link to its parent. */\nconst place = (node: OrbitNode, parent: OrbitNode, level: number): void => {\n setParent(node, parent);\n node.level = level;\n\n for (const child of node.children) {\n place(child, node, level + 1);\n }\n};\n\n/** Takes `node` out of `parent`'s children. */\nexport const detachChild = (parent: OrbitNode, node: OrbitNode): void => {\n const index = parent.children.indexOf(node);\n\n if (index !== -1) {\n parent.children.splice(index, 1);\n }\n\n setParent(node, undefined);\n};\n\n/** Adds `input`, with its children, under `parentId` at `index` among its children (default: last). Null when there's no such parent. */\nexport const addToTree = (root: OrbitNode, parentId: string, input: OrbitNewNode, index?: number, colors?: BranchColorRules): { node: OrbitNode; parent: OrbitNode } | null => {\n const path = getNodePath(root, parentId);\n\n if (path.length === 0) {\n return null;\n }\n\n const parent = path[path.length - 1];\n const before = colors && branchColorsBefore(root, colors);\n const node = createNode(input, nodeIds(root));\n insertChild(parent, node, path.length - 1, index);\n\n if (colors && before) {\n keepBranchColors(root, before, colors, { node, keepsColor: false });\n }\n\n return { node, parent };\n};\n\n/**\n * Sets the text and attributes `changes` names on `id`. New text gives the\n * node a new id when its id came from its text and no link points at it,\n * so the saved map needs no id attribute. Null when there's no such node.\n */\nexport const updateInTree = (root: OrbitNode, id: string, changes: OrbitNodeInput, colors?: BranchColorRules): { node: OrbitNode; previousId: string } | null => {\n const node = findNodeById(root, id);\n\n if (!node) {\n return null;\n }\n\n const previousId = node.id;\n const previousText = node.text;\n const idFollowsText = typeof changes.text === 'string' && hasTextId(node) && !isLinkedTo(root, node);\n const before = colors && branchColorsBefore(root, colors);\n assignAttributes(node, changes);\n\n if (idFollowsText && node.text !== previousText) {\n const taken = nodeIds(root);\n taken.delete(node.id);\n node.id = uniqueId(nodeSlug(node.text), taken);\n }\n\n if (colors && before) {\n keepBranchColors(root, before, colors, { node, keepsColor: false });\n }\n\n return { node, previousId };\n};\n\n/** Takes `id` and everything under it out of the tree. Null when there's no such node, or for the root. */\nexport const removeFromTree = (root: OrbitNode, id: string, colors?: BranchColorRules): { node: OrbitNode; parent: OrbitNode } | null => {\n const path = getNodePath(root, id);\n\n if (path.length < 2) {\n return null;\n }\n\n const node = path[path.length - 1];\n const parent = path[path.length - 2];\n const before = colors && branchColorsBefore(root, colors);\n detachChild(parent, node);\n\n if (colors && before) {\n keepBranchColors(root, before, colors);\n }\n\n return { node, parent };\n};\n\n/**\n * Moves `id`, with everything under it, under `parentId` at `index` among\n * its children (default: last). Null when either node is missing, the node\n * is the root, or `parentId` is inside it.\n */\nexport const moveInTree = (root: OrbitNode, id: string, parentId: string, index?: number, colors?: BranchColorRules): { node: OrbitNode; from: OrbitNode; to: OrbitNode } | null => {\n const path = getNodePath(root, id);\n const parentPath = getNodePath(root, parentId);\n const node = path[path.length - 1];\n\n if (path.length < 2 || parentPath.length === 0 || parentPath.includes(node)) {\n return null;\n }\n\n const from = path[path.length - 2];\n const to = parentPath[parentPath.length - 1];\n const before = colors && branchColorsBefore(root, colors);\n detachChild(from, node);\n insertChild(to, node, parentPath.length - 1, index);\n\n if (colors && before) {\n keepBranchColors(root, before, colors, { node, keepsColor: true });\n }\n\n return { node, from, to };\n};\n",
|
|
33
|
+
"export default \".orbit{position:relative;width:100%;height:100%;overflow:hidden;contain:size layout style;background:var(--_orbit-surface-pattern),var(--_orbit-surface);color:var(--_orbit-text);font-family:var(--_orbit-font-family);font-kerning:normal;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-font-smoothing:antialiased}.orbit__canvas{display:block;width:100%;height:100%;overflow:visible;touch-action:none;outline:none;cursor:grab;-webkit-user-select:none;user-select:none}.orbit__world{cursor:grab}.orbit--static .orbit__canvas{cursor:default;touch-action:auto}.orbit--static .orbit__world{cursor:default}.orbit--dragging .orbit__canvas,.orbit--dragging .orbit-ring-band{cursor:grabbing}.orbit--embedded .orbit__canvas{touch-action:pan-x pan-y}.orbit--embedded[data-orbit-view=focus] .orbit-node--planet,.orbit--embedded[data-orbit-view=focus] .orbit-ring-band{touch-action:none}.orbit__contents,.orbit__labels,.orbit__overlay{position:absolute;inset:0;pointer-events:none}.orbit__labels{transform-origin:0 0}.orbit__live{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.orbit [hidden]{display:none !important}.orbit-rendered{position:relative}.orbit-rendered>.orbit{position:absolute;inset:0}.orbit-visually-hidden{position:absolute !important;width:1px !important;height:1px !important;overflow:hidden !important;clip-path:inset(50%) !important;white-space:nowrap !important}.orbit-icon{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round;flex:none}.orbit-icon--filled{fill:currentColor}.orbit-icon--glyph{display:inline-grid;place-items:center;font-size:16px;font-weight:650;line-height:1}.orbit-node-content{position:absolute;top:0;left:0;display:grid;place-items:center;width:100px;height:100px;overflow:hidden;border-radius:50%;color:var(--_orbit-node-text);font-family:var(--_orbit-label-font);font-size:22px;line-height:1.1;text-align:center;pointer-events:none;contain:layout paint}.orbit-ring{fill:none;stroke:color-mix(in oklab, var(--orbit-ring-color, var(--_orbit-ring-stroke)) var(--_orbit-ring-tint), var(--_orbit-ring-stroke));stroke-width:var(--_orbit-ring-width);stroke-dasharray:var(--_orbit-ring-dash);stroke-linecap:round;stroke-opacity:var(--_orbit-ring-opacity);vector-effect:non-scaling-stroke;pointer-events:none}.orbit-ring-band{fill:none;stroke:rgba(0,0,0,0);pointer-events:stroke}.orbit-link{stroke:color-mix(in oklab, var(--orbit-link-color, var(--_orbit-link-stroke)) var(--_orbit-link-tint), var(--_orbit-link-stroke));stroke-width:var(--_orbit-link-width);stroke-dasharray:var(--_orbit-link-dash);stroke-linecap:round;stroke-opacity:var(--_orbit-link-opacity);vector-effect:non-scaling-stroke;pointer-events:none}.orbit-shade__highlight{stop-color:var(--_orbit-node-highlight)}.orbit-shade__highlight-fade{stop-color:color-mix(in srgb, var(--_orbit-node-highlight) 20%, transparent)}.orbit-shade__terminator-start{stop-color:var(--_orbit-node-terminator);stop-opacity:0}.orbit-shade__terminator{stop-color:var(--_orbit-node-terminator)}.orbit-shade__shading{stop-color:var(--_orbit-node-shading)}.orbit-node{cursor:pointer;outline:none}.orbit-node__body{transform-origin:0 0;transition:transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1)}.orbit-node:not(.orbit-node--crowded):hover .orbit-node__body{transform:scale(1.045)}.orbit-node:not(.orbit-node--crowded):active .orbit-node__body{transform:scale(0.97)}.orbit-node__shadow{fill:color-mix(in oklab, var(--orbit-node-color) var(--_orbit-node-shadow-tint), var(--_orbit-node-shadow));opacity:var(--_orbit-node-shadow-opacity);transform:translate(0, calc(var(--_orbit-node-shadow-offset) * 1px)) scale(var(--_orbit-node-shadow-size));transition:opacity 320ms ease,transform 320ms ease,display 320ms allow-discrete}@starting-style{.orbit-node__shadow{opacity:0}}.orbit-node--sun .orbit-node__shadow{opacity:var(--_orbit-sun-shadow-opacity);transform:translate(0, calc(var(--_orbit-node-shadow-offset) * 1px)) scale(var(--_orbit-sun-shadow-size))}.orbit-node--node .orbit-node__shadow{display:none}.orbit-node__halo{display:none;fill:none;stroke:color-mix(in oklab, var(--orbit-node-color) var(--_orbit-sun-halo-tint), var(--_orbit-sun-halo));stroke-width:var(--_orbit-sun-halo-width);stroke-dasharray:var(--_orbit-sun-halo-dash);stroke-opacity:var(--_orbit-sun-halo-opacity);vector-effect:non-scaling-stroke;transform:scale(var(--_orbit-sun-halo-size));opacity:0;transition:opacity 320ms ease,display 320ms allow-discrete}.orbit-node--sun .orbit-node__halo{display:inline;opacity:1}@starting-style{.orbit-node--sun .orbit-node__halo{opacity:0}}.orbit-node--flat .orbit-node__shadow,.orbit-node--flat .orbit-node__halo{display:none;opacity:0}.orbit-node__disc{fill-opacity:var(--_orbit-node-fill-opacity)}.orbit-node__shade,.orbit-node__image,.orbit-node__shadow,.orbit-node__halo,.orbit-node__status,.orbit-node__marker,.orbit-node__play{pointer-events:none}.orbit-node__shade{stroke:color-mix(in oklab, var(--orbit-node-color, var(--_orbit-node-stroke)) var(--_orbit-node-stroke-tint), var(--_orbit-node-stroke));stroke-width:var(--_orbit-node-stroke-width);vector-effect:non-scaling-stroke}.orbit-node--crowded .orbit-node__shade{stroke-width:calc(var(--_orbit-node-stroke-width)*.04);vector-effect:none}.orbit-node__focus-ring{display:none;fill:none;stroke:var(--_orbit-focus-ring);stroke-width:2.5;vector-effect:non-scaling-stroke;pointer-events:none;transition:opacity 120ms ease}.orbit-node:focus-visible .orbit-node__focus-ring{display:inline}@starting-style{.orbit-node:focus-visible .orbit-node__focus-ring{opacity:0}}.orbit-node__status{stroke:var(--_orbit-badge-stroke);stroke-width:.04}.orbit-node__status--active{fill:var(--_orbit-status-active)}.orbit-node__status--done{fill:var(--_orbit-status-done)}.orbit-node__status--blocked{fill:var(--_orbit-status-blocked)}.orbit-node__status--todo{fill:var(--_orbit-status-todo)}.orbit-node__status--neutral{fill:var(--_orbit-status-neutral)}.orbit-node--sun .orbit-node__status{stroke-width:.025}.orbit-node__marker{fill:var(--_orbit-note-indicator);stroke:var(--_orbit-badge-stroke);stroke-width:.04}.orbit-node__play{fill:rgba(15,23,42,.62)}.orbit-node__play path{fill:#fff}.orbit-node--moon{cursor:pointer}.orbit-node--sun .orbit-node__marker,.orbit-node--sun .orbit-node__play{display:none}.orbit-node--moon .orbit-node__disc{fill-opacity:var(--_orbit-moon-opacity)}.orbit-node--moon .orbit-node__shade{stroke-width:calc(var(--_orbit-node-stroke-width)*.7)}.orbit-node--speck .orbit-node__body{transform-box:fill-box;transform-origin:center}.orbit-node--speck .orbit-node__marker,.orbit-node--speck .orbit-node__status,.orbit-node--speck .orbit-node__play{display:none}.orbit-node--speck .orbit-node__shade{stroke-width:calc(var(--_orbit-node-stroke-width)*var(--orbit-speck-radius)*var(--_orbit-speck-rim, 0.2));vector-effect:none}.orbit-node--speck.orbit-node--moon .orbit-node__shade{stroke-width:calc(var(--_orbit-node-stroke-width)*.7*var(--orbit-speck-radius)*var(--_orbit-speck-rim, 0.2))}.orbit-node--speck.orbit-node--crowded .orbit-node__shade{stroke-width:calc(var(--_orbit-node-stroke-width)*.04*var(--orbit-speck-radius))}.orbit-label{position:absolute;top:0;left:0;display:flex;flex-direction:column;align-items:center;gap:2px;width:max-content;color:var(--_orbit-node-text);font-family:var(--_orbit-label-font);font-size:13px;font-weight:var(--_orbit-label-weight);line-height:1.22;text-align:center;letter-spacing:var(--_orbit-label-letter-spacing);overflow-wrap:break-word;hyphens:auto;will-change:transform,opacity;user-select:none}.orbit-label__icon{font-size:1.45em;line-height:1}.orbit-label__text{white-space:pre}.orbit-label--no-icon .orbit-label__icon{display:none}.orbit-label--sun{color:var(--_orbit-root-text);font-family:var(--_orbit-display-font);font-size:16px;font-weight:var(--_orbit-display-weight)}.orbit-label--node{font-size:12px}.orbit-label--light{color:var(--_orbit-node-text-inverse);text-shadow:var(--_orbit-label-shadow)}.orbit-label--outside{box-sizing:border-box;width:max-content;max-width:160px;padding:2px 8px;border-radius:999px;background:var(--_orbit-control-background);color:var(--_orbit-control-text);font-size:11.5px;box-shadow:0 1px 2px rgba(15,23,42,.08)}.orbit-label--sun.orbit-label--outside{max-width:280px}.orbit-label--outside .orbit-label__icon{display:none}.orbit-label--outside .orbit-label__text{display:-webkit-box;overflow:hidden;-webkit-box-orient:vertical;-webkit-line-clamp:1;line-clamp:1;white-space:normal}.orbit-label--sun.orbit-label--outside .orbit-label__text{-webkit-line-clamp:2;line-clamp:2}.orbit-label--wrapped{max-width:var(--orbit-pill-width, 120px);border-radius:11px}.orbit-label--wrapped .orbit-label__text{-webkit-line-clamp:2;line-clamp:2}.orbit-count{position:absolute;top:0;left:0;padding:1px 6px;border-radius:999px;background:var(--_orbit-control-background);color:var(--_orbit-control-muted-text);z-index:1;font-size:10.5px;font-weight:650;line-height:13px;font-variant-numeric:tabular-nums;translate:-50% -50%;pointer-events:none}.orbit-actions{position:absolute;top:0;left:0;display:flex;flex-wrap:wrap;justify-content:center;gap:8px;translate:-50% 0;opacity:0;visibility:hidden;transition:opacity 180ms ease,visibility 0s linear 180ms;pointer-events:auto}.orbit-actions--visible{opacity:1;visibility:visible;transition:opacity 220ms ease 60ms}.orbit-action{display:inline-grid;place-items:center;width:36px;height:36px;padding:0;border:1px solid var(--_orbit-action-border);border-radius:999px;background:var(--_orbit-action-background);color:var(--_orbit-action-text);box-shadow:var(--_orbit-action-shadow);cursor:pointer;transition:transform 160ms ease,box-shadow 160ms ease}.orbit-action:hover{transform:translateY(-1px)}.orbit-action:active{transform:scale(0.96)}.orbit-action:focus-visible{outline:2.5px solid var(--_orbit-focus-ring);outline-offset:2px}.orbit-add{cursor:pointer;outline:none}.orbit-add__body{transform-origin:0 0;transition:transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1)}.orbit-add:hover .orbit-add__body{transform:scale(1.06)}.orbit-add:active .orbit-add__body{transform:scale(0.95)}.orbit-add__disc{fill:var(--_orbit-control-background);fill-opacity:.5;stroke:var(--_orbit-muted-text);stroke-opacity:.6;stroke-width:1.5;stroke-dasharray:5 4;vector-effect:non-scaling-stroke;transition:fill-opacity 160ms ease,stroke-opacity 160ms ease}.orbit-add:hover .orbit-add__disc{fill-opacity:.8;stroke-opacity:.9}.orbit-add__plus{fill:none;stroke:var(--_orbit-muted-text);stroke-width:2.5;stroke-linecap:round;vector-effect:non-scaling-stroke;pointer-events:none}.orbit-add__focus-ring{fill:none;stroke:var(--_orbit-focus-ring);stroke-width:2.5;vector-effect:non-scaling-stroke;opacity:0;pointer-events:none;transition:opacity 120ms ease}.orbit-add:focus-visible .orbit-add__focus-ring{opacity:1}.orbit-add--pending .orbit-add__disc{fill-opacity:1;stroke:var(--_orbit-focus-ring);stroke-opacity:1;stroke-width:2;stroke-dasharray:none}.orbit-add--pending .orbit-add__plus{display:none}.orbit-add--drop .orbit-add__plus{display:none}.orbit-add--drop .orbit-add__disc{fill-opacity:.35;stroke:var(--_orbit-focus-ring);stroke-opacity:.9}.orbit-add--drop .orbit-add__body{animation:orbit-drop-place 900ms ease-in-out infinite alternate}.orbit-add--waiting{opacity:.45}.orbit-add--held{pointer-events:none}.orbit-add--waiting .orbit-add__body{animation:none}@keyframes orbit-drop-place{from{transform:scale(0.92)}to{transform:scale(1)}}.orbit-node--editing .orbit-node__focus-ring{display:inline}.orbit-node--lifted .orbit-node__body{transform:scale(1.12)}.orbit-node--lifted .orbit-node__shadow{opacity:min(1,var(--_orbit-node-shadow-opacity)*1.6);transform:translate(0, calc(var(--_orbit-node-shadow-offset) * 2.5px)) scale(calc(var(--_orbit-node-shadow-size) * 1.08))}.orbit-node--drop-target .orbit-node__body{transform:scale(1.1)}.orbit-node--drop-target .orbit-node__focus-ring{display:inline}.orbit__carried{pointer-events:none}.orbit-editor{position:absolute;top:0;left:0;box-sizing:border-box;display:block;min-height:0;margin:0;padding:1px 2px;overflow:hidden;border:none;border-radius:6px;outline:none;background:rgba(0,0,0,0);color:var(--_orbit-node-text);caret-color:var(--_orbit-focus-ring);font-family:var(--_orbit-label-font);font-size:16px;font-weight:var(--_orbit-label-weight);line-height:1.22;letter-spacing:var(--_orbit-label-letter-spacing);text-align:center;white-space:pre-wrap;overflow-wrap:break-word;resize:none;pointer-events:auto;user-select:text;-webkit-user-select:text}.orbit-editor::placeholder{color:currentColor;opacity:.45}.orbit-editor--sun{color:var(--_orbit-root-text);font-family:var(--_orbit-display-font);font-weight:var(--_orbit-display-weight)}.orbit-editor--light{color:var(--_orbit-node-text-inverse)}.orbit-editor--slot{color:var(--_orbit-control-text)}.orbit-editor--floating{padding:4px 8px;border-radius:10px;background:var(--_orbit-control-background);color:var(--_orbit-control-text);box-shadow:var(--_orbit-control-shadow)}.orbit-editor[hidden]{display:none}.orbit-empty{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;padding:24px;color:var(--_orbit-muted-text);font-size:13px;text-align:center;pointer-events:none}.orbit-empty strong{color:var(--_orbit-text);font-size:15px;font-weight:650}.orbit-outline--visible{position:absolute;top:60px;bottom:12px;left:12px;width:min(320px,100% - 24px);padding:8px;overflow:auto;overscroll-behavior:contain;border:1px solid var(--_orbit-control-border);border-radius:14px;background:var(--_orbit-control-background);box-shadow:var(--_orbit-control-shadow);backdrop-filter:blur(var(--_orbit-control-blur));-webkit-backdrop-filter:blur(var(--_orbit-control-blur));color:var(--_orbit-control-text);font-size:13px;z-index:1}.orbit-outline--visible ul{margin:0;padding:0;list-style:none}.orbit-outline--visible ul ul{margin-left:10px;padding-left:10px;border-left:1px solid var(--_orbit-control-border)}.orbit-outline--visible button,.orbit-outline--visible span{display:block;width:100%;padding:5px 8px;border:0;border-radius:8px;background:none;color:inherit;font:inherit;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.orbit-outline--visible button{cursor:pointer}.orbit-outline--visible button:hover{background:color-mix(in srgb, var(--_orbit-control-text) 8%, transparent)}.orbit-outline--visible button:focus-visible{outline:2.5px solid var(--_orbit-focus-ring);outline-offset:-2px}.orbit-outline--visible button[aria-current=true]{background:var(--_orbit-control-active-background);color:var(--_orbit-control-active-text)}.orbit-tooltip{position:absolute;top:0;left:0;max-width:260px;padding:8px 12px;border-radius:10px;background:var(--_orbit-tooltip-background);color:var(--_orbit-tooltip-text);font-size:12.5px;line-height:1.4;box-shadow:0 8px 24px rgba(15,23,42,.18);pointer-events:none;translate:-50% calc(-100% - 10px);opacity:0;transition:opacity 140ms ease}.orbit-tooltip--visible{opacity:1}.orbit-tooltip__title{display:block;font-weight:650}.orbit-tooltip__detail{display:block;margin-top:2px;opacity:.82}.orbit-controls{position:absolute;inset:0;pointer-events:none}.orbit-controls__top{position:absolute;top:12px;right:12px;left:12px;display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.orbit-controls__start{display:flex;align-items:center;gap:8px;min-width:0}.orbit-controls__zoom{position:absolute;right:12px;bottom:12px}.orbit-panel{display:inline-flex;align-items:center;gap:2px;min-width:0;padding:3px;border:1px solid var(--_orbit-control-border);border-radius:12px;background:var(--_orbit-control-background);box-shadow:var(--_orbit-control-shadow);backdrop-filter:blur(var(--_orbit-control-blur));-webkit-backdrop-filter:blur(var(--_orbit-control-blur));pointer-events:auto}.orbit-panel--vertical{flex-direction:column}.orbit-button{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:32px;height:32px;padding:0 8px;border:0;border-radius:9px;background:rgba(0,0,0,0);color:var(--_orbit-control-muted-text);font:inherit;font-size:12.5px;font-weight:600;white-space:nowrap;cursor:pointer;transition:background-color 140ms ease,color 140ms ease}.orbit-button:hover{color:var(--_orbit-control-text);background:color-mix(in srgb, var(--_orbit-control-text) 8%, transparent)}.orbit-button:focus-visible{outline:2.5px solid var(--_orbit-focus-ring);outline-offset:1px}.orbit-button[aria-pressed=true],.orbit-button--active{background:var(--_orbit-control-active-background);color:var(--_orbit-control-active-text)}.orbit-button--icon{width:32px;padding:0}.orbit-breadcrumbs{display:flex;align-items:center;min-width:0}.orbit-breadcrumbs__item{max-width:180px;min-width:0}.orbit-breadcrumbs__item span{overflow:hidden;text-overflow:ellipsis}.orbit-breadcrumbs__item[aria-current=location]{color:var(--_orbit-control-text);cursor:default}.orbit-breadcrumbs__separator{flex:none;width:14px;height:14px;color:var(--_orbit-control-muted-text);opacity:.7}.orbit-back{display:none;max-width:180px}.orbit-back span{overflow:hidden;text-overflow:ellipsis}.orbit-hint{position:absolute;left:50%;bottom:16px;padding:7px 14px;border:1px solid var(--_orbit-control-border);border-radius:999px;background:var(--_orbit-control-background);color:var(--_orbit-control-text);font-size:12.5px;font-weight:600;box-shadow:var(--_orbit-control-shadow);backdrop-filter:blur(var(--_orbit-control-blur));translate:-50% 0;opacity:0;transition:opacity 200ms ease;pointer-events:none}.orbit-hint--visible{opacity:1}.orbit--narrow .orbit-controls__crumbs{display:none}.orbit--narrow .orbit-back{display:inline-flex}.orbit--narrow .orbit-segmented__label{display:none}@media(pointer: coarse){.orbit-button{min-width:40px;height:40px}.orbit-button--icon{width:40px}.orbit-action{width:42px;height:42px}}.orbit-sheet{box-sizing:border-box;width:min(560px,100vw - 32px);max-height:86vh;max-height:min(86vh,86dvh);margin:auto;padding:0;border:1px solid var(--_orbit-sheet-border);border-radius:20px;background:var(--_orbit-sheet-background);color:var(--_orbit-sheet-text);font-family:var(--_orbit-font-family);box-shadow:var(--_orbit-sheet-shadow);backdrop-filter:blur(var(--_orbit-sheet-blur));-webkit-backdrop-filter:blur(var(--_orbit-sheet-blur));overflow:hidden}.orbit-sheet[open]{display:flex;flex-direction:column;animation:orbit-sheet-in 220ms cubic-bezier(0.2, 0.8, 0.2, 1)}.orbit-sheet::backdrop{background:var(--_orbit-sheet-backdrop);backdrop-filter:blur(6px)}.orbit-sheet__header{display:flex;align-items:flex-start;gap:12px;padding:20px 20px 12px 24px}.orbit-sheet__handle{display:none}.orbit-sheet__heading{flex:1;min-width:0}.orbit-sheet__path{margin:0 0 4px;color:var(--_orbit-sheet-muted-text);font-size:12px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.orbit-sheet__title{margin:0;font-family:var(--_orbit-display-font);font-size:20px;font-weight:var(--_orbit-display-weight);line-height:1.25;overflow-wrap:anywhere}.orbit-sheet__chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}.orbit-sheet__chip{display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:999px;background:var(--_orbit-chip-background);color:var(--_orbit-chip-text);font-size:12px;font-weight:600}.orbit-sheet__chip::before{content:\\\"\\\";display:none;width:7px;height:7px;border-radius:50%;background:currentColor}.orbit-sheet__chip--status::before{display:block;background:var(--orbit-chip-dot, var(--_orbit-status-neutral))}.orbit-sheet__chip--type{background:none;box-shadow:inset 0 0 0 1px var(--_orbit-chip-background)}.orbit-sheet__details{margin-bottom:16px}.orbit-sheet__actions{display:flex;flex-wrap:wrap;gap:8px;margin-left:auto}.orbit-sheet__action{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border:1px solid var(--_orbit-sheet-border);border-radius:999px;background:none;color:var(--_orbit-sheet-text);font:inherit;font-size:14px;font-weight:600;cursor:pointer}.orbit-sheet__action:hover{background:color-mix(in srgb, var(--_orbit-sheet-text) 8%, transparent)}.orbit-sheet__action:focus-visible{outline:2.5px solid var(--_orbit-focus-ring);outline-offset:2px}.orbit-sheet__action .orbit-icon{width:16px;height:16px}.orbit-sheet__action .orbit-icon--glyph{font-size:14px}.orbit-sheet__close{flex:none}.orbit-sheet__body{flex:1;min-height:0;padding:0 24px 20px;overflow:auto;overscroll-behavior:contain;font-size:15px;line-height:1.6}.orbit-sheet__media{margin:0 0 16px}.orbit-sheet__media img,.orbit-sheet__media video{display:block;width:100%;max-height:60vh;object-fit:contain;border-radius:12px;background:var(--_orbit-chip-background)}.orbit-sheet__media iframe{display:block;width:100%;aspect-ratio:16/9;border:0;border-radius:12px;background:#000}.orbit-sheet__media figcaption{margin-top:8px;color:var(--_orbit-sheet-muted-text);font-size:13px}.orbit-sheet__picture{display:block;width:100%;padding:0;border:0;border-radius:12px;background:none;cursor:zoom-in}.orbit-sheet__picture:focus-visible{outline:2.5px solid var(--_orbit-focus-ring);outline-offset:2px}.orbit-sheet__expand{display:inline-flex;align-items:center;gap:6px;margin-top:8px;padding:5px 12px;border:1px solid var(--_orbit-sheet-border);border-radius:999px;background:none;color:var(--_orbit-sheet-text);font:inherit;font-size:13px;font-weight:600;cursor:pointer}.orbit-sheet__expand:hover{background:color-mix(in srgb, var(--_orbit-sheet-text) 8%, transparent)}.orbit-sheet__expand:focus-visible{outline:2.5px solid var(--_orbit-focus-ring);outline-offset:2px}.orbit-sheet__expand .orbit-icon{width:16px;height:16px}.orbit-sheet__note>:first-child{margin-top:0}.orbit-sheet__note>:last-child{margin-bottom:0}.orbit-sheet__note p,.orbit-sheet__note ul,.orbit-sheet__note ol,.orbit-sheet__note blockquote,.orbit-sheet__note pre{margin:0 0 12px}.orbit-sheet__note ul,.orbit-sheet__note ol{padding-left:22px}.orbit-sheet__note h3,.orbit-sheet__note h4,.orbit-sheet__note h5{margin:18px 0 8px;font-size:15px;font-weight:650}.orbit-sheet__note a{color:var(--_orbit-link-text);text-underline-offset:2px}.orbit-sheet__note code{padding:1px 5px;border-radius:6px;background:var(--_orbit-chip-background);font-size:.92em}.orbit-sheet__note pre{padding:12px;border-radius:10px;background:var(--_orbit-chip-background);overflow:auto}.orbit-sheet__note pre code{padding:0;background:none}.orbit-sheet__note blockquote{padding-left:12px;border-left:3px solid var(--_orbit-sheet-border);color:var(--_orbit-sheet-muted-text)}.orbit-sheet__footer{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:12px 16px;border-top:1px solid var(--_orbit-sheet-border)}.orbit-sheet__link{padding:0;border:0;background:none;color:var(--_orbit-link-text);font:inherit;font-weight:600;text-decoration:none;cursor:pointer}.orbit-sheet .orbit-button{color:var(--_orbit-sheet-muted-text)}.orbit-sheet .orbit-button:hover{color:var(--_orbit-sheet-text);background:color-mix(in srgb, var(--_orbit-sheet-text) 8%, transparent)}@media(max-width: 640px){.orbit-sheet{width:100%;max-width:100%;max-height:88vh;max-height:88dvh;margin:auto 0 0;border-bottom:0;border-radius:20px 20px 0 0}.orbit-sheet[open]{animation-name:orbit-sheet-up}.orbit-sheet__handle{display:block;width:40px;height:5px;margin:8px auto 0;border-radius:999px;background:var(--_orbit-sheet-border);touch-action:none}}@media(min-width: 960px){.orbit-sheet{width:min(440px,40vw);height:100vh;height:100dvh;max-height:100vh;max-height:100dvh;margin:0 0 0 auto;border-width:0 0 0 1px;border-radius:0}.orbit-sheet[open]{animation-name:orbit-sheet-side}.orbit-sheet::backdrop{backdrop-filter:none}}@keyframes orbit-sheet-side{from{transform:translateX(100%)}}@keyframes orbit-sheet-in{from{opacity:0;transform:translateY(8px) scale(0.98)}}@keyframes orbit-sheet-up{from{transform:translateY(100%)}}.orbit-viewer{position:fixed;inset:0;box-sizing:border-box;width:auto;height:auto;max-width:none;max-height:none;margin:0;padding:0;border:0;overflow:hidden;background:rgba(0,0,0,0);color:var(--_orbit-sheet-text);font-family:var(--_orbit-font-family);outline:none;overscroll-behavior:contain;touch-action:none}.orbit-viewer[open]{display:grid;grid-template-rows:auto minmax(0, 1fr) auto;animation:orbit-viewer-in 180ms ease-out}.orbit-viewer::backdrop{background:rgba(0,0,0,0)}.orbit-viewer::before{content:\\\"\\\";position:absolute;inset:0;background:var(--_orbit-sheet-background);backdrop-filter:blur(var(--_orbit-sheet-blur));-webkit-backdrop-filter:blur(var(--_orbit-sheet-blur));opacity:calc(1 - var(--_orbit-viewer-pull, 0)*.8)}.orbit-viewer__bar{grid-row:1;position:relative;display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:40px;padding:max(12px,env(safe-area-inset-top)) max(16px,env(safe-area-inset-right)) 4px max(16px,env(safe-area-inset-left));opacity:calc(1 - var(--_orbit-viewer-pull, 0))}.orbit-viewer__counter{margin:0;color:var(--_orbit-sheet-muted-text);font-size:13px;font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}.orbit-viewer__tools{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px;margin-left:auto}.orbit-viewer__stage{grid-row:2;position:relative;overflow:hidden;touch-action:none}.orbit-viewer__media{position:absolute;inset:0}.orbit-viewer__media--entering{animation:orbit-viewer-show 200ms ease-out}.orbit-viewer--settling .orbit-viewer__media{transition:transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1)}.orbit-viewer__picture{position:absolute;box-sizing:content-box;max-width:none;max-height:none;margin:0;padding:0;border:0;transform-origin:center;cursor:zoom-in;-webkit-user-select:none;user-select:none;-webkit-user-drag:none}.orbit-viewer__picture--gliding{transition:transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1)}.orbit-viewer--zoomed .orbit-viewer__picture{cursor:grab}.orbit-viewer--dragging .orbit-viewer__picture{cursor:grabbing}.orbit-viewer__player{position:absolute;overflow:hidden;border-radius:12px;background:#000;box-shadow:var(--_orbit-sheet-shadow)}.orbit-viewer__player iframe,.orbit-viewer__player video{display:block;width:100%;height:100%;border:0;background:#000}.orbit-viewer__status{position:absolute;inset:0;display:grid;place-items:center;align-content:center;gap:12px;margin:0;padding:24px;color:var(--_orbit-sheet-muted-text);font-size:14px;text-align:center;pointer-events:none}.orbit-viewer__status--loading::before{content:\\\"\\\";width:28px;height:28px;border:3px solid currentColor;border-top-color:rgba(0,0,0,0);border-radius:50%;opacity:.7;animation:orbit-viewer-spin 800ms linear infinite}.orbit-viewer__step{position:absolute;top:calc(50% - 22px);width:44px;height:44px;border:1px solid var(--_orbit-control-border);border-radius:999px;background:var(--_orbit-control-background);color:var(--_orbit-control-text);box-shadow:var(--_orbit-control-shadow);backdrop-filter:blur(var(--_orbit-control-blur));-webkit-backdrop-filter:blur(var(--_orbit-control-blur))}.orbit-viewer__step:hover{background:color-mix(in srgb, var(--_orbit-control-text) 8%, var(--_orbit-control-background))}.orbit-viewer__step:disabled{opacity:.4;cursor:default}.orbit-viewer__step--previous{left:max(12px,env(safe-area-inset-left))}.orbit-viewer__step--next{right:max(12px,env(safe-area-inset-right))}.orbit-viewer__caption{grid-row:3;position:relative;max-height:30vh;padding:6px max(24px,env(safe-area-inset-right)) max(16px,env(safe-area-inset-bottom)) max(24px,env(safe-area-inset-left));overflow:auto;overscroll-behavior:contain;touch-action:pan-y;text-align:center;opacity:calc(1 - var(--_orbit-viewer-pull, 0))}.orbit-viewer__title{max-width:72ch;margin:0 auto;font-family:var(--_orbit-display-font);font-size:17px;font-weight:var(--_orbit-display-weight);line-height:1.3;overflow-wrap:anywhere}.orbit-viewer__text,.orbit-viewer__description{max-width:72ch;margin:4px auto 0;font-size:14px;line-height:1.5;overflow-wrap:anywhere}.orbit-viewer__description{color:var(--_orbit-sheet-muted-text);font-size:13px}.orbit-viewer--still .orbit-viewer__bar,.orbit-viewer--still .orbit-viewer__step{display:none}.orbit-viewer--still .orbit-viewer__media{pointer-events:none}@media(max-width: 640px){.orbit-viewer__bar{padding-right:max(12px,env(safe-area-inset-right));padding-left:max(12px,env(safe-area-inset-left))}.orbit-viewer__tools{gap:6px}.orbit-viewer__step--previous{left:max(8px,env(safe-area-inset-left))}.orbit-viewer__step--next{right:max(8px,env(safe-area-inset-right))}.orbit-viewer__caption{padding-right:max(16px,env(safe-area-inset-right));padding-left:max(16px,env(safe-area-inset-left))}.orbit-viewer__title{font-size:16px}}@keyframes orbit-viewer-in{from{opacity:0}}@keyframes orbit-viewer-show{from{opacity:0;transform:scale(0.98)}}@keyframes orbit-viewer-spin{to{transform:rotate(360deg)}}.orbit-error{box-sizing:border-box;margin:12px;padding:14px 16px;border:1px dashed var(--_orbit-error-border);border-radius:12px;background:var(--_orbit-error-background);color:var(--_orbit-error-text);font:14px/1.45 var(--_orbit-font-family)}@supports not (color: color-mix(in srgb, red, blue)){.orbit-ring{stroke:var(--_orbit-ring-stroke)}.orbit-link{stroke:var(--_orbit-link-stroke)}.orbit-shade__highlight-fade{stop-color:var(--_orbit-node-highlight);stop-opacity:.2}.orbit-node__shadow{fill:var(--_orbit-node-shadow)}.orbit-node__halo{stroke:var(--_orbit-sun-halo)}.orbit-node__shade{stroke:var(--_orbit-node-stroke)}.orbit-outline--visible button:hover,.orbit-button:hover,.orbit-sheet__action:hover,.orbit-sheet__expand:hover,.orbit-sheet .orbit-button:hover{background:rgba(127,127,127,.14)}.orbit-viewer__step:hover{background:var(--_orbit-control-background)}}@supports not (translate: 1px){.orbit-hint{transform:translateX(-50%)}}@media(prefers-reduced-motion: reduce){.orbit *,.orbit-sheet,.orbit-viewer{transition:none !important;animation:none !important}}@media(forced-colors: active){.orbit-node__focus-ring,.orbit-add__focus-ring{stroke:Highlight}.orbit-add__disc,.orbit-add__plus{stroke:CanvasText}.orbit-node__shade,.orbit-node__halo{stroke:CanvasText}.orbit-node__shadow{display:none}.orbit-button[aria-pressed=true]{outline:2px solid Highlight}}\";",
|
|
34
|
+
"export default \".orbit-print{color:var(--orbit-print-text, var(--_orbit-print-text));font-family:var(--orbit-print-font, var(--_orbit-print-font));font-size:11pt;line-height:1.45;print-color-adjust:exact;-webkit-print-color-adjust:exact}.orbit-print__title{margin:0 0 6pt;font-family:var(--orbit-print-display-font, var(--_orbit-print-display-font));font-size:22pt;line-height:1.2;break-after:avoid}.orbit-print__picture{margin:12pt 0 18pt;break-inside:avoid}.orbit-print__picture svg{display:block;width:100%;height:auto;max-height:150mm}.orbit-print__children{margin-inline-start:4pt;padding-inline-start:12pt;border-inline-start:1px solid var(--orbit-print-border, var(--_orbit-print-border))}.orbit-print__entry{padding:5pt 0 3pt;break-inside:avoid}.orbit-print__entry--parent{break-after:avoid}.orbit-print__name{margin:0;font-family:var(--orbit-print-display-font, var(--_orbit-print-display-font));font-size:11pt;line-height:1.3}.orbit-print__name--depth-1{margin-top:8pt;font-size:15pt}.orbit-print__name--depth-2{font-size:12.5pt}.orbit-print__dot{display:inline-block;width:.6em;height:.6em;margin-inline-end:.4em;border-radius:50%;background:var(--orbit-print-dot);vertical-align:.05em}.orbit-print__chips{display:flex;flex-wrap:wrap;gap:3pt 4pt;margin:3pt 0 0}.orbit-print__chip{padding:0 6pt;border-radius:8pt;background:var(--orbit-print-chip-background, var(--_orbit-print-chip-background));color:var(--orbit-print-chip-text, var(--_orbit-print-chip-text));font-size:8.5pt;line-height:1.7}.orbit-print__chip--status::before{content:\\\"\\\";display:inline-block;width:6pt;height:6pt;margin-inline-end:4pt;border-radius:50%;background:var(--orbit-print-status);vertical-align:.05em}.orbit-print__link{margin:3pt 0 0;color:var(--orbit-print-muted-text, var(--_orbit-print-muted-text));font-size:9pt}.orbit-print__address{color:var(--orbit-print-link-text, var(--_orbit-print-link-text));overflow-wrap:anywhere;text-decoration:none}.orbit-print__details{margin:4pt 0 0;font-size:10pt}.orbit-print__note{margin:4pt 0 0;font-size:10pt}.orbit-print__note p,.orbit-print__note ul,.orbit-print__note ol,.orbit-print__note pre,.orbit-print__note blockquote{margin:0 0 4pt}.orbit-print__note ul,.orbit-print__note ol{padding-inline-start:16pt}.orbit-print__note blockquote{padding-inline-start:8pt;border-inline-start:2pt solid var(--orbit-print-border, var(--_orbit-print-border));color:var(--orbit-print-muted-text, var(--_orbit-print-muted-text))}.orbit-print__note pre,.orbit-print__note code{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9pt;white-space:pre-wrap}.orbit-print__note a{color:var(--orbit-print-link-text, var(--_orbit-print-link-text))}.orbit-print__note img{display:block;max-width:100%;max-height:80mm;break-inside:avoid}.orbit-print__note--plain{white-space:pre-wrap}.orbit-print__media{margin:6pt 0 0;break-inside:avoid}.orbit-print__image{display:block;max-width:60%;max-height:70mm;border-radius:6pt;object-fit:contain}.orbit-print__caption{margin-top:2pt;color:var(--orbit-print-muted-text, var(--_orbit-print-muted-text));font-size:8.5pt;overflow-wrap:anywhere}\";",
|
|
35
|
+
"import componentStyles from './styles/orbit.scss';\nimport printStyles from './styles/print.scss';\nimport { themeStylesheet } from './themes.js';\n\nconst STYLESHEET = componentStyles + printStyles + themeStylesheet();\nconst styledRoots = new WeakSet<Document | ShadowRoot>();\nlet sharedSheet: CSSStyleSheet | null = null;\n\n/**\n * Adds the orbit stylesheet, once, to the document or shadow root that holds\n * `element`. Constructable stylesheets are used where available, so pages\n * with a strict Content Security Policy keep working.\n */\nexport const ensureStyles = (element: Node): void => {\n const target = styleTarget(element);\n\n if (!target || styledRoots.has(target)) {\n return;\n }\n\n styledRoots.add(target);\n\n if ('adoptedStyleSheets' in target && typeof CSSStyleSheet === 'function' && 'replaceSync' in CSSStyleSheet.prototype) {\n try {\n sharedSheet ??= createSheet();\n target.adoptedStyleSheets = [...target.adoptedStyleSheets, sharedSheet];\n return;\n } catch {\n // A sheet built for another document can't be adopted: fall back to a <style> element.\n }\n }\n\n const style = (element.ownerDocument ?? document).createElement('style');\n style.setAttribute('data-orbit-styles', '');\n style.textContent = STYLESHEET;\n\n if (isShadowRoot(target)) {\n target.appendChild(style);\n } else {\n (target.head ?? target.documentElement).appendChild(style);\n }\n};\n\nconst createSheet = (): CSSStyleSheet => {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(STYLESHEET);\n return sheet;\n};\n\nconst styleTarget = (element: Node): Document | ShadowRoot | null => {\n const root = element.getRootNode?.();\n\n if (root && isShadowRoot(root)) {\n return root;\n }\n\n return element.ownerDocument ?? (typeof document === 'undefined' ? null : document);\n};\n\nconst isShadowRoot = (node: Node): node is ShadowRoot => {\n return typeof ShadowRoot !== 'undefined' && node instanceof ShadowRoot;\n};\n",
|
|
36
|
+
"/**\n * Pointer gestures for the map: tap, long press, spin (focus mode), pan\n * (overview), pinch, wheel, double tap, and dragging a node that a held\n * press lifted. The controller only recognizes gestures; the renderer\n * decides what they do.\n *\n * Two properties are load-bearing for touch: pointerdown is never\n * preventDefault-ed (that would suppress the `click` every tap relies on),\n * and native scrolling is managed with `touch-action` in the stylesheet.\n * Pointer capture is taken only once a drag engages, so taps keep native\n * targeting.\n */\n\nexport interface Point {\n x: number;\n y: number;\n}\n\n/** What a one-finger drag starting at a point does. */\nexport type DragGesture = 'spin' | 'pan' | 'none';\n\nexport interface GestureCallbacks {\n isInteractive(): boolean;\n\n /** What dragging from this point (container coordinates) does. */\n dragGesture(point: Point): DragGesture;\n\n /** The orbit's center on screen. */\n spinCenter(): Point;\n\n /** True while the orbit coasts: the next press catches it. */\n isCoasting(): boolean;\n\n onCatch(): void;\n onSpinStart(time: number, angle: number): void;\n onSpinMove(time: number, angle: number): void;\n\n /** `cancelled` when the browser took the pointer over (to scroll, say): no fling. */\n onSpinEnd(time: number, cancelled: boolean): void;\n\n onPanStart(time: number): void;\n onPan(deltaX: number, deltaY: number, time: number): void;\n onPanEnd(time: number, cancelled: boolean): void;\n\n /** Zoom by `factor` around `center`, and pan by how far the center moved. */\n onPinch(factor: number, center: Point, deltaX: number, deltaY: number): void;\n\n onPinchEnd(): void;\n onWheel(event: WheelEvent, point: Point): void;\n onDoubleTap(point: Point, target: EventTarget | null): void;\n\n /**\n * A touch or pen held still on `target`. Returns whether the map took it:\n * the press then neither taps nor spins.\n */\n onLongPress(point: Point, target: EventTarget | null): boolean;\n\n /**\n * A press held still on `target`: whether it lifted a node, which moving\n * the press then drags (see `onNodeDrag`). Touches and pens get here after\n * `onLongPress`; a mouse held still gets here alone, with no menu.\n */\n onHold(point: Point, target: EventTarget | null): boolean;\n\n /**\n * The lifted node follows the press: `move` as it moves, then `drop` where\n * it's let go (moved or not), or `cancel` when the press is taken away.\n */\n onNodeDrag(point: Point, phase: 'move' | 'drop' | 'cancel'): void;\n\n /** How long (ms) a still touch takes to become a long press. */\n longPressDelay(): number;\n\n onDraggingChange(dragging: boolean): void;\n}\n\ntype Gesture = 'none' | 'tap' | 'spin' | 'pan' | 'pinch' | 'move';\n\n/** Movement (px) before a press becomes a drag. Below this a press is a tap. */\nconst DRAG_SLOP = 4;\n/** Fingers wobble more than a mouse: the drag slop for touch and pens, which also cancels a long press. */\nconst TOUCH_SLOP = 8;\nconst DOUBLE_TAP_TIME = 320;\nconst DOUBLE_TAP_DISTANCE = 28;\n\nexport class InputController {\n private element: Element | null = null;\n private readonly container: HTMLElement;\n private readonly callbacks: GestureCallbacks;\n private readonly pointers = new Map<number, Point>();\n private gesture: Gesture = 'none';\n private engaged = false;\n private startPoint: Point | null = null;\n private lastPoint: Point | null = null;\n\n /**\n * Where the map was on the page when the pointers now down first touched\n * it. Asking again on every move would make the browser lay out the whole\n * map each time, thousands of elements on a big one, and a pointer can\n * move several times a frame.\n */\n private gestureRectangle: DOMRect | null = null;\n\n private lastPinchDistance: number | null = null;\n private lastPinchCenter: Point | null = null;\n private suppressNextClick = false;\n private lastTap: { time: number; point: Point } | null = null;\n private longPress: { pointerId: number; timer: ReturnType<typeof setTimeout> } | null = null;\n\n /** The press became a long press: lifting it is no tap. */\n private pressTaken = false;\n\n /** The held press lifted a node: moving it drags the node. */\n private lifted = false;\n\n constructor(container: HTMLElement, callbacks: GestureCallbacks) {\n this.container = container;\n this.callbacks = callbacks;\n }\n\n attach(element: Element): void {\n if (this.element === element) {\n return;\n }\n\n this.detach();\n this.element = element;\n element.addEventListener('pointerdown', this.handlePointerDown as EventListener);\n element.addEventListener('pointermove', this.handlePointerMove as EventListener);\n element.addEventListener('pointerup', this.handlePointerUp as EventListener);\n element.addEventListener('pointercancel', this.handlePointerUp as EventListener);\n element.addEventListener('wheel', this.handleWheel as EventListener, { passive: false });\n element.addEventListener('touchmove', this.handleTouchMove as EventListener, { passive: false });\n element.addEventListener('dblclick', this.handleDoubleClick as EventListener);\n // Capture phase so the click that ends a drag never reaches node listeners.\n element.addEventListener('click', this.handleClickCapture as EventListener, true);\n }\n\n detach(): void {\n const element = this.element;\n\n if (!element) {\n return;\n }\n\n element.removeEventListener('pointerdown', this.handlePointerDown as EventListener);\n element.removeEventListener('pointermove', this.handlePointerMove as EventListener);\n element.removeEventListener('pointerup', this.handlePointerUp as EventListener);\n element.removeEventListener('pointercancel', this.handlePointerUp as EventListener);\n element.removeEventListener('wheel', this.handleWheel as EventListener);\n element.removeEventListener('touchmove', this.handleTouchMove as EventListener);\n element.removeEventListener('dblclick', this.handleDoubleClick as EventListener);\n element.removeEventListener('click', this.handleClickCapture as EventListener, true);\n this.element = null;\n this.reset();\n }\n\n private reset(): void {\n if (this.lifted || this.gesture === 'move') {\n this.callbacks.onNodeDrag(this.lastPoint ?? { x: 0, y: 0 }, 'cancel');\n }\n\n if (this.engaged) {\n this.callbacks.onDraggingChange(false);\n }\n\n this.cancelLongPress();\n this.pressTaken = false;\n this.lifted = false;\n this.pointers.clear();\n this.gestureRectangle = null;\n this.gesture = 'none';\n this.engaged = false;\n this.startPoint = null;\n this.lastPoint = null;\n this.lastPinchDistance = null;\n this.lastPinchCenter = null;\n }\n\n private localPoint(event: { clientX?: number; clientY?: number }): Point {\n const rectangle = this.gestureRectangle ?? this.container.getBoundingClientRect();\n // Synthetic events may carry no coordinates: treat them as the middle of the map.\n const x = Number.isFinite(event.clientX) ? (event.clientX as number) - rectangle.left : rectangle.width / 2;\n const y = Number.isFinite(event.clientY) ? (event.clientY as number) - rectangle.top : rectangle.height / 2;\n return { x, y };\n }\n\n private angleOf(point: Point): number {\n const center = this.callbacks.spinCenter();\n return (Math.atan2(point.y - center.y, point.x - center.x) * 180) / Math.PI;\n }\n\n private pinchDistance(): number | null {\n if (this.pointers.size < 2) {\n return null;\n }\n\n const [first, second] = Array.from(this.pointers.values());\n return Math.hypot(first.x - second.x, first.y - second.y);\n }\n\n private pinchCenter(): Point {\n const [first, second] = Array.from(this.pointers.values());\n return { x: (first.x + second.x) / 2, y: (first.y + second.y) / 2 };\n }\n\n private readonly handleClickCapture = (event: MouseEvent): void => {\n if (!this.suppressNextClick) {\n return;\n }\n\n this.suppressNextClick = false;\n event.stopPropagation();\n event.preventDefault();\n };\n\n private readonly handlePointerDown = (event: PointerEvent): void => {\n if (!this.callbacks.isInteractive()) {\n return;\n }\n\n if (event.pointerType === 'mouse' && event.button !== 0) {\n return;\n }\n\n if (this.pointers.size === 0) {\n this.gestureRectangle = this.container.getBoundingClientRect();\n }\n\n const point = this.localPoint(event);\n this.pointers.set(event.pointerId, point);\n this.suppressNextClick = false;\n this.cancelLongPress();\n\n if (this.pointers.size === 2) {\n // A second finger puts a lifted node back: two fingers pinch.\n if (this.lifted || this.gesture === 'move') {\n this.lifted = false;\n this.callbacks.onNodeDrag(this.lastPoint ?? point, 'cancel');\n }\n\n if (this.engaged && this.gesture === 'spin') {\n this.callbacks.onSpinEnd(event.timeStamp, true);\n } else if (this.engaged && this.gesture === 'pan') {\n this.callbacks.onPanEnd(event.timeStamp, true);\n }\n\n if (!this.engaged) {\n this.callbacks.onDraggingChange(true);\n }\n\n this.gesture = 'pinch';\n this.engaged = true;\n this.lastPinchDistance = this.pinchDistance();\n this.lastPinchCenter = this.pinchCenter();\n return;\n }\n\n if (this.pointers.size > 2) {\n return;\n }\n\n const catching = this.callbacks.isCoasting();\n\n if (catching) {\n // A touch on a spinning orbit catches it; it never opens a planet.\n this.callbacks.onCatch();\n this.suppressNextClick = true;\n }\n\n this.startPoint = point;\n this.lastPoint = point;\n this.engaged = false;\n this.pressTaken = false;\n const drag = this.callbacks.dragGesture(point);\n this.gesture = drag === 'none' ? 'tap' : drag;\n\n if (!catching) {\n this.startLongPress(event.pointerId, point, event.target, event.pointerType === 'mouse');\n }\n };\n\n private startLongPress(pointerId: number, point: Point, target: EventTarget | null, mouse: boolean): void {\n const timer = setTimeout(() => {\n this.longPress = null;\n\n if (this.engaged || this.pointers.size !== 1) {\n return;\n }\n\n // A mouse has its right click for menus: held still, it only lifts.\n const taken = !mouse && this.callbacks.onLongPress(point, target);\n const lifted = this.callbacks.onHold(point, target);\n\n if (!taken && !lifted) {\n return;\n }\n\n this.lifted = lifted;\n this.lastTap = null;\n\n if (mouse) {\n // A slow click that lets go without moving still clicks.\n return;\n }\n\n // The press is spent: lifting the finger doesn't tap, and moving it drags the lifted node or nothing.\n this.pressTaken = true;\n this.gesture = 'none';\n this.suppressNextClick = true;\n }, this.callbacks.longPressDelay());\n\n this.longPress = { pointerId, timer };\n }\n\n private cancelLongPress(): void {\n if (this.longPress) {\n clearTimeout(this.longPress.timer);\n this.longPress = null;\n }\n }\n\n private readonly handlePointerMove = (event: PointerEvent): void => {\n if (!this.pointers.has(event.pointerId)) {\n return;\n }\n\n const point = this.localPoint(event);\n this.pointers.set(event.pointerId, point);\n\n if (this.gesture === 'pinch') {\n const distance = this.pinchDistance();\n\n if (distance === null) {\n return;\n }\n\n const center = this.pinchCenter();\n const previousCenter = this.lastPinchCenter ?? center;\n const factor = this.lastPinchDistance ? distance / this.lastPinchDistance : 1;\n this.callbacks.onPinch(factor, center, center.x - previousCenter.x, center.y - previousCenter.y);\n this.lastPinchDistance = distance;\n this.lastPinchCenter = center;\n return;\n }\n\n if (!this.startPoint || !this.lastPoint) {\n return;\n }\n\n const moved = Math.hypot(point.x - this.startPoint.x, point.y - this.startPoint.y);\n const slop = event.pointerType === 'mouse' ? DRAG_SLOP : TOUCH_SLOP;\n\n if (this.longPress && moved >= slop) {\n this.cancelLongPress();\n }\n\n if (this.lifted && this.gesture !== 'move') {\n if (moved < slop) {\n return;\n }\n\n this.gesture = 'move';\n this.engaged = true;\n this.callbacks.onDraggingChange(true);\n\n try {\n this.element?.setPointerCapture?.(event.pointerId);\n } catch {\n // Pointer capture is optional (some test environments lack it).\n }\n }\n\n if (this.gesture === 'move') {\n this.lastPoint = point;\n this.callbacks.onNodeDrag(point, 'move');\n return;\n }\n\n if (this.gesture !== 'spin' && this.gesture !== 'pan') {\n return;\n }\n\n if (!this.engaged) {\n if (moved < slop) {\n return;\n }\n\n this.cancelLongPress();\n this.engaged = true;\n this.callbacks.onDraggingChange(true);\n\n try {\n this.element?.setPointerCapture?.(event.pointerId);\n } catch {\n // Pointer capture is optional (some test environments lack it).\n }\n\n if (this.gesture === 'spin') {\n // Anchor at the current position so the slop distance doesn't jump.\n this.callbacks.onSpinStart(event.timeStamp, this.angleOf(point));\n } else {\n this.callbacks.onPanStart(event.timeStamp);\n }\n }\n\n const samples = typeof event.getCoalescedEvents === 'function' ? event.getCoalescedEvents() : [];\n const points = samples.length > 0 ? samples.map((sample) => ({ point: this.localPoint(sample), time: sample.timeStamp })) : [{ point, time: event.timeStamp }];\n\n for (const sample of points) {\n if (this.gesture === 'spin') {\n this.callbacks.onSpinMove(sample.time, this.angleOf(sample.point));\n } else {\n this.callbacks.onPan(sample.point.x - this.lastPoint.x, sample.point.y - this.lastPoint.y, sample.time);\n }\n\n this.lastPoint = sample.point;\n }\n };\n\n private readonly handlePointerUp = (event: PointerEvent): void => {\n if (!this.pointers.delete(event.pointerId)) {\n return;\n }\n\n this.cancelLongPress();\n const point = this.localPoint(event);\n\n if (this.pointers.size === 0) {\n this.gestureRectangle = null;\n }\n\n if (this.gesture === 'pinch') {\n if (this.pointers.size === 1) {\n this.callbacks.onPinchEnd();\n // One finger lifted mid-pinch: continue as a pan in the overview.\n const remaining = Array.from(this.pointers.values())[0];\n this.lastPinchDistance = null;\n this.lastPinchCenter = null;\n this.startPoint = remaining;\n this.lastPoint = remaining;\n\n if (this.callbacks.dragGesture(remaining) === 'pan') {\n this.gesture = 'pan';\n this.callbacks.onPanStart(event.timeStamp);\n } else {\n this.gesture = 'none';\n }\n\n this.suppressNextClick = true;\n return;\n }\n\n if (this.pointers.size === 0) {\n this.callbacks.onPinchEnd();\n this.suppressNextClick = true;\n this.reset();\n return;\n }\n\n // A finger lifted from a pinch of three or more: the pair that remains sets a fresh baseline.\n this.lastPinchDistance = this.pinchDistance();\n this.lastPinchCenter = this.pinchCenter();\n return;\n }\n\n if (this.pointers.size > 0) {\n return;\n }\n\n const cancelled = event.type === 'pointercancel';\n\n if (this.lifted || this.gesture === 'move') {\n // Let go: a node that moved lands where it is, and one only lifted goes back down.\n this.lifted = false;\n this.callbacks.onNodeDrag(point, cancelled ? 'cancel' : 'drop');\n this.gesture = 'none';\n }\n\n if (this.engaged) {\n // A cancel ends the drag with no click after it, so there's nothing to swallow.\n this.suppressNextClick = !cancelled;\n\n if (this.gesture === 'spin') {\n this.callbacks.onSpinEnd(event.timeStamp, cancelled);\n } else if (this.gesture === 'pan') {\n this.callbacks.onPanEnd(event.timeStamp, cancelled);\n }\n } else if (event.pointerType !== 'mouse' && event.type === 'pointerup' && !this.pressTaken) {\n this.detectDoubleTap(point, event.timeStamp, event.target);\n }\n\n this.reset();\n };\n\n private detectDoubleTap(point: Point, time: number, target: EventTarget | null): void {\n const previous = this.lastTap;\n\n if (previous && time - previous.time < DOUBLE_TAP_TIME && Math.hypot(point.x - previous.point.x, point.y - previous.point.y) < DOUBLE_TAP_DISTANCE) {\n this.lastTap = null;\n this.callbacks.onDoubleTap(point, target);\n return;\n }\n\n this.lastTap = { time, point };\n }\n\n private readonly handleDoubleClick = (event: MouseEvent): void => {\n if (!this.callbacks.isInteractive()) {\n return;\n }\n\n this.callbacks.onDoubleTap(this.localPoint(event), event.target);\n };\n\n /**\n * A lifted node is dragged, not the page: the browser mustn't scroll it\n * from under the press, as it would where `touch-action` lets one finger\n * scroll the page (Chromium doesn't apply `touch-action` to the shapes\n * inside an SVG, so the canvas's own decides).\n */\n private readonly handleTouchMove = (event: TouchEvent): void => {\n if ((this.lifted || this.gesture === 'move') && event.cancelable) {\n event.preventDefault();\n }\n };\n\n private readonly handleWheel = (event: WheelEvent): void => {\n if (!this.callbacks.isInteractive()) {\n return;\n }\n\n this.callbacks.onWheel(event, this.localPoint(event));\n };\n}\n\n/**\n * Zoom factor for a wheel event: the same zoom per scrolled pixel for mouse\n * wheels and trackpads. Trackpad pinches arrive as wheel events with\n * `ctrlKey` and small pixel deltas, so they get a stronger multiplier; a\n * mouse wheel turned with Ctrl held sends large deltas and keeps the normal one.\n */\nexport const wheelZoomFactor = (event: Pick<WheelEvent, 'deltaY' | 'deltaMode' | 'ctrlKey'>, pageHeight: number): number => {\n let pixels = event.deltaY;\n\n if (event.deltaMode === 1) {\n pixels *= 16;\n } else if (event.deltaMode === 2) {\n pixels *= pageHeight;\n }\n\n const trackpadPinch = event.ctrlKey && event.deltaMode === 0 && Math.abs(event.deltaY) < 50;\n const factor = Math.exp(-pixels * 0.002 * (trackpadPinch ? 5 : 1));\n return Math.min(2, Math.max(0.5, factor));\n};\n",
|
|
37
|
+
"/**\n * One animation loop per map. Tasks (camera flights, spin, transitions,\n * glides) advance with real elapsed time, then the map paints once per\n * frame. The loop sleeps as soon as nothing is moving.\n */\n\n/**\n * Advances one animation. Returns `true` while it still has work to do,\n * `false` once it's done, or `'hold'` to keep running without anything to\n * paint this frame (a motion too slow to show on every frame). A task that\n * throws is reported and dropped, so the loop carries on.\n */\nexport type FrameTask = (now: number, elapsed: number) => boolean | 'hold';\n\ntype Scheduler = (callback: (now: number) => void) => number;\ntype Canceller = (handle: number) => void;\n\n/** Frames longer than this (a background tab, a debugger pause) count as this long. */\nconst LONGEST_FRAME = 64;\n\nexport class AnimationClock {\n private readonly paint: () => void;\n private readonly schedule: Scheduler;\n private readonly cancel: Canceller;\n private readonly tasks = new Set<FrameTask>();\n private frameHandle: number | null = null;\n private previousTime: number | null = null;\n private paintRequested = false;\n\n constructor(\n paint: () => void,\n schedule: Scheduler = (callback) => requestAnimationFrame(callback),\n cancel: Canceller = (handle) => cancelAnimationFrame(handle),\n ) {\n this.paint = paint;\n this.schedule = schedule;\n this.cancel = cancel;\n }\n\n /** Runs `task` every frame until it returns false. Returns a function that removes it. */\n add(task: FrameTask): () => void {\n this.tasks.add(task);\n this.wake();\n\n return () => {\n this.tasks.delete(task);\n };\n }\n\n /** Paints once on the next frame, without adding a task. */\n requestPaint(): void {\n this.paintRequested = true;\n this.wake();\n }\n\n get isRunning(): boolean {\n return this.frameHandle !== null;\n }\n\n stop(): void {\n if (this.frameHandle !== null) {\n this.cancel(this.frameHandle);\n }\n\n this.frameHandle = null;\n this.previousTime = null;\n this.tasks.clear();\n this.paintRequested = false;\n }\n\n private wake(): void {\n if (this.frameHandle === null) {\n this.frameHandle = this.schedule(this.tick);\n }\n }\n\n private readonly tick = (now: number): void => {\n const elapsed = this.previousTime === null ? 1000 / 60 : Math.min(LONGEST_FRAME, Math.max(0, now - this.previousTime));\n this.previousTime = now;\n let changed = this.paintRequested;\n\n for (const task of Array.from(this.tasks)) {\n let result: boolean | 'hold';\n\n try {\n result = task(now, elapsed);\n } catch (error) {\n // A task that threw is done: the rest of the loop carries on.\n console.error('[orbit] An animation task threw:', error);\n result = false;\n }\n\n if (result === false) {\n this.tasks.delete(task);\n }\n\n changed ||= result !== 'hold';\n }\n\n this.paintRequested = false;\n\n if (changed) {\n try {\n this.paint();\n } catch (error) {\n console.error('[orbit] Painting the map threw:', error);\n }\n }\n\n if (this.tasks.size > 0 || this.paintRequested) {\n this.frameHandle = this.schedule(this.tick);\n } else {\n this.frameHandle = null;\n this.previousTime = null;\n }\n };\n}\n\n/** Ease-in-out cubic, for camera flights and node morphs. */\nexport const easeInOutCubic = (progress: number): number => {\n return progress < 0.5 ? 4 * progress * progress * progress : 1 - (-2 * progress + 2) ** 3 / 2;\n};\n\n/** Ease-out cubic, for entrances and small settles. */\nexport const easeOutCubic = (progress: number): number => {\n return 1 - (1 - progress) ** 3;\n};\n\n/** Maps `progress` from the window [start, end] to [0, 1], clamped. */\nexport const within = (progress: number, start: number, end: number): number => {\n if (progress <= start) {\n return 0;\n }\n\n if (progress >= end) {\n return 1;\n }\n\n return (progress - start) / (end - start);\n};\n\nexport const interpolate = (from: number, to: number, progress: number): number => {\n return from + (to - from) * progress;\n};\n",
|
|
38
|
+
"/**\n * Camera math. A camera is the world point shown at the viewport's center\n * and a zoom factor. Everything is plain geometry so it can be unit-tested\n * without a DOM.\n */\n\nexport interface Camera {\n x: number;\n y: number;\n scale: number;\n}\n\nexport interface Viewport {\n width: number;\n height: number;\n}\n\nexport interface Point {\n x: number;\n y: number;\n}\n\n/** Maps world points onto the screen: `p ↦ (p − center) × scale + viewport center`. */\nexport const worldToScreen = (camera: Camera, viewport: Viewport, point: Point): Point => {\n return {\n x: (point.x - camera.x) * camera.scale + viewport.width / 2,\n y: (point.y - camera.y) * camera.scale + viewport.height / 2,\n };\n};\n\nexport const screenToWorld = (camera: Camera, viewport: Viewport, point: Point): Point => {\n return {\n x: (point.x - viewport.width / 2) / camera.scale + camera.x,\n y: (point.y - viewport.height / 2) / camera.scale + camera.y,\n };\n};\n\n/** SVG `transform` for the world group. */\nexport const cameraTransform = (camera: Camera, viewport: Viewport): string => {\n return `translate(${round(viewport.width / 2)} ${round(viewport.height / 2)}) scale(${round(camera.scale, 5)}) translate(${round(-camera.x)} ${round(-camera.y)})`;\n};\n\n/** Zooms by `factor` keeping the world point under `anchor` (screen coordinates) in place. */\nexport const zoomAround = (camera: Camera, viewport: Viewport, factor: number, anchor: Point): Camera => {\n const fixed = screenToWorld(camera, viewport, anchor);\n const scale = camera.scale * factor;\n return {\n scale,\n x: fixed.x - (anchor.x - viewport.width / 2) / scale,\n y: fixed.y - (anchor.y - viewport.height / 2) / scale,\n };\n};\n\n/** Moves the camera so the content shifts by a screen-space delta. */\nexport const panBy = (camera: Camera, deltaX: number, deltaY: number): Camera => {\n return { scale: camera.scale, x: camera.x - deltaX / camera.scale, y: camera.y - deltaY / camera.scale };\n};\n\n/**\n * A camera that keeps `center` at the middle of the viewport and fits\n * content reaching `extent` away from it on each axis, inside `padding`.\n */\n/** Room the page's own controls take at the viewport's edges, in px. */\nexport interface Insets {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n\nexport const NO_INSETS: Insets = { top: 0, right: 0, bottom: 0, left: 0 };\n\n/**\n * The camera that shows `extent` around `center`, `padding` px from the\n * edges of what `insets` leave of the viewport, and centered there.\n */\nexport const fitAround = (center: Point, extent: Point, viewport: Viewport, padding: number, maximumScale: number, insets: Insets = NO_INSETS): Camera => {\n const width = Math.max(1, viewport.width - insets.left - insets.right);\n const height = Math.max(1, viewport.height - insets.top - insets.bottom);\n const usableWidth = Math.max(width - padding * 2, width * 0.35);\n const usableHeight = Math.max(height - padding * 2, height * 0.35);\n const fitted = Math.min(\n extent.x > 0 ? usableWidth / (extent.x * 2) : maximumScale,\n extent.y > 0 ? usableHeight / (extent.y * 2) : maximumScale,\n maximumScale,\n );\n const scale = fitted > 0 && Number.isFinite(fitted) ? fitted : 1;\n // The middle of what's left is off the viewport's middle: the camera looks the other way by as much.\n return {\n x: center.x - (insets.left - insets.right) / 2 / scale,\n y: center.y - (insets.top - insets.bottom) / 2 / scale,\n scale,\n };\n};\n\n/** A similarity transform `p ↦ p × scale + (x, y)`, used to place one scene inside another. */\nexport interface Similarity {\n scale: number;\n x: number;\n y: number;\n}\n\nexport const IDENTITY: Similarity = { scale: 1, x: 0, y: 0 };\n\nexport const applySimilarity = (transform: Similarity, point: Point): Point => {\n return { x: point.x * transform.scale + transform.x, y: point.y * transform.scale + transform.y };\n};\n\nexport const invertSimilarity = (transform: Similarity): Similarity => {\n return { scale: 1 / transform.scale, x: -transform.x / transform.scale, y: -transform.y / transform.scale };\n};\n\n/** `outer ∘ inner`: apply `inner` first, then `outer`. */\nexport const composeSimilarity = (outer: Similarity, inner: Similarity): Similarity => {\n return {\n scale: outer.scale * inner.scale,\n x: inner.x * outer.scale + outer.x,\n y: inner.y * outer.scale + outer.y,\n };\n};\n\n/** The same view expressed in coordinates transformed by `transform`. */\nexport const transformCamera = (transform: Similarity, camera: Camera): Camera => {\n const center = applySimilarity(transform, camera);\n return { x: center.x, y: center.y, scale: camera.scale / transform.scale };\n};\n\nconst RHO = Math.SQRT2;\nconst RHO_SQUARED = 2;\nconst RHO_FOURTH = 4;\n\nexport interface CameraPath {\n /** The camera at `progress` ∈ [0, 1]. */\n at(progress: number): Camera;\n\n /** Path length in the paper's units; flights take time proportional to it. */\n length: number;\n}\n\n/**\n * Van Wijk & Nuij, \"Smooth and efficient zooming and panning\" (2003): the\n * path that zooms out a little, travels, then zooms in, so the start and the\n * destination stay in view for as long as possible. It is the same path\n * d3's `interpolateZoom` follows.\n */\nexport const smoothZoomPath = (from: Camera, to: Camera, viewport: Viewport): CameraPath => {\n const viewWidth = Math.max(viewport.width, 1);\n const startX = from.x;\n const startY = from.y;\n const startWidth = viewWidth / from.scale;\n const endWidth = viewWidth / to.scale;\n const deltaX = to.x - from.x;\n const deltaY = to.y - from.y;\n const distanceSquared = deltaX * deltaX + deltaY * deltaY;\n\n if (distanceSquared < 1e-12) {\n const length = Math.log(endWidth / startWidth) / RHO;\n return {\n length: Math.abs(length),\n at: (progress) => ({\n x: startX + progress * deltaX,\n y: startY + progress * deltaY,\n scale: viewWidth / (startWidth * Math.exp(RHO * progress * length)),\n }),\n };\n }\n\n const distance = Math.sqrt(distanceSquared);\n const startTerm = (endWidth * endWidth - startWidth * startWidth + RHO_FOURTH * distanceSquared) / (2 * startWidth * RHO_SQUARED * distance);\n const endTerm = (endWidth * endWidth - startWidth * startWidth - RHO_FOURTH * distanceSquared) / (2 * endWidth * RHO_SQUARED * distance);\n const startRatio = Math.log(Math.sqrt(startTerm * startTerm + 1) - startTerm);\n const endRatio = Math.log(Math.sqrt(endTerm * endTerm + 1) - endTerm);\n const length = (endRatio - startRatio) / RHO;\n const coshStart = Math.cosh(startRatio);\n\n return {\n length: Math.abs(length),\n at: (progress) => {\n const position = progress * length;\n const travelled = (startWidth / (RHO_SQUARED * distance)) * (coshStart * Math.tanh(RHO * position + startRatio) - Math.sinh(startRatio));\n const width = (startWidth * coshStart) / Math.cosh(RHO * position + startRatio);\n return {\n x: startX + travelled * deltaX,\n y: startY + travelled * deltaY,\n scale: viewWidth / width,\n };\n },\n };\n};\n\nconst round = (value: number, decimals = 3): number => {\n const factor = 10 ** decimals;\n return Math.round(value * factor) / factor;\n};\n",
|
|
39
|
+
"/**\n * Spinner physics for the focus-mode orbit.\n *\n * Release speed comes from where the pointer actually was over the last\n * 80 ms, not from the last pointer event, so a lazy drag barely coasts and a\n * hard flick spins for several turns on any device. Coasting decays\n * exponentially using the exact solution for each step, so the result is the\n * same at 60 Hz, 120 Hz or any other frame rate.\n */\n\n/** Degrees. `-180 < result <= 180`. */\nexport const normalizeDelta = (delta: number): number => {\n let result = delta % 360;\n\n if (result > 180) {\n result -= 360;\n } else if (result <= -180) {\n result += 360;\n }\n\n return result;\n};\n\nconst VELOCITY_WINDOW = 80;\n/** A pointer that rested this long before release flings nothing. */\nconst STALE_AFTER = 50;\nconst SAMPLE_HISTORY = 160;\n\n/** Tracks a dragged angle over time and reports the release velocity. */\nexport class AngularVelocityTracker {\n private samples: { time: number; angle: number }[] = [];\n private lastRawAngle = 0;\n private unwrappedAngle = 0;\n\n reset(time: number, rawAngle: number): void {\n this.lastRawAngle = rawAngle;\n this.unwrappedAngle = rawAngle;\n this.samples = [{ time, angle: rawAngle }];\n }\n\n /** Records the pointer's angle (degrees) at `time` (milliseconds). Returns the change since the last sample. */\n add(time: number, rawAngle: number): number {\n const delta = normalizeDelta(rawAngle - this.lastRawAngle);\n this.lastRawAngle = rawAngle;\n this.unwrappedAngle += delta;\n this.samples.push({ time, angle: this.unwrappedAngle });\n\n while (this.samples.length > 2 && time - this.samples[0].time > SAMPLE_HISTORY) {\n this.samples.shift();\n }\n\n return delta;\n }\n\n /** Degrees per millisecond at `releaseTime`: the least-squares slope of the last 80 ms. */\n velocityAt(releaseTime: number): number {\n const recent = this.samples.filter((sample) => releaseTime - sample.time <= VELOCITY_WINDOW);\n\n if (recent.length < 2 || releaseTime - recent[recent.length - 1].time > STALE_AFTER) {\n return 0;\n }\n\n const meanTime = recent.reduce((sum, sample) => sum + sample.time, 0) / recent.length;\n const meanAngle = recent.reduce((sum, sample) => sum + sample.angle, 0) / recent.length;\n let covariance = 0;\n let variance = 0;\n\n for (const sample of recent) {\n covariance += (sample.time - meanTime) * (sample.angle - meanAngle);\n variance += (sample.time - meanTime) ** 2;\n }\n\n return variance === 0 ? 0 : covariance / variance;\n }\n}\n\nexport interface SpinSettings {\n /** Time constant of the exponential slow-down, in seconds. */\n decay: number;\n\n /** Fastest coast, in degrees per second. */\n maxSpeed: number;\n\n /** Below this speed (degrees per second) a coast hands over to settling. */\n settleSpeed: number;\n\n /** Snap a planet to the top when settling. */\n snap: boolean;\n}\n\nexport const DEFAULT_SPIN_SETTINGS: SpinSettings = {\n decay: 1.4,\n maxSpeed: 1440,\n settleSpeed: 30,\n snap: false,\n};\n\nexport type SpinMode = 'idle' | 'dragging' | 'coasting' | 'settling';\n\n/** Natural frequency of the settling spring, in radians per second (critically damped). */\nconst SETTLE_FREQUENCY = 10;\n\nexport class SpinPhysics {\n /** Rotation of the orbit, in degrees. */\n angle = 0;\n\n /** Degrees per millisecond. */\n velocity = 0;\n\n mode: SpinMode = 'idle';\n settings: SpinSettings;\n private settleTarget = 0;\n\n /** Angles (degrees) that put a planet at the top; used for snapping. */\n private slots: number[] = [];\n\n constructor(settings: Partial<SpinSettings> = {}) {\n this.settings = { ...DEFAULT_SPIN_SETTINGS, ...settings };\n }\n\n /** The finger is on the orbit: stops any coast. */\n grab(): void {\n this.mode = 'dragging';\n this.velocity = 0;\n }\n\n /** Rotates directly while dragging. */\n drag(delta: number): void {\n this.angle += delta;\n }\n\n /** Lets go with a velocity in degrees per millisecond. */\n release(velocity: number, slots: number[] = []): void {\n this.slots = slots;\n const limit = this.settings.maxSpeed / 1000;\n this.velocity = Math.max(-limit, Math.min(limit, velocity));\n\n if (Math.abs(this.velocity) * 1000 >= this.settings.settleSpeed) {\n this.mode = 'coasting';\n } else {\n this.beginSettling();\n }\n }\n\n /** Eases the orbit to the turn equivalent to `angle` (degrees) that is nearest to where it is now. */\n settleTo(angle: number): void {\n this.settleTarget = this.angle + normalizeDelta(angle - this.angle);\n this.mode = 'settling';\n }\n\n /** Stops immediately, wherever the orbit is. */\n stop(): void {\n this.mode = 'idle';\n this.velocity = 0;\n }\n\n get isMoving(): boolean {\n return this.mode === 'coasting' || this.mode === 'settling';\n }\n\n /** Advances by `elapsed` milliseconds. Returns whether the orbit is still moving. */\n step(elapsed: number): boolean {\n if (this.mode === 'coasting') {\n const timeConstant = this.settings.decay * 1000;\n const retained = Math.exp(-elapsed / timeConstant);\n // Exact integral of v·e^(−t/τ) over the step, so frame rate never matters.\n this.angle += this.velocity * timeConstant * (1 - retained);\n this.velocity *= retained;\n\n if (Math.abs(this.velocity) * 1000 < this.settings.settleSpeed) {\n this.beginSettling();\n }\n\n return true;\n }\n\n if (this.mode === 'settling') {\n return this.stepSettling(elapsed);\n }\n\n return false;\n }\n\n private beginSettling(): void {\n if (!this.settings.snap || this.slots.length === 0) {\n this.stop();\n return;\n }\n\n this.settleTarget = this.nearestSlot(this.angle);\n this.mode = 'settling';\n }\n\n private nearestSlot(angle: number): number {\n let best = angle;\n let bestDistance = Infinity;\n\n for (const slot of this.slots) {\n const distance = normalizeDelta(slot - angle);\n\n if (Math.abs(distance) < bestDistance) {\n bestDistance = Math.abs(distance);\n best = angle + distance;\n }\n }\n\n return best;\n }\n\n private stepSettling(elapsed: number): boolean {\n // Critically damped spring, integrated in 4 ms steps for stability.\n let remaining = elapsed / 1000;\n let velocity = this.velocity * 1000;\n\n while (remaining > 0) {\n const step = Math.min(remaining, 0.004);\n const offset = this.angle - this.settleTarget;\n const acceleration = -SETTLE_FREQUENCY * SETTLE_FREQUENCY * offset - 2 * SETTLE_FREQUENCY * velocity;\n velocity += acceleration * step;\n this.angle += velocity * step;\n remaining -= step;\n }\n\n this.velocity = velocity / 1000;\n\n if (Math.abs(this.angle - this.settleTarget) < 0.05 && Math.abs(velocity) < 0.5) {\n this.angle = this.settleTarget;\n this.stop();\n return false;\n }\n\n return true;\n }\n}\n",
|
|
40
|
+
"/**\n * Pan momentum for the overview. Like the orbit spin, the release velocity\n * is the least-squares slope of the last 80 ms of pointer movement, and the\n * glide slows down exponentially using the exact solution for each step.\n */\n\nconst VELOCITY_WINDOW = 80;\nconst STALE_AFTER = 50;\nconst SAMPLE_HISTORY = 160;\n\nexport interface Velocity {\n /** Pixels per millisecond. */\n x: number;\n\n y: number;\n}\n\n/** Tracks a dragged position over time and reports the release velocity. */\nexport class PointVelocityTracker {\n private samples: { time: number; x: number; y: number }[] = [];\n private x = 0;\n private y = 0;\n\n reset(time: number): void {\n this.x = 0;\n this.y = 0;\n this.samples = [{ time, x: 0, y: 0 }];\n }\n\n /** Records a movement of (`deltaX`, `deltaY`) pixels at `time` (milliseconds). */\n add(time: number, deltaX: number, deltaY: number): void {\n this.x += deltaX;\n this.y += deltaY;\n this.samples.push({ time, x: this.x, y: this.y });\n\n while (this.samples.length > 2 && time - this.samples[0].time > SAMPLE_HISTORY) {\n this.samples.shift();\n }\n }\n\n velocityAt(releaseTime: number): Velocity {\n const recent = this.samples.filter((sample) => releaseTime - sample.time <= VELOCITY_WINDOW);\n\n if (recent.length < 2 || releaseTime - recent[recent.length - 1].time > STALE_AFTER) {\n return { x: 0, y: 0 };\n }\n\n const meanTime = recent.reduce((sum, sample) => sum + sample.time, 0) / recent.length;\n const meanX = recent.reduce((sum, sample) => sum + sample.x, 0) / recent.length;\n const meanY = recent.reduce((sum, sample) => sum + sample.y, 0) / recent.length;\n let covarianceX = 0;\n let covarianceY = 0;\n let variance = 0;\n\n for (const sample of recent) {\n const time = sample.time - meanTime;\n covarianceX += time * (sample.x - meanX);\n covarianceY += time * (sample.y - meanY);\n variance += time * time;\n }\n\n if (variance === 0) {\n return { x: 0, y: 0 };\n }\n\n return { x: covarianceX / variance, y: covarianceY / variance };\n }\n}\n\n/** Fastest glide, in pixels per millisecond. */\nconst MAXIMUM_SPEED = 6;\n/** Below this speed (pixels per millisecond) a glide stops. */\nconst STOP_SPEED = 0.02;\n\nexport class Glide {\n velocity: Velocity = { x: 0, y: 0 };\n private readonly timeConstant: number;\n\n /** `timeConstant` in milliseconds: how long the glide takes to lose about two thirds of its speed. */\n constructor(timeConstant = 325) {\n this.timeConstant = timeConstant;\n }\n\n get isMoving(): boolean {\n return Math.hypot(this.velocity.x, this.velocity.y) >= STOP_SPEED;\n }\n\n start(velocity: Velocity): void {\n const speed = Math.hypot(velocity.x, velocity.y);\n const scale = speed > MAXIMUM_SPEED ? MAXIMUM_SPEED / speed : 1;\n this.velocity = { x: velocity.x * scale, y: velocity.y * scale };\n }\n\n stop(): void {\n this.velocity = { x: 0, y: 0 };\n }\n\n /** Advances by `elapsed` milliseconds and returns the distance travelled, in pixels. */\n step(elapsed: number): { x: number; y: number } {\n const retained = Math.exp(-elapsed / this.timeConstant);\n const travelled = this.timeConstant * (1 - retained);\n const distance = { x: this.velocity.x * travelled, y: this.velocity.y * travelled };\n this.velocity = { x: this.velocity.x * retained, y: this.velocity.y * retained };\n\n if (!this.isMoving) {\n this.stop();\n }\n\n return distance;\n }\n}\n",
|
|
41
|
+
"import type { OrbitNode } from './types.js';\nimport { clamp } from './utils.js';\n\n/** Where the layout puts the map and how much room it has. */\nexport interface LayoutConfig {\n cx: number;\n cy: number;\n containerWidth: number;\n containerHeight: number;\n\n /** Levels below the layout root to render; deeper nodes are omitted. */\n maxDepth?: number;\n\n /**\n * Focus layouts: ring radii to keep where the orbit has as many rings,\n * instead of making room for the moons again. A drag along the orbit keeps\n * the rings it began with. Rings never come out smaller than the planets need.\n */\n keptRings?: number[];\n}\n\n/** A node with its place in the layout. */\nexport interface PositionedNode extends OrbitNode {\n x: number;\n y: number;\n radius: number;\n\n /** Degrees: 0 is right, -90 is up. */\n angle: number;\n\n /** Distance from the parent. */\n orbitRadius: number;\n}\n\ninterface MeasuredNode {\n node: OrbitNode;\n radius: number;\n subtreeRadius: number;\n childOrbitRadius: number;\n children: MeasuredNode[];\n}\n\nconst SPACING_FACTOR = 1.32;\nconst NODE_GAP = 14;\nconst MIN_SUN_RADIUS = 34;\nconst MIN_PLANET_RADIUS = 18;\nconst MAX_SUN_RADIUS = 76;\nconst MAX_PLANET_RADIUS = 48;\n/**\n * An orbit's planets fill rings out from the sun until they all fit. Past\n * this many rings, the last of them may stretch to take the rest instead,\n * when that keeps the orbit smaller than more rings would.\n */\nconst ROOMY_RING_LIMIT = 7;\nconst FOCUS_RING_GAP_FACTOR = 2.15;\n/**\n * Crowded orbits of planets without moons pack closer: rings start right\n * outside the sun and sit a planet's width apart, with more of them before\n * the last may stretch, so the planets come out as big as the screen allows.\n */\nconst COMPACT_RING_GAP = 8;\nconst COMPACT_RING_LIMIT = 12;\n/** An orbit of this many rings or more is crowded: its sun grows (see calculateFocusLayout). */\nconst CROWDED_RING_COUNT = 4;\n\n/** Moons drawn around a planet; more children show as \"+N\". */\nexport const MOON_LIMIT = 6;\n/**\n * The room kept between a moon and another planet. Moons of different\n * planets keep a moon's radius apart, so that where two fans meet they read\n * as two.\n */\nconst MOON_CLEARANCE = 2;\n\n/** Where a planet's moons go: `distance` from its center, at `offsets` degrees from the direction away from the sun. */\nexport interface MoonPlacement {\n distance: number;\n radius: number;\n offsets: number[];\n}\n\n/** The moons of a planet fan out on its outer side, 30° apart, 150° at most. */\nexport const moonPlacement = (planetRadius: number, moonCount: number): MoonPlacement => {\n const count = Math.min(moonCount, MOON_LIMIT);\n const spread = Math.min(150, (count - 1) * 30);\n return {\n distance: planetRadius * 1.45,\n radius: Math.min(7, Math.max(2.5, planetRadius * 0.17)),\n offsets: Array.from({ length: count }, (_, index) => (count === 1 ? 0 : -spread / 2 + (spread * index) / (count - 1))),\n };\n};\n\n/**\n * Calculate layout for focus mode (center sun + direct children).\n * The orbit radius is never clamped below the collision-free radius. If the\n * result is wider than the container, the renderer auto-fits the whole group.\n */\nexport const calculateFocusLayout = (\n focusedNode: OrbitNode,\n config: LayoutConfig,\n): { sun: PositionedNode; planets: PositionedNode[]; orbitRadius: number; orbitRings: number[] } => {\n const { cx, cy, containerWidth, containerHeight } = config;\n const depthCapped = config.maxDepth !== undefined && focusedNode.level >= config.maxDepth;\n const children = depthCapped ? [] : visibleChildren(focusedNode);\n const childCount = children.length;\n const baseDim = layoutBasis(containerWidth, containerHeight);\n\n let sunRadius = clamp(baseDim * 0.115, MIN_SUN_RADIUS, MAX_SUN_RADIUS);\n const planetDensityScale = childCount === 0\n ? 1\n : clamp(Math.pow(10 / childCount, 0.32), 0.58, 1.1);\n const planetRadius = clamp(\n baseDim * 0.074 * planetDensityScale,\n MIN_PLANET_RADIUS,\n MAX_PLANET_RADIUS,\n );\n const compact = children.every((child) => visibleChildren(child).length === 0);\n let orbitPlan = calculateFocusRingPlan(childCount, sunRadius, planetRadius, baseDim, compact);\n\n // A crowded orbit shrinks its sun on screen with everything else: the sun grows with its rings,\n // so the focused node stays the focus and its name stays legible.\n if (orbitPlan.rings.length >= CROWDED_RING_COUNT) {\n const grown = Math.min(MAX_SUN_RADIUS, sunRadius * (1 + 0.06 * (orbitPlan.rings.length - 1)));\n\n if (grown > sunRadius) {\n sunRadius = grown;\n orbitPlan = calculateFocusRingPlan(childCount, sunRadius, planetRadius, baseDim, compact);\n }\n }\n\n const keptRings = config.keptRings;\n\n if (keptRings && keptRings.length === orbitPlan.rings.length) {\n orbitPlan.rings = orbitPlan.rings.map((radius, index) => Math.max(radius, keptRings[index]));\n } else {\n const moonsHidden = config.maxDepth !== undefined && focusedNode.level + 1 >= config.maxDepth;\n const moonCounts = children.map((child) => (moonsHidden ? 0 : Math.min(visibleChildren(child).length, MOON_LIMIT)));\n makeRoomForMoons(orbitPlan, planetRadius, moonCounts);\n }\n\n const orbitRadius = orbitPlan.rings[orbitPlan.rings.length - 1] ?? 0;\n\n const sun: PositionedNode = {\n ...focusedNode,\n parent: focusedNode.parent,\n x: cx,\n y: cy,\n radius: sunRadius,\n angle: -90,\n orbitRadius: 0,\n };\n\n const planets: PositionedNode[] = [];\n let childIndex = 0;\n\n orbitPlan.rings.forEach((ringRadius, ringIndex) => {\n const ringCount = orbitPlan.counts[ringIndex] ?? 0;\n const angleStep = 360 / ringCount;\n const startAngle = ringStartAngle(ringIndex, ringCount);\n\n for (let localIndex = 0; localIndex < ringCount; localIndex += 1) {\n const child = children[childIndex];\n\n if (!child) {\n break;\n }\n\n const angleDeg = startAngle + angleStep * localIndex;\n const angleRad = toRadians(angleDeg);\n\n planets.push({\n ...child,\n parent: child.parent,\n x: cx + ringRadius * Math.cos(angleRad),\n y: cy + ringRadius * Math.sin(angleRad),\n radius: planetRadius,\n angle: angleDeg,\n orbitRadius: ringRadius,\n });\n childIndex += 1;\n }\n });\n\n return { sun, planets, orbitRadius, orbitRings: orbitPlan.rings };\n};\n\n/**\n * Calculate layout for all mode. Each node owns a measured subtree circle; a\n * parent's child orbit is sized so sibling subtree circles cannot overlap.\n */\nexport const calculateAllLayout = (\n node: OrbitNode,\n config: LayoutConfig,\n parentAngle: number = -90,\n): PositionedNode[] => {\n const baseDim = layoutBasis(config.containerWidth, config.containerHeight);\n const complexityScale = clamp(Math.pow(18 / countVisibleNodes(node), 0.18), 0.74, 1.08);\n const measured = measureSubtree(node, baseDim, complexityScale, config.maxDepth ?? Infinity);\n const positionedNodes: PositionedNode[] = [];\n\n placeSubtree(measured, config.cx, config.cy, parentAngle, 0, positionedNodes);\n return positionedNodes;\n};\n\n/**\n * The rings of the overview: one around each node with children, through them.\n */\nexport const getOrbitRings = (\n positionedNodes: PositionedNode[],\n): { centerId: string; cx: number; cy: number; r: number }[] => {\n const rings: { centerId: string; cx: number; cy: number; r: number }[] = [];\n const seen = new Set<string>();\n\n for (const node of positionedNodes) {\n if (visibleChildren(node).length === 0) {\n continue;\n }\n\n const childNode = positionedNodes.find(\n (n) => n.parent?.id === node.id && n.id !== node.id,\n );\n\n if (!childNode) {\n continue;\n }\n\n const dx = childNode.x - node.x;\n const dy = childNode.y - node.y;\n const r = Math.sqrt(dx * dx + dy * dy);\n const key = `${node.x.toFixed(1)},${node.y.toFixed(1)},${r.toFixed(1)}`;\n\n if (!seen.has(key) && r > 10) {\n seen.add(key);\n rings.push({ centerId: node.id, cx: node.x, cy: node.y, r });\n }\n }\n\n return rings;\n};\n\nconst measureSubtree = (\n node: OrbitNode,\n baseDim: number,\n complexityScale: number,\n depthRemaining: number,\n): MeasuredNode => {\n const radius = radiusForLevel(baseDim, node.level, complexityScale);\n const children = depthRemaining > 0 ? visibleChildren(node) : [];\n const childMeasures = children.map((child) => measureSubtree(child, baseDim, complexityScale, depthRemaining - 1));\n\n const childBounds = childMeasures.map((child) => child.subtreeRadius);\n const childOrbitRadius = requiredOrbitRadius(radius, childBounds);\n const maxChildBound = childBounds.length > 0 ? Math.max(...childBounds) : 0;\n\n return {\n node,\n radius,\n subtreeRadius: Math.max(radius, childOrbitRadius + maxChildBound),\n childOrbitRadius,\n children: childMeasures,\n };\n};\n\nconst MAX_FAN_DEGREES = 270;\n\nconst placeSubtree = (\n measured: MeasuredNode,\n x: number,\n y: number,\n angle: number,\n orbitRadius: number,\n positionedNodes: PositionedNode[],\n): void => {\n const positioned: PositionedNode = {\n ...measured.node,\n parent: measured.node.parent,\n x,\n y,\n radius: measured.radius,\n angle,\n orbitRadius,\n };\n\n positionedNodes.push(positioned);\n\n const childCount = measured.children.length;\n\n if (childCount === 0) {\n return;\n }\n\n const isRoot = measured.node.level === 0;\n const fullCircle = isRoot || childCount === 1;\n const naturalFan = (childCount - 1) * (360 / childCount);\n const fanDegrees = fullCircle ? 360 : Math.min(naturalFan, MAX_FAN_DEGREES);\n const angleStep = childCount === 1\n ? 0\n : fullCircle\n ? 360 / childCount\n : fanDegrees / (childCount - 1);\n\n const startAngle = childCount === 1\n ? angle\n : isRoot\n ? -90\n : angle - fanDegrees / 2;\n\n measured.children.forEach((child, index) => {\n const childAngle = startAngle + angleStep * index;\n const angleRad = toRadians(childAngle);\n const childX = x + measured.childOrbitRadius * Math.cos(angleRad);\n const childY = y + measured.childOrbitRadius * Math.sin(angleRad);\n placeSubtree(child, childX, childY, childAngle, measured.childOrbitRadius, positionedNodes);\n });\n};\n\nconst requiredOrbitRadius = (centerRadius: number, childRadii: number[]): number => {\n if (childRadii.length === 0) {\n return 0;\n }\n\n const parentClearance = Math.max(\n ...childRadii.map((childRadius) => centerRadius + childRadius + NODE_GAP),\n );\n\n if (childRadii.length === 1) {\n return parentClearance;\n }\n\n const angleStep = (2 * Math.PI) / childRadii.length;\n const chordFactor = 2 * Math.sin(angleStep / 2);\n\n const siblingClearance = childRadii.reduce((max, childRadius, index) => {\n const nextRadius = childRadii[(index + 1) % childRadii.length];\n const required = ((childRadius + nextRadius) * SPACING_FACTOR + NODE_GAP) / chordFactor;\n return Math.max(max, required);\n }, 0);\n\n return Math.max(parentClearance, siblingClearance);\n};\n\nconst calculateFocusRingPlan = (\n childCount: number,\n sunRadius: number,\n planetRadius: number,\n baseDim: number,\n compact = false,\n): RingPlan => {\n if (childCount === 0) {\n return { rings: [], counts: [], ringGap: 0 };\n }\n\n const roomy = ringPlan(\n childCount,\n planetRadius,\n Math.max(baseDim * 0.26, sunRadius + planetRadius + NODE_GAP * 1.3),\n planetRadius * FOCUS_RING_GAP_FACTOR + NODE_GAP,\n ROOMY_RING_LIMIT,\n );\n\n // One ring keeps its roomy layout. Planets without moons that need several\n // rings pack closer, when that makes the orbit smaller.\n if (!compact || roomy.rings.length <= 1) {\n return roomy;\n }\n\n const close = ringPlan(childCount, planetRadius, sunRadius + planetRadius + NODE_GAP, planetRadius * 2 + COMPACT_RING_GAP, COMPACT_RING_LIMIT);\n return (close.rings.at(-1) ?? 0) < (roomy.rings.at(-1) ?? 0) ? close : roomy;\n};\n\n/** The rings of a focus view, the number of planets on each, and the distance between rings. */\ninterface RingPlan {\n rings: number[];\n counts: number[];\n ringGap: number;\n}\n\n/**\n * Rings from `innerRingRadius` out, `ringGap` apart, until they hold every\n * child. Past `ringLimit` rings, the last of the first `ringLimit` may\n * stretch to take the rest instead, when that keeps the orbit smaller: for a\n * few more planets it does, but a big orbit's last ring would stretch so far\n * out that every planet came out a speck.\n */\nconst ringPlan = (\n childCount: number,\n planetRadius: number,\n innerRingRadius: number,\n ringGap: number,\n ringLimit: number,\n): RingPlan => {\n const rings: number[] = [];\n let totalCapacity = 0;\n\n while (totalCapacity < childCount) {\n const radius = innerRingRadius + ringGap * rings.length;\n rings.push(radius);\n totalCapacity += focusRingCapacity(radius, planetRadius);\n }\n\n const fewer = rings.slice(0, ringLimit);\n const stretched: RingPlan = { rings: fewer, counts: distributeAcrossRings(childCount, fewer, planetRadius), ringGap };\n\n if (rings.length <= ringLimit) {\n return stretched;\n }\n\n const all: RingPlan = { rings, counts: distributeAcrossRings(childCount, rings, planetRadius), ringGap };\n return (all.rings.at(-1) ?? 0) < (stretched.rings.at(-1) ?? 0) ? all : stretched;\n};\n\n/** The first planet on each ring is at the top; every other ring is turned half a step. */\nconst ringStartAngle = (ringIndex: number, count: number): number => {\n return ringIndex % 2 === 0 ? -90 : -90 + 360 / count / 2;\n};\n\ninterface Circle {\n x: number;\n y: number;\n radius: number;\n}\n\n/** A planet on a ring and its moons. */\ninterface PlanetBodies {\n planet: Circle;\n moons: Circle[];\n}\n\nconst planetBodies = (ringRadius: number, angle: number, planetRadius: number, moonCount: number): PlanetBodies => {\n const x = ringRadius * Math.cos(toRadians(angle));\n const y = ringRadius * Math.sin(toRadians(angle));\n const { distance, radius, offsets } = moonPlacement(planetRadius, moonCount);\n return {\n planet: { x, y, radius: planetRadius },\n moons: offsets.map((offset) => ({\n x: x + distance * Math.cos(toRadians(angle + offset)),\n y: y + distance * Math.sin(toRadians(angle + offset)),\n radius,\n })),\n };\n};\n\nconst apart = (first: Circle, second: Circle, gap: number): boolean => {\n return Math.hypot(first.x - second.x, first.y - second.y) >= first.radius + second.radius + gap;\n};\n\n/** Whether the moons of either planet keep clear of the other planet and its moons (see `MOON_CLEARANCE`). */\nconst moonsClear = (first: PlanetBodies, second: PlanetBodies): boolean => {\n return first.moons.every((moon) => apart(moon, second.planet, MOON_CLEARANCE) && second.moons.every((other) => apart(moon, other, moon.radius)))\n && second.moons.every((moon) => apart(moon, first.planet, MOON_CLEARANCE));\n};\n\n/** Whether every moon of `planet` is nearer it than `neighbor`: a moon past the middle reads as the neighbor's. */\nconst moonsOnOwnSide = (planet: PlanetBodies, neighbor: PlanetBodies): boolean => {\n return planet.moons.every((moon) => {\n return Math.hypot(moon.x - planet.planet.x, moon.y - planet.planet.y) < Math.hypot(moon.x - neighbor.planet.x, moon.y - neighbor.planet.y);\n });\n};\n\n/**\n * Rings are planned for the planets' bodies, but moons fan out on the outer\n * side of their planets, toward the neighbors on the ring and the next ring\n * out. Each ring with moons on it or inside it moves out (and the rings\n * beyond it with it) just as far as its moons need; orbits whose moons\n * already have room keep their rings.\n */\nconst makeRoomForMoons = (plan: RingPlan, planetRadius: number, moonCounts: number[]): void => {\n if (moonCounts.every((count) => count === 0)) {\n return;\n }\n\n const moonReach = moonPlacement(planetRadius, 1);\n // Planets farther apart than this can't touch each other's moons.\n const reach = 2 * (moonReach.distance + moonReach.radius) + Math.max(MOON_CLEARANCE, moonReach.radius);\n let first = 0;\n let inner: { radius: number; start: number; step: number; planets: PlanetBodies[] } | undefined;\n\n plan.rings.forEach((planned, ringIndex) => {\n const count = plan.counts[ringIndex] ?? 0;\n const moons = moonCounts.slice(first, first + count);\n const start = ringStartAngle(ringIndex, count);\n const step = 360 / Math.max(1, count);\n const innerPlanets = inner?.planets.some((planet) => planet.moons.length > 0) ? inner : undefined;\n // Neighbors on a ring are all `step` apart, so one pair of each kind tells for all of them.\n const neighborPairs = count < 2\n ? []\n : [...new Set(moons.map((moonCount, index) => `${moonCount},${moons[(index + 1) % count]}`))].map((pair) => pair.split(',').map(Number));\n\n const besideNeighbors = (radius: number): boolean => {\n return neighborPairs.every(([before, after]) => {\n const planet = planetBodies(radius, 0, planetRadius, before);\n const next = planetBodies(radius, step, planetRadius, after);\n return moonsClear(planet, next) && moonsOnOwnSide(planet, next) && moonsOnOwnSide(next, planet);\n });\n };\n\n // Moons on the ring inside reach out toward the planets on this one: check those within reach.\n const besideInnerRing = (radius: number): boolean => {\n if (!innerPlanets) {\n return true;\n }\n\n const total = innerPlanets.planets.length;\n const window = innerPlanets.radius <= reach ? 180 : toDegrees(Math.asin(reach / innerPlanets.radius));\n\n return moons.every((moonCount, index) => {\n const angle = start + step * index;\n const planet = planetBodies(radius, angle, planetRadius, moonCount);\n const lowest = Math.floor((angle - window - innerPlanets.start) / innerPlanets.step);\n const highest = Math.min(lowest + total - 1, Math.ceil((angle + window - innerPlanets.start) / innerPlanets.step));\n\n for (let candidate = lowest; candidate <= highest; candidate += 1) {\n const other = innerPlanets.planets[((candidate % total) + total) % total];\n\n if (Math.hypot(other.planet.x - planet.planet.x, other.planet.y - planet.planet.y) < reach && !moonsClear(other, planet)) {\n return false;\n }\n }\n\n return true;\n });\n };\n\n const lowest = ringIndex === 0 ? planned : Math.max(planned, plan.rings[ringIndex - 1] + plan.ringGap);\n const radius = smallestFitting(lowest, planetRadius, (candidate) => besideNeighbors(candidate) && besideInnerRing(candidate));\n plan.rings[ringIndex] = radius;\n inner = { radius, start, step, planets: moons.map((moonCount, index) => planetBodies(radius, start + step * index, planetRadius, moonCount)) };\n first += count;\n });\n};\n\n/** The smallest radius from `lowest` up that `fits`, to within a quarter; `fits` holds for every radius past one where it holds. */\nconst smallestFitting = (lowest: number, stride: number, fits: (radius: number) => boolean): number => {\n if (fits(lowest)) {\n return lowest;\n }\n\n let low = lowest;\n let high = lowest + stride;\n\n while (!fits(high)) {\n low = high;\n high += stride;\n }\n\n while (high - low > 0.25) {\n const middle = (low + high) / 2;\n\n if (fits(middle)) {\n high = middle;\n } else {\n low = middle;\n }\n }\n\n return high;\n};\n\nconst distributeAcrossRings = (childCount: number, rings: number[], planetRadius: number): number[] => {\n const capacities = rings.map((radius) => focusRingCapacity(radius, planetRadius));\n const counts: number[] = [];\n let remaining = childCount;\n\n for (let index = 0; index < rings.length; index += 1) {\n const ringsLeft = rings.length - index;\n const capacity = capacities[index] ?? remaining;\n const count = index === rings.length - 1\n ? remaining\n : Math.min(capacity, Math.ceil(remaining / ringsLeft));\n counts.push(count);\n remaining -= count;\n }\n\n const lastIndex = rings.length - 1;\n\n if (lastIndex >= 0) {\n rings[lastIndex] = Math.max(\n rings[lastIndex],\n requiredRingRadiusForCount(planetRadius, counts[lastIndex] ?? 0),\n );\n }\n\n return counts;\n};\n\nconst focusRingCapacity = (radius: number, planetRadius: number): number => {\n const minimumChord = planetRadius * 2 + NODE_GAP * 0.85;\n\n if (minimumChord >= radius * 2) {\n return 1;\n }\n\n const minAngle = 2 * Math.asin(minimumChord / (radius * 2));\n return Math.max(1, Math.floor((2 * Math.PI) / minAngle));\n};\n\nconst requiredRingRadiusForCount = (planetRadius: number, count: number): number => {\n if (count <= 1) {\n return 0;\n }\n\n const chordFactor = 2 * Math.sin(Math.PI / count);\n return (planetRadius * 2 + NODE_GAP * 0.85) / chordFactor;\n};\n\nconst radiusForLevel = (baseDim: number, level: number, scale: number): number => {\n if (level === 0) {\n return clamp(baseDim * 0.115 * scale, MIN_SUN_RADIUS, MAX_SUN_RADIUS);\n }\n\n if (level === 1) {\n return clamp(baseDim * 0.074 * scale, MIN_PLANET_RADIUS, MAX_PLANET_RADIUS);\n }\n\n if (level === 2) {\n return clamp(baseDim * 0.056 * scale, 15, 36);\n }\n\n return clamp(baseDim * 0.044 * scale, 12, 28);\n};\n\nconst layoutBasis = (containerWidth: number, containerHeight: number): number => {\n const shortSide = Math.min(containerWidth, containerHeight);\n const areaDim = Math.sqrt(containerWidth * containerHeight);\n return Math.min(areaDim, shortSide * 1.25);\n};\n\nconst countVisibleNodes = (node: OrbitNode): number => {\n return 1 + visibleChildren(node).reduce((sum, child) => sum + countVisibleNodes(child), 0);\n};\n\nconst visibleChildren = (node: OrbitNode): OrbitNode[] => {\n return node.collapsed ? [] : node.children;\n};\n\nconst toRadians = (degrees: number): number => {\n return (degrees * Math.PI) / 180;\n};\n\nconst toDegrees = (radians: number): number => {\n return (radians * 180) / Math.PI;\n};\n",
|
|
42
|
+
"const supports = (property: string, value: string): boolean => {\n const css = (globalThis as { CSS?: { supports?: (property: string, value: string) => boolean } }).CSS;\n return typeof css?.supports !== 'function' || css.supports(property, value);\n};\n\n/**\n * What the browser draws with, checked once. A few effects need newer CSS:\n * older browsers, such as the WebViews of phones that don't update theirs,\n * get plainer versions of them instead of broken ones. Outside a browser (on\n * a server, or tests without a DOM) everything counts as there.\n */\nexport const browser = {\n /** CSS `color-mix()` (Chromium 111, Safari 16.2, Firefox 113). Without it, siblings keep their branch's own color. */\n mixesColors: supports('color', 'color-mix(in oklab, red 50%, blue)'),\n\n /** The `translate` property (Chromium 104, Safari 14.1, Firefox 72). Without it, overlays are centered through their transform. */\n translates: supports('translate', '1px'),\n};\n\nconst coarseQueries = new WeakMap<Window, MediaQueryList>();\n\n/**\n * Whether `element`'s page is used with a finger (`pointer: coarse`), where\n * the stylesheet makes buttons bigger. The query is made once per window.\n */\nexport const pointsCoarsely = (element: Element): boolean => {\n const view = element.ownerDocument.defaultView;\n\n if (!view || typeof view.matchMedia !== 'function') {\n return false;\n }\n\n let query = coarseQueries.get(view);\n\n if (!query) {\n query = view.matchMedia('(pointer: coarse)');\n coarseQueries.set(view, query);\n }\n\n return query.matches;\n};\n\n/**\n * The transform that puts an overlay at `x`, `y`. `centering` is the\n * stylesheet's `translate` for it, as `translate()` takes it: where the\n * browser lacks that property, the transform moves the overlay instead.\n */\nexport const overlayTransform = (x: number, y: number, centering: string): string => {\n const position = `translate3d(${x}px, ${y}px, 0)`;\n return browser.translates ? position : `${position} translate(${centering})`;\n};\n",
|
|
43
|
+
"/**\n * Scenes: what each view of a map contains, in world coordinates.\n *\n * A focus scene puts the focused node (the sun) at the origin with its\n * children (planets) on rings and its grandchildren as small moons around\n * them. An overview scene lays out the whole tree around the root. Every\n * node keeps one color in every scene, and nodes are keyed by id so a\n * transition can morph the same node from one scene into the next: the\n * moons of a planet grow into the planets of the next view.\n */\n\nimport type { OrbitNode } from '../types.js';\nimport { branchNumbers, branchPalette, isPaletteNumber, paletteColorOf } from '../branch-colors.js';\nimport { calculateAllLayout, calculateFocusLayout, getOrbitRings, MOON_LIMIT, moonPlacement } from '../layout.js';\nimport { findNodeById } from '../utils.js';\nimport { browser } from '../browser.js';\nimport { fitAround, type Camera, type Insets, type Similarity, type Viewport, applySimilarity } from './camera.js';\n\nexport type NodeRole = 'sun' | 'planet' | 'moon' | 'node';\n\nexport interface SceneNode {\n id: string;\n node: OrbitNode;\n role: NodeRole;\n\n /** World position of the center, before any orbit spin. */\n x: number;\n\n y: number;\n radius: number;\n color: string;\n depth: number;\n parentId?: string;\n\n /** Planets: angle around the sun (degrees, −90 = top) and distance from it. */\n orbitAngle?: number;\n\n orbitRadius?: number;\n\n /** Moons: the planet they circle, their angle relative to the direction from the sun to the planet, and their distance. */\n hostId?: string;\n\n hostOffset?: number;\n hostDistance?: number;\n\n /** Children that exist but aren't drawn: beyond the moon limit, or under a collapsed node. */\n hiddenChildren: number;\n\n /** Turns with the orbit when it spins. */\n spins: boolean;\n\n /** A planet of an orbit too crowded for each planet's shadow to read: drawn flat. */\n crowded?: boolean;\n}\n\nexport interface SceneRing {\n id: string;\n centerId: string;\n cx: number;\n cy: number;\n radius: number;\n color: string;\n\n /** Openings around each body on the ring, so the line never runs through a node. */\n gaps: { angle: number; halfWidth: number }[];\n\n spins: boolean;\n}\n\nexport interface SceneLink {\n id: string;\n fromId: string;\n toId: string;\n color: string;\n}\n\nexport interface Scene {\n kind: 'focus' | 'overview';\n focusId: string;\n nodes: Map<string, SceneNode>;\n rings: SceneRing[];\n links: SceneLink[];\n\n /** The camera that fits the scene into the viewport. */\n frame: Camera;\n\n /**\n * How far the scene reaches from its focus node on each axis, in world\n * units: what `frame` fits. A focus scene reaches as far on both, the edge\n * of its orbit at every turn.\n */\n extent: { x: number; y: number };\n\n /** Focus scenes of editable maps: the free place in the orbit where a new idea goes. */\n addSlot?: SceneSlot;\n}\n\n/** A free place in the sun's orbit, laid out like a planet, for the next child. */\nexport interface SceneSlot {\n /** The node a new idea there becomes a child of: the sun. */\n parentId: string;\n\n /** Its position among the sun's children. */\n index: number;\n\n x: number;\n y: number;\n radius: number;\n orbitAngle: number;\n orbitRadius: number;\n}\n\nexport interface SceneOptions {\n viewport: Viewport;\n\n /** The parts of the viewport the page's own controls cover: views are fitted into the rest. */\n insets?: Insets;\n\n colors: Map<string, string>;\n maxDepth?: number;\n\n /** Keep a place in the orbit for a new idea, after the sun's children (or at `index`). Focus scenes only. */\n addSlot?: { index?: number };\n\n /**\n * One of the sun's children being dragged to another place among them: it's\n * laid out at `index` among the others, so they make room for it there.\n * Focus scenes only.\n */\n reorder?: { id: string; index: number };\n\n /**\n * While a node is carried along the orbit of `focusId`: the radii its rings\n * had when the drag began. They keep them until the drop, so the orbit\n * doesn't grow or shrink as the places in it move. Focus scenes only.\n */\n keptRings?: { focusId: string; radii: number[] };\n}\n\n/** The id the slot uses while it is laid out with the planets; no node can have it. */\nconst SLOT_ID = '\\u0000orbit-add';\n\nexport { MOON_LIMIT };\n/** More planets than this in one view, and their shadows overlap into a haze: they're drawn flat. */\nexport const CROWDED_ORBIT = 48;\n/** The largest zoom a fitted view uses, so small maps don't balloon. */\nconst MAXIMUM_FIT_SCALE = 1.35;\nconst FOCUS_PADDING = 40;\nconst OVERVIEW_PADDING = 48;\n\n/** Room kept around a fitted view: less on small screens, where every pixel counts. */\nconst fitPadding = (viewport: Viewport, padding: number): number => {\n return Math.min(padding, Math.max(16, Math.min(viewport.width, viewport.height) * 0.05));\n};\n\n/**\n * The camera that fits a view reaching `extent` from its focus node into\n * `viewport`, inside what `insets` leave of it, with at least `below` px\n * between the view and the lower edge of that.\n */\nconst fitExtent = (kind: Scene['kind'], extent: Scene['extent'], viewport: Viewport, insets: Insets | undefined, below = 0): Camera => {\n const padding = fitPadding(viewport, kind === 'focus' ? FOCUS_PADDING : OVERVIEW_PADDING);\n const room = Math.max(0, below - padding);\n const sides = insets ?? { top: 0, right: 0, bottom: 0, left: 0 };\n return fitAround({ x: 0, y: 0 }, extent, viewport, padding, MAXIMUM_FIT_SCALE, room > 0 ? { ...sides, bottom: sides.bottom + room } : sides);\n};\n\n/**\n * The camera that fits `scene` into `viewport` as its `frame` does, inside\n * what `insets` leave of it, and with at least `below` px under it: room for\n * something drawn there, such as the focused node's buttons.\n */\nexport const fitScene = (scene: Scene, viewport: Viewport, insets?: Insets, below = 0): Camera => {\n return fitExtent(scene.kind, scene.extent, viewport, insets, below);\n};\n\nconst RING_GAP_PADDING = 7;\n\n/**\n * One color per node, the same in every view. The root uses the first\n * palette entry; top-level branches take the others in turn (see\n * `branchNumbers`); deeper nodes use their branch's color, mixed toward the\n * theme's `shade-light` or `shade-dark` by position so siblings stay\n * distinguishable. A node's own color always wins: its `color`, or its\n * type's (see `ownColor`); then its `paletteColor`.\n */\nexport const assignNodeColors = (\n tree: OrbitNode,\n palette: string[],\n ownColor: (node: OrbitNode) => string | undefined = (node) => node.color,\n): Map<string, string> => {\n const colors = new Map<string, string>();\n const branchColors = branchPalette(palette);\n const numbers = branchNumbers(tree.children, branchColors.length);\n const chosen = (node: OrbitNode): string | undefined => ownColor(node) ?? (isPaletteNumber(node.paletteColor) ? paletteColorOf(branchColors, node.paletteColor) : undefined);\n colors.set(tree.id, chosen(tree) ?? palette[0]);\n\n for (const branch of tree.children) {\n const branchColor = ownColor(branch) ?? paletteColorOf(branchColors, numbers.get(branch) as number);\n colors.set(branch.id, branchColor);\n\n const visit = (node: OrbitNode, inherited: string) => {\n node.children.forEach((child, siblingIndex) => {\n const own = chosen(child);\n colors.set(child.id, own ?? shade(inherited, siblingIndex));\n visit(child, own ?? inherited);\n });\n };\n\n visit(branch, branchColor);\n }\n\n return colors;\n};\n\n/** How much of the branch color each sibling keeps, and what the rest is mixed with. */\nexport const SHADES: [number, 'light' | 'dark'][] = [\n [100, 'light'],\n [78, 'light'],\n [86, 'dark'],\n [62, 'light'],\n [76, 'dark'],\n];\n\nconst shade = (color: string, siblingIndex: number): string => {\n const [amount, toward] = SHADES[siblingIndex % SHADES.length];\n return amount === 100 || !browser.mixesColors ? color : `color-mix(in oklab, ${color} ${amount}%, var(--_orbit-shade-${toward}))`;\n};\n\n/** `children` with the one `reorder` names moved to its index among the others (unchanged without it). */\nconst reordered = (children: OrbitNode[], reorder: SceneOptions['reorder']): OrbitNode[] => {\n const moving = reorder ? children.find((child) => child.id === reorder.id) : undefined;\n\n if (!reorder || !moving) {\n return children;\n }\n\n const others = children.filter((child) => child !== moving);\n const index = Math.min(others.length, Math.max(0, Math.trunc(reorder.index)));\n return [...others.slice(0, index), moving, ...others.slice(index)];\n};\n\nconst visibleChildren = (node: OrbitNode, maxDepth: number | undefined): OrbitNode[] => {\n if (node.collapsed) {\n return [];\n }\n\n if (maxDepth !== undefined && node.level >= maxDepth) {\n return [];\n }\n\n return node.children;\n};\n\nexport const buildFocusScene = (tree: OrbitNode, focusId: string, options: SceneOptions): Scene => {\n const focused = findNodeById(tree, focusId) ?? tree;\n const { viewport, colors, maxDepth, reorder } = options;\n const children = reordered(focused.children, reorder);\n const canGrow = maxDepth === undefined || focused.level < maxDepth;\n const slotIndex = options.addSlot && canGrow\n ? Math.min(children.length, Math.max(0, Math.trunc(options.addSlot.index ?? children.length)))\n : null;\n // Entering a collapsed node opens it: `collapsed` folds a node away\n // elsewhere (no moons, a \"+N\" count), never in its own focus view. The\n // slot for a new idea is laid out as one more child.\n const laidOut: OrbitNode = focused.collapsed || slotIndex !== null || children !== focused.children\n ? { ...focused, collapsed: false, children }\n : focused;\n\n if (slotIndex !== null) {\n const slot: OrbitNode = { id: SLOT_ID, text: '', level: focused.level + 1, children: [] };\n laidOut.children = [...children.slice(0, slotIndex), slot, ...children.slice(slotIndex)];\n }\n\n const layout = calculateFocusLayout(laidOut, {\n cx: 0,\n cy: 0,\n containerWidth: viewport.width,\n containerHeight: viewport.height,\n maxDepth,\n keptRings: options.keptRings?.focusId === focused.id ? options.keptRings.radii : undefined,\n });\n const slotCount = slotIndex === null ? 0 : 1;\n const nodes = new Map<string, SceneNode>();\n const colorOf = (node: OrbitNode) => colors.get(node.id) ?? node.color ?? '#999999';\n\n nodes.set(focused.id, {\n id: focused.id,\n node: focused,\n role: 'sun',\n x: 0,\n y: 0,\n radius: layout.sun.radius,\n color: colorOf(focused),\n depth: focused.level,\n parentId: focused.parent?.id,\n hiddenChildren: Math.max(0, children.length - (layout.planets.length - slotCount)),\n spins: false,\n });\n\n let extentX = layout.sun.radius;\n let extentY = layout.sun.radius;\n const planetRadius = roomyPlanetRadius(layout);\n const crowded = layout.planets.length - slotCount > CROWDED_ORBIT;\n let addSlot: SceneSlot | undefined;\n\n for (const planet of layout.planets) {\n if (planet.id === SLOT_ID) {\n addSlot = {\n parentId: focused.id,\n index: slotIndex ?? focused.children.length,\n x: planet.x,\n y: planet.y,\n radius: planetRadius ?? planet.radius,\n orbitAngle: planet.angle,\n orbitRadius: planet.orbitRadius,\n };\n extentX = Math.max(extentX, planet.orbitRadius + addSlot.radius);\n extentY = Math.max(extentY, planet.orbitRadius + addSlot.radius);\n continue;\n }\n\n const node = findNodeById(focused, planet.id) ?? planet;\n const moons = visibleChildren(node, maxDepth).slice(0, MOON_LIMIT);\n const radius = planetRadius ?? planet.radius;\n nodes.set(planet.id, {\n id: planet.id,\n node,\n role: 'planet',\n x: planet.x,\n y: planet.y,\n radius,\n color: colorOf(node),\n depth: node.level,\n parentId: focused.id,\n orbitAngle: planet.angle,\n orbitRadius: planet.orbitRadius,\n hiddenChildren: node.children.length - moons.length,\n spins: true,\n crowded,\n });\n const { distance: moonDistance, radius: moonRadius, offsets } = moonPlacement(radius, moons.length);\n\n moons.forEach((moon, index) => {\n const offset = offsets[index];\n const angle = toRadians(planet.angle + offset);\n nodes.set(moon.id, {\n id: moon.id,\n node: moon,\n role: 'moon',\n x: planet.x + moonDistance * Math.cos(angle),\n y: planet.y + moonDistance * Math.sin(angle),\n radius: moonRadius,\n color: colorOf(moon),\n depth: moon.level,\n parentId: planet.id,\n hostId: planet.id,\n hostOffset: offset,\n hostDistance: moonDistance,\n hiddenChildren: moon.children.length,\n spins: true,\n });\n });\n\n const reach = planet.orbitRadius + (moons.length > 0 ? moonDistance + moonRadius : radius);\n extentX = Math.max(extentX, reach);\n extentY = Math.max(extentY, reach);\n }\n\n const rings: SceneRing[] = layout.planets.length === 0\n ? []\n : layout.orbitRings.map((radius, index) => ({\n id: `${focused.id}#${index}`,\n centerId: focused.id,\n cx: 0,\n cy: 0,\n radius,\n color: colorOf(focused),\n gaps: layout.planets\n .filter((planet) => Math.abs(planet.orbitRadius - radius) < 0.5)\n .map((planet) => ({ angle: planet.angle, halfWidth: gapHalfWidth(planetRadius ?? planet.radius, radius) })),\n spins: true,\n }));\n\n const extent = { x: extentX, y: extentY };\n return {\n kind: 'focus',\n focusId: focused.id,\n nodes,\n rings,\n links: [],\n frame: fitExtent('focus', extent, viewport, options.insets),\n extent,\n addSlot,\n };\n};\n\n/**\n * A single ring of planets usually has room to spare: grow the planets\n * (and with them their moons) toward the sun's size, as far as the\n * neighbors and the sun allow. Null keeps the layout's size.\n */\nconst roomyPlanetRadius = (layout: ReturnType<typeof calculateFocusLayout>): number | null => {\n if (layout.orbitRings.length !== 1 || layout.planets.length === 0) {\n return null;\n }\n\n const ring = layout.orbitRings[0];\n const count = layout.planets.length;\n // Half the distance to a neighbor, less the moons that reach sideways.\n const besideNeighbors = count > 1 ? (ring * Math.sin(Math.PI / count) - 14) / 1.45 : Infinity;\n const besideSun = ring - layout.sun.radius - 24;\n const current = layout.planets[0].radius;\n return Math.max(current, Math.min(layout.sun.radius * 0.72, besideNeighbors, besideSun));\n};\n\nexport const buildOverviewScene = (tree: OrbitNode, options: SceneOptions): Scene => {\n const { viewport, colors, maxDepth } = options;\n const positioned = calculateAllLayout(tree, {\n cx: 0,\n cy: 0,\n containerWidth: viewport.width,\n containerHeight: viewport.height,\n maxDepth,\n });\n const nodes = new Map<string, SceneNode>();\n const links: SceneLink[] = [];\n const byId = indexTree(tree);\n let extentX = 0;\n let extentY = 0;\n\n for (const entry of positioned) {\n const node = byId.get(entry.id) ?? entry;\n const color = colors.get(node.id) ?? '#999999';\n const shown = visibleChildren(node, maxDepth).length;\n nodes.set(entry.id, {\n id: entry.id,\n node,\n role: 'node',\n x: entry.x,\n y: entry.y,\n radius: entry.radius,\n color,\n depth: node.level,\n parentId: entry.parent?.id,\n hiddenChildren: node.children.length - shown,\n spins: false,\n });\n\n if (entry.parent && node.level > 0) {\n links.push({ id: `${entry.parent.id}->${entry.id}`, fromId: entry.parent.id, toId: entry.id, color: colors.get(entry.parent.id) ?? color });\n }\n\n extentX = Math.max(extentX, Math.abs(entry.x) + entry.radius);\n extentY = Math.max(extentY, Math.abs(entry.y) + entry.radius);\n }\n\n const bodiesByCenter = new Map<string, typeof positioned>();\n\n for (const entry of positioned) {\n const parentId = entry.parent?.id;\n\n if (parentId !== undefined) {\n const bodies = bodiesByCenter.get(parentId) ?? [];\n bodies.push(entry);\n bodiesByCenter.set(parentId, bodies);\n }\n }\n\n const rings: SceneRing[] = getOrbitRings(positioned).map((ring) => {\n const { centerId } = ring;\n const bodies = bodiesByCenter.get(centerId) ?? [];\n return {\n id: `${centerId}#overview`,\n centerId,\n cx: ring.cx,\n cy: ring.cy,\n radius: ring.r,\n color: colors.get(centerId) ?? '#999999',\n gaps: bodies.map((body) => ({\n angle: toDegrees(Math.atan2(body.y - ring.cy, body.x - ring.cx)),\n halfWidth: gapHalfWidth(body.radius, ring.r),\n })),\n spins: false,\n };\n });\n\n // A ring reaches past the bodies on it where none of them sit near its extremes.\n for (const ring of rings) {\n extentX = Math.max(extentX, Math.abs(ring.cx) + ring.radius);\n extentY = Math.max(extentY, Math.abs(ring.cy) + ring.radius);\n }\n\n const extent = { x: extentX, y: extentY };\n return {\n kind: 'overview',\n focusId: tree.id,\n nodes,\n rings,\n links,\n frame: fitExtent('overview', extent, viewport, options.insets),\n extent,\n };\n};\n\n/** Every node of a tree by id. */\nconst indexTree = (tree: OrbitNode): Map<string, OrbitNode> => {\n const byId = new Map<string, OrbitNode>();\n\n const visit = (node: OrbitNode) => {\n byId.set(node.id, node);\n node.children.forEach(visit);\n };\n\n visit(tree);\n return byId;\n};\n\n/**\n * The transform that places `target` so the node `anchorId` lands exactly\n * where it is displayed now (`current`): used to fly from one view to the\n * next without any jump.\n */\nexport const alignScene = (target: Scene, anchorId: string, current: { x: number; y: number; radius: number }): Similarity => {\n const anchor = target.nodes.get(anchorId);\n\n if (!anchor || anchor.radius <= 0) {\n return { scale: 1, x: 0, y: 0 };\n }\n\n const scale = current.radius / anchor.radius;\n return { scale, x: current.x - anchor.x * scale, y: current.y - anchor.y * scale };\n};\n\n/** Applies a placement to a scene node's position and size. */\nexport const placeNode = (node: SceneNode, transform: Similarity): { x: number; y: number; radius: number } => {\n const point = applySimilarity(transform, node);\n return { x: point.x, y: point.y, radius: node.radius * transform.scale };\n};\n\n/** Gap half-width (degrees) that keeps a ring line clear of a body of `bodyRadius` sitting on it. */\nconst gapHalfWidth = (bodyRadius: number, ringRadius: number): number => {\n const ratio = Math.min(1, (bodyRadius + RING_GAP_PADDING) / Math.max(ringRadius, 1));\n return toDegrees(Math.asin(ratio));\n};\n\nexport const toRadians = (degrees: number): number => {\n return (degrees * Math.PI) / 180;\n};\n\nexport const toDegrees = (radians: number): number => {\n return (radians * 180) / Math.PI;\n};\n",
|
|
44
|
+
"/**\n * What is on screen this frame. Pure functions: a scene plus the orbit's\n * rotation gives the resting display; during a flight, the current display\n * morphs into the target scene placed in today's world coordinates.\n */\n\nimport type { OrbitNode } from '../types.js';\nimport { applySimilarity, transformCamera, type Camera, type CameraPath, type Similarity } from './camera.js';\nimport { interpolate, within } from './animation-clock.js';\nimport { toRadians, type NodeRole, type Scene, type SceneRing } from './scene.js';\n\nexport interface DisplayNode {\n id: string;\n node: OrbitNode;\n role: NodeRole;\n x: number;\n y: number;\n radius: number;\n opacity: number;\n\n /** Multiplies the label's own visibility rules (level of detail, role). */\n labelOpacity: number;\n\n color: string;\n depth: number;\n hiddenChildren: number;\n parentId?: string;\n hostId?: string;\n\n /** A planet of a crowded orbit, drawn flat (see `drawsFlat`). */\n crowded?: boolean;\n\n /** During a flight, how the node comes or goes with its siblings (see `Cluster`). */\n cluster?: Cluster;\n\n /** A body that turns with its orbit: where it is in the unturned orbit (see `OrbitTurn`). */\n unturned?: Point;\n}\n\n/**\n * A focused orbit at rest, turned `rotation` degrees about its sun at\n * (`cx`, `cy`). Each body that turns with it (those with `unturned`) is drawn\n * where it is in the unturned orbit, in a group that turns, so spinning the\n * orbit moves the group instead of every body in it.\n */\nexport interface OrbitTurn {\n cx: number;\n cy: number;\n rotation: number;\n}\n\ninterface Point {\n readonly x: number;\n readonly y: number;\n}\n\n/**\n * During a flight, nodes that come or go together: the children of one\n * parent growing out of it, shrinking into it, or fading where they are.\n * Each is drawn at its own `x`, `y`, `radius` and `nodeOpacity`, which hold\n * still, scaled by `scale` about the pivot with `opacity` on top, which are\n * the same for all of them, so a family can be moved as one.\n */\nexport interface Cluster {\n pivotX: number;\n pivotY: number;\n scale: number;\n opacity: number;\n x: number;\n y: number;\n radius: number;\n nodeOpacity: number;\n}\n\nexport interface DisplayRing {\n id: string;\n centerId: string;\n cx: number;\n cy: number;\n radius: number;\n color: string;\n gaps: SceneRing['gaps'];\n\n /** Degrees added to every gap angle (the orbit's spin). */\n rotation: number;\n\n opacity: number;\n}\n\nexport interface DisplayLink {\n id: string;\n fromId: string;\n toId: string;\n color: string;\n opacity: number;\n}\n\n/** The free place in the orbit for a new idea (see `SceneSlot`), where it is this frame. */\nexport interface DisplaySlot {\n parentId: string;\n index: number;\n x: number;\n y: number;\n radius: number;\n opacity: number;\n\n /** Where the slot is in the unturned orbit (see `OrbitTurn`). */\n unturned?: Point;\n}\n\nexport interface Display {\n nodes: Map<string, DisplayNode>;\n rings: DisplayRing[];\n links: DisplayLink[];\n camera: Camera;\n addSlot?: DisplaySlot;\n\n /** A focused orbit at rest. */\n turn?: OrbitTurn;\n}\n\n/** A scene at rest, with its orbit turned by `rotation` degrees. */\nexport const sceneDisplay = (scene: Scene, rotation: number, camera: Camera): Display => {\n const nodes = new Map<string, DisplayNode>();\n const sun = scene.nodes.get(scene.focusId);\n const centerX = sun?.x ?? 0;\n const centerY = sun?.y ?? 0;\n\n for (const node of scene.nodes.values()) {\n let x = node.x;\n let y = node.y;\n let unturned: Point | undefined;\n\n if (node.spins && node.role === 'planet' && node.orbitAngle !== undefined && node.orbitRadius !== undefined) {\n const angle = toRadians(node.orbitAngle + rotation);\n x = centerX + node.orbitRadius * Math.cos(angle);\n y = centerY + node.orbitRadius * Math.sin(angle);\n unturned = node;\n }\n\n nodes.set(node.id, {\n id: node.id,\n node: node.node,\n role: node.role,\n x,\n y,\n radius: node.radius,\n opacity: 1,\n labelOpacity: 1,\n color: node.color,\n depth: node.depth,\n hiddenChildren: node.hiddenChildren,\n parentId: node.parentId,\n hostId: node.hostId,\n crowded: node.crowded,\n unturned,\n });\n }\n\n // Moons follow their planet around the sun.\n for (const node of scene.nodes.values()) {\n if (node.role !== 'moon' || !node.hostId) {\n continue;\n }\n\n const host = scene.nodes.get(node.hostId);\n const hostDisplay = nodes.get(node.hostId);\n const moon = nodes.get(node.id);\n\n if (!host || !hostDisplay || !moon || host.orbitAngle === undefined) {\n continue;\n }\n\n const angle = toRadians(host.orbitAngle + rotation + (node.hostOffset ?? 0));\n moon.x = hostDisplay.x + (node.hostDistance ?? 0) * Math.cos(angle);\n moon.y = hostDisplay.y + (node.hostDistance ?? 0) * Math.sin(angle);\n moon.unturned = hostDisplay.unturned && node;\n }\n\n let addSlot: DisplaySlot | undefined;\n\n if (scene.addSlot) {\n const { parentId, index, orbitAngle, orbitRadius, radius } = scene.addSlot;\n const angle = toRadians(orbitAngle + rotation);\n addSlot = { parentId, index, x: centerX + orbitRadius * Math.cos(angle), y: centerY + orbitRadius * Math.sin(angle), radius, opacity: 1, unturned: scene.addSlot };\n }\n\n return {\n nodes,\n rings: scene.rings.map((ring) => ({ ...ring, rotation: ring.spins ? rotation : 0, opacity: 1 })),\n links: scene.links.map((link) => ({ ...link, opacity: 1 })),\n camera,\n addSlot,\n turn: scene.kind === 'focus' ? { cx: centerX, cy: centerY, rotation } : undefined,\n };\n};\n\nexport interface Transition {\n /** The display when the flight started, in the current world. */\n from: Display;\n\n /** Fade out and in without moving anything, for readers who prefer reduced motion. */\n fade?: boolean;\n\n /** The destination scene in its own coordinates. */\n target: Scene;\n\n /** Places `target` in the current world. */\n placement: Similarity;\n\n cameraPath: CameraPath;\n startedAt: number;\n duration: number;\n}\n\n/** The camera that frames `scene` once it is placed by `placement`. */\nexport const placedFrame = (scene: Scene, placement: Similarity): Camera => {\n return transformCamera(placement, scene.frame);\n};\n\n/**\n * The display `progress` (0–1, already eased) of the way through a flight.\n * Nodes in both views travel; new nodes grow out of their parent (or fade\n * in where they will be); nodes that leave shrink into their parent in the\n * new view (or fade where they are, as the camera passes them).\n */\n/** A flight's destination at rest, placed in today's world: the same on every frame of the flight. */\ninterface PlacedTarget {\n resting: Display;\n nodes: Map<string, DisplayNode>;\n}\n\nconst placedTargets = new WeakMap<Transition, PlacedTarget>();\n\nconst placedTarget = (transition: Transition): PlacedTarget => {\n const cached = placedTargets.get(transition);\n\n if (cached) {\n return cached;\n }\n\n const { target, placement } = transition;\n const resting = sceneDisplay(target, 0, target.frame);\n const nodes = new Map<string, DisplayNode>();\n\n for (const node of resting.nodes.values()) {\n const point = applySimilarity(placement, node);\n nodes.set(node.id, { ...node, x: point.x, y: point.y, radius: node.radius * placement.scale });\n }\n\n const placed = { resting, nodes };\n placedTargets.set(transition, placed);\n return placed;\n};\n\nexport const transitionDisplay = (transition: Transition, progress: number): Display => {\n const { from, target, placement } = transition;\n const { resting: restingTarget, nodes: destination } = placedTarget(transition);\n\n const nodes = new Map<string, DisplayNode>();\n const enterProgress = within(progress, 0.25, 1);\n const exitProgress = within(progress, 0, 0.6);\n\n for (const [id, end] of destination) {\n const start = from.nodes.get(id);\n\n if (start) {\n nodes.set(id, {\n ...end,\n role: progress < 0.5 ? start.role : end.role,\n x: interpolate(start.x, end.x, progress),\n y: interpolate(start.y, end.y, progress),\n radius: interpolate(start.radius, end.radius, progress),\n opacity: interpolate(start.opacity, 1, progress),\n labelOpacity: interpolate(start.labelOpacity, 1, progress),\n });\n continue;\n }\n\n const origin = (end.parentId && from.nodes.get(end.parentId)) || undefined;\n\n if (origin) {\n const opacity = within(progress, 0.25, 0.6);\n nodes.set(id, {\n ...end,\n x: interpolate(origin.x, end.x, enterProgress),\n y: interpolate(origin.y, end.y, enterProgress),\n radius: end.radius * enterProgress,\n opacity,\n labelOpacity: within(progress, 0.6, 1),\n cluster: { pivotX: origin.x, pivotY: origin.y, scale: enterProgress, opacity, x: end.x, y: end.y, radius: end.radius, nodeOpacity: 1 },\n });\n } else {\n nodes.set(id, {\n ...end,\n opacity: enterProgress,\n labelOpacity: within(progress, 0.6, 1),\n cluster: { pivotX: 0, pivotY: 0, scale: 1, opacity: enterProgress, x: end.x, y: end.y, radius: end.radius, nodeOpacity: 1 },\n });\n }\n }\n\n for (const [id, start] of from.nodes) {\n if (destination.has(id)) {\n continue;\n }\n\n const into = (start.parentId && destination.get(start.parentId)) || undefined;\n const remaining = 1 - exitProgress;\n\n if (into) {\n nodes.set(id, {\n ...start,\n x: interpolate(start.x, into.x, exitProgress),\n y: interpolate(start.y, into.y, exitProgress),\n radius: start.radius * remaining,\n opacity: start.opacity * remaining,\n labelOpacity: start.labelOpacity * (1 - within(progress, 0, 0.35)),\n cluster: { pivotX: into.x, pivotY: into.y, scale: remaining, opacity: remaining, x: start.x, y: start.y, radius: start.radius, nodeOpacity: start.opacity },\n });\n } else {\n nodes.set(id, {\n ...start,\n opacity: start.opacity * remaining,\n labelOpacity: start.labelOpacity * (1 - within(progress, 0, 0.35)),\n cluster: { pivotX: 0, pivotY: 0, scale: 1, opacity: remaining, x: start.x, y: start.y, radius: start.radius, nodeOpacity: start.opacity },\n });\n }\n }\n\n const rings: DisplayRing[] = [];\n\n for (const ring of from.rings) {\n rings.push({ ...ring, opacity: ring.opacity * (1 - within(progress, 0, 0.5)) });\n }\n\n for (const ring of restingTarget.rings) {\n const center = applySimilarity(placement, { x: ring.cx, y: ring.cy });\n const finalRadius = ring.radius * placement.scale;\n const startCenter = from.nodes.get(ring.centerId);\n const startRadius = startCenter ? Math.min(finalRadius, startCenter.radius * 1.6) : finalRadius * 0.6;\n const ringProgress = within(progress, 0.2, 1);\n rings.push({\n ...ring,\n id: `${ring.id}@target`,\n cx: center.x,\n cy: center.y,\n radius: interpolate(startRadius, finalRadius, ringProgress),\n opacity: within(progress, 0.3, 1),\n });\n }\n\n const targetLinks = new Set(target.links.map((link) => link.id));\n const links: DisplayLink[] = from.links\n .filter((link) => !targetLinks.has(link.id))\n .map((link) => ({ ...link, opacity: link.opacity * (1 - within(progress, 0, 0.5)) }));\n const sharedLinks = new Set(from.links.map((link) => link.id));\n\n for (const link of target.links) {\n links.push({ ...link, opacity: sharedLinks.has(link.id) ? 1 : within(progress, 0.4, 1) });\n }\n\n return {\n nodes,\n rings,\n links,\n camera: transition.cameraPath.at(progress),\n addSlot: transitionSlot(from.addSlot, restingTarget.addSlot && placeSlot(restingTarget.addSlot, placement), progress),\n };\n};\n\nconst placeSlot = (slot: DisplaySlot, placement: Similarity): DisplaySlot => {\n const point = applySimilarity(placement, slot);\n return { ...slot, x: point.x, y: point.y, radius: slot.radius * placement.scale };\n};\n\n/**\n * The slot for a new idea during a flight: it slides to its next place in\n * the same orbit (after an idea joins it, say); otherwise the old one fades\n * as the flight starts and the new one appears as it lands.\n */\nconst transitionSlot = (start: DisplaySlot | undefined, end: DisplaySlot | undefined, progress: number): DisplaySlot | undefined => {\n if (start && end && start.parentId === end.parentId) {\n return {\n ...end,\n x: interpolate(start.x, end.x, progress),\n y: interpolate(start.y, end.y, progress),\n radius: interpolate(start.radius, end.radius, progress),\n opacity: interpolate(start.opacity, 1, progress),\n };\n }\n\n if (end && progress >= 0.5) {\n return { ...end, opacity: within(progress, 0.7, 1) };\n }\n\n return start && { ...start, opacity: start.opacity * (1 - within(progress, 0, 0.3)) };\n};\n\n/**\n * A view change without movement: the old view fades out, then the new one\n * fades in already in place (in its own coordinates, with its own camera).\n */\nexport const fadeDisplay = (transition: Transition, progress: number): Display => {\n if (progress < 0.5) {\n const visible = 1 - progress * 2;\n const nodes = new Map<string, DisplayNode>();\n\n for (const [id, node] of transition.from.nodes) {\n nodes.set(id, { ...node, opacity: node.opacity * visible, labelOpacity: node.labelOpacity * visible });\n }\n\n const slot = transition.from.addSlot;\n return {\n nodes,\n rings: transition.from.rings.map((ring) => ({ ...ring, opacity: ring.opacity * visible })),\n links: transition.from.links.map((link) => ({ ...link, opacity: link.opacity * visible })),\n camera: transition.from.camera,\n addSlot: slot && { ...slot, opacity: slot.opacity * visible },\n };\n }\n\n const visible = (progress - 0.5) * 2;\n const resting = sceneDisplay(transition.target, 0, transition.target.frame);\n\n for (const node of resting.nodes.values()) {\n node.opacity = visible;\n node.labelOpacity = visible;\n }\n\n return {\n ...resting,\n rings: resting.rings.map((ring) => ({ ...ring, opacity: visible })),\n links: resting.links.map((link) => ({ ...link, opacity: visible })),\n addSlot: resting.addSlot && { ...resting.addSlot, opacity: visible },\n };\n};\n",
|
|
45
|
+
"/**\n * Text broken into pieces and wrapped, for labels in exported SVGs and for\n * planning where labels go. Without a font to measure with, widths are\n * estimates from the kind of each character: CJK, kana, Hangul and emoji\n * are about as wide as the font is tall, and other letters a little over\n * half that.\n */\n\nimport type { TextMeasure } from './engine/text-measure.js';\n\nexport interface TextLayout {\n lines: string[];\n truncated: boolean;\n lineHeight: number;\n totalHeight: number;\n}\n\n/** Average width of a narrow character, in ems. */\nexport const NARROW_EMS = 0.55;\n\n/**\n * Characters about as wide as the font is tall: Hangul jamo, CJK (radicals\n * and punctuation through ideographs, kana, bopomofo and Yi), Hangul\n * syllables, CJK compatibility and full-width forms, the ideographs past\n * U+20000, and emoji.\n */\nexport const WIDE_CHARACTER = /[\\u1100-\\u115F\\u2E80-\\uA4CF\\uA960-\\uA97F\\uAC00-\\uD7A3\\uF900-\\uFAFF\\uFE30-\\uFE4F\\uFF00-\\uFF60\\uFFE0-\\uFFE6\\u{20000}-\\u{3FFFD}]|\\p{Extended_Pictographic}/u;\n\n/** Scripts written without spaces, which may break between any two of their characters. */\nconst BREAKS_ANYWHERE = /[⺀-〾ぁ-㏿㐀-䶿一-鿿가-힣豈--⦆\\u{20000}-\\u{3FFFD}]/u;\n\n/**\n * Text in Latin-1 and plain spaces only: one character is one grapheme, none\n * of them wide or breaking anywhere. Most names are, and they skip the\n * segmenter, which is slow to call for each of a big map's names.\n */\nconst PLAIN = /^[\\x20-\\x7e\\xa0-\\xff\\u2000-\\u200a]*$/;\n\nlet segmenter: Intl.Segmenter | null | undefined;\n\n/** The characters of `text` as people see them, so an emoji with its modifiers stays whole. */\nexport const graphemes = (text: string): string[] => {\n if (PLAIN.test(text)) {\n return text.split('');\n }\n\n if (segmenter === undefined) {\n segmenter = typeof Intl !== 'undefined' && 'Segmenter' in Intl ? new Intl.Segmenter(undefined, { granularity: 'grapheme' }) : null;\n }\n\n return segmenter ? Array.from(segmenter.segment(text), (part) => part.segment) : Array.from(text);\n};\n\n/** How many narrow and wide characters `text` has. */\nexport const characterWidths = (text: string): { narrow: number; wide: number } => {\n if (PLAIN.test(text)) {\n return { narrow: text.length, wide: 0 };\n }\n\n let wide = 0;\n const all = graphemes(text);\n\n for (const character of all) {\n if (WIDE_CHARACTER.test(character)) {\n wide += 1;\n }\n }\n\n return { narrow: all.length - wide, wide };\n};\n\n/** Estimated width of `text`, in ems. */\nexport const textEms = (text: string): number => {\n const { narrow, wide } = characterWidths(text);\n return narrow * NARROW_EMS + wide;\n};\n\nconst estimatedEms = textEms;\n\n/** A piece of text that stays on one line, and whether a space comes before it. */\nexport interface TextUnit {\n text: string;\n spaced: boolean;\n}\n\n/** Spaces a line may break at: every kind but the no-break ones, which keep their neighbors together. */\nexport const BREAKING_SPACE = /[^\\S\\u00a0\\u202f\\ufeff]+/u;\n\n/**\n * Where a word may break besides between CJK characters: after an\n * underscore, slash or hyphen, after a dot or colon a letter follows, and\n * between a lowercase and an uppercase letter. Identifiers such as\n * `contact_tec_mail_address_key`, `docs/format.md` or `startedAt` then wrap\n * where they read, instead of being cut short.\n */\nconst WORD_BREAK = /(?<=[_/\\\\-])(?=.)|(?<=[.:])(?=\\p{L})|(?<=\\p{Ll})(?=\\p{Lu})/u;\n\n/** A word cut where it may break onto another line. */\nexport const wordPieces = (word: string): string[] => {\n return word.split(WORD_BREAK).filter(Boolean);\n};\n\n/**\n * Where text may break: between words, inside long words where they read\n * (`wordPieces`), and between the characters of scripts written without spaces.\n */\nexport const breakUnits = (text: string): TextUnit[] => {\n const units: TextUnit[] = [];\n\n for (const [index, word] of text.split(BREAKING_SPACE).filter(Boolean).entries()) {\n let run = '';\n let first = true;\n\n const push = (piece: string) => {\n units.push({ text: piece, spaced: first && index > 0 });\n first = false;\n };\n\n for (const piece of wordPieces(word)) {\n if (PLAIN.test(piece)) {\n push(piece);\n continue;\n }\n\n for (const character of graphemes(piece)) {\n if (BREAKS_ANYWHERE.test(character)) {\n if (run) {\n push(run);\n run = '';\n }\n\n push(character);\n } else {\n run += character;\n }\n }\n\n if (run) {\n push(run);\n run = '';\n }\n }\n }\n\n return units;\n};\n\n/** Joins units back into text, with their spaces. */\nexport const joinUnits = (units: TextUnit[]): string => {\n return units.map((unit, index) => (index > 0 && unit.spaced ? ` ${unit.text}` : unit.text)).join('');\n};\n\n/** As much of `text` as fits in `maxEms` with an ellipsis after it, cut between characters. */\nconst truncate = (text: string, maxEms: number, ems: (value: string) => number): string => {\n let kept = '';\n\n for (const character of graphemes(text)) {\n if (ems(`${kept}${character}…`) > maxEms) {\n break;\n }\n\n kept += character;\n }\n\n return `${kept.trimEnd()}…`;\n};\n\n/**\n * Wraps text into at most `maxLines` lines of `maxWidth` pixels, ending with\n * an ellipsis when cut. Widths are estimates, unless `measure` measures them\n * in the font the text is drawn with.\n */\nexport const wrapText = (\n text: string,\n maxWidth: number,\n fontSize: number,\n maxLines = 3,\n measure?: Pick<TextMeasure, 'ems'>,\n): TextLayout => {\n const textEms = measure ? (value: string) => measure.ems(value, fontSize) : estimatedEms;\n // Room for at least three narrow characters, however small the space.\n const maxEms = Math.max(3 * NARROW_EMS, maxWidth / fontSize);\n const lineHeight = fontSize * 1.3;\n\n const lines: string[] = [];\n let current: TextUnit[] = [];\n\n for (const unit of breakUnits(text)) {\n const candidate = joinUnits([...current, unit]);\n\n if (current.length === 0 || textEms(candidate) <= maxEms) {\n current.push(unit);\n\n if (current.length === 1 && textEms(unit.text) > maxEms) {\n lines.push(truncate(unit.text, maxEms, textEms));\n current = [];\n }\n\n continue;\n }\n\n lines.push(joinUnits(current));\n current = [{ ...unit, spaced: false }];\n\n if (textEms(unit.text) > maxEms) {\n lines.push(truncate(unit.text, maxEms, textEms));\n current = [];\n }\n }\n\n if (current.length > 0) {\n lines.push(joinUnits(current));\n }\n\n const truncated = lines.length > maxLines;\n const resultLines = lines.slice(0, maxLines);\n\n if (truncated && resultLines.length === maxLines) {\n const last = resultLines[maxLines - 1];\n\n if (!last.endsWith('…')) {\n resultLines[maxLines - 1] = textEms(`${last}…`) <= maxEms ? `${last}…` : truncate(last, maxEms, textEms);\n }\n }\n\n return {\n lines: resultLines,\n truncated,\n lineHeight,\n totalHeight: resultLines.length * lineHeight,\n };\n};\n",
|
|
46
|
+
"/**\n * How wide label text is, in ems of the font it's drawn with. In a browser,\n * names are measured with the fonts the page gives the map's labels (each\n * theme's, a node type's own, a page's brand font), so a name fills its\n * node as far as it really reaches and never spills out of it. Where there's\n * no canvas to measure with (a server, tests), widths are estimated from the\n * kind of each character.\n */\n\nimport type { OrbitNode } from '../types.js';\nimport type { MapExtensions } from '../extensions.js';\nimport type { OrbitThemeToken } from '../themes.js';\nimport type { NodeRole } from './scene.js';\nimport { WIDE_CHARACTER, characterWidths, graphemes } from '../text-layout.js';\n\n/** Text widths in one font. */\nexport interface TextMeasure {\n /** Equal keys measure alike: caches of fitted labels are kept by it. */\n readonly key: string;\n\n /** Whether widths in ems differ by font size (fonts with optical sizes); estimates don't. */\n readonly bySize: boolean;\n\n /** The width of `text` on one line at `fontSize` px, in ems. */\n ems(text: string, fontSize: number): number;\n\n /** The space between two words, in ems. */\n space(fontSize: number): number;\n\n /** The ellipsis a cut name ends with, in ems. */\n ellipsis(fontSize: number): number;\n\n /** How wide the font draws, as `font-stretch` (a percentage of its normal width). */\n readonly stretch: number;\n\n /**\n * The same font drawn narrower, for names that don't fit at its width,\n * or null when it has no narrower width (most fonts don't: only those\n * with a width axis or condensed faces do).\n */\n narrower(): TextMeasure | null;\n}\n\n/** The measures a map's labels are fitted with: names inside nodes, pills beside them, and the \"+N\" names keep clear of. */\nexport interface LabelMeasures {\n /** Equal keys measure alike. */\n readonly key: string;\n\n /** For a node's name inside it. */\n inside(role: NodeRole, node?: OrbitNode): TextMeasure;\n\n /** For a node's name on its pill. */\n pill(role: NodeRole, node?: OrbitNode): TextMeasure;\n\n /** For the \"+N\" a node shows for children that aren't drawn. */\n count(): TextMeasure;\n}\n\n/** Widths estimated from the kind of each character: wide ones (CJK, emoji) take an em, the rest `narrow`. */\nclass EstimatedMeasure implements TextMeasure {\n readonly key: string;\n readonly bySize = false;\n readonly stretch = 100;\n private readonly narrow: number;\n private readonly spaceWidth: number;\n private readonly ellipsisWidth: number;\n\n constructor(narrow: number, spaceWidth: number, ellipsisWidth: number) {\n this.narrow = narrow;\n this.spaceWidth = spaceWidth;\n this.ellipsisWidth = ellipsisWidth;\n this.key = `estimate ${narrow}`;\n }\n\n ems(text: string): number {\n // One character at a time, when a cut name is filled to its ellipsis.\n if (text.length === 1) {\n return WIDE_CHARACTER.test(text) ? 1 : this.narrow;\n }\n\n const { narrow, wide } = characterWidths(text);\n return narrow * this.narrow + wide;\n }\n\n space(): number {\n return this.spaceWidth;\n }\n\n ellipsis(): number {\n return this.ellipsisWidth;\n }\n\n narrower(): TextMeasure | null {\n return null;\n }\n}\n\n/** A name inside its node: semibold UI fonts average a little under 0.58 em a character. */\nexport const INSIDE_ESTIMATE: TextMeasure = new EstimatedMeasure(0.58, 0.3, 0.8);\n/** A name on a pill: 6.4 px a character in its 11.5 px text. */\nexport const PILL_ESTIMATE: TextMeasure = new EstimatedMeasure(6.4 / 11.5, 0.3, 0.8);\n/** A \"+N\": its plus sign and figures, in semibold text, take a little over two thirds of an em each. */\nexport const COUNT_ESTIMATE: TextMeasure = new EstimatedMeasure(0.7, 0.3, 0.8);\n\n/** Estimates for every label, where nothing can be measured. */\nexport const ESTIMATED_LABELS: LabelMeasures = {\n key: 'estimate',\n inside: () => INSIDE_ESTIMATE,\n pill: () => PILL_ESTIMATE,\n count: () => COUNT_ESTIMATE,\n};\n\ntype MeasuringContext = CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n\n/**\n * The two sizes text is measured at. Labels are drawn between them, and\n * fonts with optical sizes draw small text wider: widths at the sizes in\n * between are interpolated.\n */\nconst SMALL_SIZE = 9;\nconst LARGE_SIZE = 16;\n\n/** What a label's font is, as the page computes it. */\nexport interface LabelFont {\n family: string;\n weight: string;\n style: string;\n\n /** `font-stretch`, as a percentage of the normal width. */\n stretch: number;\n\n /** Space after each character, in ems. */\n letterSpacing: number;\n}\n\n/** The canvas keyword for a width, as `font-stretch` percentages map to them. */\nconst stretchKeyword = (stretch: number): string => {\n const keywords: [number, string][] = [\n [50, 'ultra-condensed'], [62.5, 'extra-condensed'], [75, 'condensed'], [87.5, 'semi-condensed'], [100, 'normal'],\n [112.5, 'semi-expanded'], [125, 'expanded'], [150, 'extra-expanded'], [200, 'ultra-expanded'],\n ];\n let nearest = keywords[4];\n\n for (const keyword of keywords) {\n if (Math.abs(keyword[0] - stretch) < Math.abs(nearest[0] - stretch)) {\n nearest = keyword;\n }\n }\n\n return nearest[1];\n};\n\n/** The widths a name tries, narrowest last, when it doesn't fit at its font's own: semi-condensed, then condensed. */\nconst NARROWER_WIDTHS = [87.5, 75];\n/** A narrower width counts only if it draws text at least this much narrower. */\nconst NOTICEABLY_NARROWER = 0.97;\n\n/**\n * Text in scripts that draw each letter on its own (Latin, Greek, Cyrillic,\n * with digits, punctuation and spaces): its width is the sum of its\n * letters', give or take kerning, which only ever makes a word narrower.\n * Measuring letters instead of words takes a canvas call per letter of the\n * alphabet, not per name: a big map brings hundreds of new names into view\n * at a time.\n */\nconst LETTER_BY_LETTER = /^[\\u0020-\\u052F\\u1E00-\\u1FFF\\u2000-\\u206F\\u20A0-\\u20BF]*$/;\n\n/** Text measured in a font with a canvas, at two sizes, interpolated between them. */\nclass CanvasMeasure implements TextMeasure {\n readonly key: string;\n readonly bySize = true;\n private readonly context: MeasuringContext;\n private readonly font: LabelFont;\n private readonly widths = new Map<string, [number, number]>();\n private readonly letters = new Map<string, [number, number]>();\n private narrowerMeasure: TextMeasure | null | undefined;\n\n constructor(context: MeasuringContext, font: LabelFont, key: string) {\n this.context = context;\n this.font = font;\n this.key = key;\n }\n\n ems(text: string, fontSize: number): number {\n let widths = this.widths.get(text);\n\n if (!widths) {\n widths = LETTER_BY_LETTER.test(text) ? this.sumOfLetters(text) : [this.measure(text, SMALL_SIZE), this.measure(text, LARGE_SIZE)];\n\n if (this.widths.size >= MEASURED_TEXTS_LIMIT) {\n this.widths.clear();\n }\n\n this.widths.set(text, widths);\n }\n\n const share = Math.min(1, Math.max(0, (fontSize - SMALL_SIZE) / (LARGE_SIZE - SMALL_SIZE)));\n return widths[0] + (widths[1] - widths[0]) * share;\n }\n\n space(fontSize: number): number {\n return this.ems(' ', fontSize);\n }\n\n ellipsis(fontSize: number): number {\n return this.ems('…', fontSize);\n }\n\n get stretch(): number {\n return this.font.stretch;\n }\n\n narrower(): TextMeasure | null {\n if (this.narrowerMeasure !== undefined) {\n return this.narrowerMeasure;\n }\n\n this.narrowerMeasure = null;\n const stretch = NARROWER_WIDTHS.find((width) => width < this.font.stretch);\n\n if (stretch !== undefined && 'fontStretch' in this.context) {\n const narrower = measureFor({ ...this.font, stretch });\n const sample = 'Orbit names';\n\n if (narrower && narrower.ems(sample, 13) < this.ems(sample, 13) * NOTICEABLY_NARROWER) {\n this.narrowerMeasure = narrower;\n }\n }\n\n return this.narrowerMeasure;\n }\n\n private sumOfLetters(text: string): [number, number] {\n let small = 0;\n let large = 0;\n\n for (const letter of text) {\n let widths = this.letters.get(letter);\n\n if (!widths) {\n widths = [this.measure(letter, SMALL_SIZE), this.measure(letter, LARGE_SIZE)];\n this.letters.set(letter, widths);\n }\n\n small += widths[0];\n large += widths[1];\n }\n\n return [small, large];\n }\n\n private measure(text: string, size: number): number {\n const { context, font } = this;\n context.font = `${font.style} ${font.weight} ${size}px ${font.family}`;\n\n if ('fontStretch' in context) {\n context.fontStretch = stretchKeyword(font.stretch) as CanvasFontStretch;\n }\n\n const spacing = font.letterSpacing === 0 ? 0 : font.letterSpacing * graphemes(text).length;\n return context.measureText(text).width / size + spacing;\n }\n}\n\n/** More texts than the largest maps have; past it, a font's measurements start over. */\nconst MEASURED_TEXTS_LIMIT = 50000;\n\nlet sharedContext: MeasuringContext | null | undefined;\n\n/** A canvas to measure with, or null where there's none that measures (a server, a DOM without canvas). */\nconst measuringContext = (): MeasuringContext | null => {\n if (sharedContext !== undefined) {\n return sharedContext;\n }\n\n sharedContext = null;\n\n try {\n let context: MeasuringContext | null = null;\n\n if (typeof OffscreenCanvas === 'function') {\n context = new OffscreenCanvas(1, 1).getContext('2d');\n }\n\n if (!context && typeof document !== 'undefined' && typeof document.createElement === 'function') {\n context = document.createElement('canvas').getContext('2d');\n }\n\n // A stand-in canvas (some test DOMs have one) measures nothing: estimates are better than zeros.\n if (context && typeof context.measureText === 'function') {\n context.font = '16px sans-serif';\n\n if (context.measureText('Orbit').width > 0) {\n sharedContext = context;\n }\n }\n } catch {\n sharedContext = null;\n }\n\n if (sharedContext) {\n watchFontLoads();\n }\n\n return sharedContext;\n};\n\n/** Measures by font, shared by every map that draws with the same one. */\nconst canvasMeasures = new Map<string, CanvasMeasure>();\n/** Names the measures: their keys go into the cache key of every label fitted each frame, so they're short. */\nlet measureCount = 0;\n\n/** The measure for a font, or null when nothing can measure it. */\nexport const measureFor = (font: LabelFont): TextMeasure | null => {\n const context = measuringContext();\n\n if (!context || !font.family) {\n return null;\n }\n\n const spec = `${font.style} ${font.weight} ${font.stretch}% ${font.letterSpacing} ${font.family}`;\n let measure = canvasMeasures.get(spec);\n\n if (!measure) {\n measureCount += 1;\n measure = new CanvasMeasure(context, font, `font ${measureCount}`);\n canvasMeasures.set(spec, measure);\n }\n\n return measure;\n};\n\nconst resetListeners = new Set<() => void>();\n\n/**\n * Calls `listener` whenever measurements start over: a font finished loading,\n * so text measured while the page drew it with a fallback measures anew.\n * Returns a function that stops listening.\n */\nexport const onMeasurementsReset = (listener: () => void): () => void => {\n resetListeners.add(listener);\n\n return () => {\n resetListeners.delete(listener);\n };\n};\n\n/** Forgets every measurement, and tells whoever keeps fits made from them. */\nexport const resetMeasurements = (): void => {\n canvasMeasures.clear();\n\n for (const listener of Array.from(resetListeners)) {\n listener();\n }\n};\n\nlet watchingFonts = false;\n\n/** Measures again when the page's fonts finish loading: until then a name may have been measured in a fallback font. */\nconst watchFontLoads = (): void => {\n if (watchingFonts || typeof document === 'undefined') {\n return;\n }\n\n const fonts = (document as Document & { fonts?: FontFaceSet }).fonts;\n\n if (!fonts || typeof fonts.addEventListener !== 'function') {\n return;\n }\n\n watchingFonts = true;\n fonts.addEventListener('loadingdone', () => resetMeasurements());\n};\n\n/** Font properties that set how wide text is, among a node type's tokens. */\nconst FONT_TOKENS: OrbitThemeToken[] = ['font-family', 'label-font', 'display-font', 'label-weight', 'display-weight', 'label-letter-spacing'];\n\n/**\n * The fonts a map's labels are drawn with, read from the page: a hidden\n * label of each kind in the map's label layer, so the theme, the page's\n * own CSS and a node type's tokens all count. Read again when `refresh` is\n * called (the theme or the page may have changed), not on every frame.\n */\nexport class LabelFonts implements LabelMeasures {\n private readonly layer: HTMLElement;\n private readonly extensions: () => MapExtensions | undefined;\n\n /** A hidden box in the label layer holding a label of each kind, to read its font from. */\n private shelf: HTMLElement | null = null;\n\n private probes = new Map<string, HTMLElement>();\n\n /** By kind of label (and node type with a font of its own); null where nothing measures. */\n private measures = new Map<string, TextMeasure | null>();\n\n /** The sun's and other nodes' measures, for nodes without a type: looked up for every label on every frame. */\n private sunMeasure: TextMeasure | null | undefined;\n\n private nameMeasure: TextMeasure | null | undefined;\n\n /** The \"+N\"'s measure: looked up for every label on every frame. */\n private countMeasure: TextMeasure | null | undefined;\n\n private stale = true;\n private currentKey = 'estimate';\n\n /** A recheck waiting for the page to be idle (see `recheckWhenIdle`). */\n private recheck: { cancel: () => void } | null = null;\n\n constructor(layer: HTMLElement, extensions: () => MapExtensions | undefined) {\n this.layer = layer;\n this.extensions = extensions;\n }\n\n /** Equal keys measure alike: a change of font changes the key. */\n get key(): string {\n this.read();\n return this.currentKey;\n }\n\n /** The theme, the page or the fonts may have changed: read the fonts again before the next fit. */\n refresh(): void {\n this.stale = true;\n }\n\n inside(role: NodeRole, node?: OrbitNode): TextMeasure {\n return this.measure(role, node) ?? INSIDE_ESTIMATE;\n }\n\n pill(role: NodeRole, node?: OrbitNode): TextMeasure {\n return this.measure(role, node) ?? PILL_ESTIMATE;\n }\n\n count(): TextMeasure {\n if (this.stale) {\n this.read();\n }\n\n if (this.countMeasure === undefined) {\n const font = this.computedFont('count', 'orbit-count', undefined);\n this.countMeasure = font ? measureFor(font) : null;\n }\n\n return this.countMeasure ?? COUNT_ESTIMATE;\n }\n\n /**\n * Once the page is idle, reads the fonts again and calls `changed` if they\n * differ: a page may switch its fonts at any time (a class, a brand font).\n * Off the frames that draw, so reading doesn't make one late.\n */\n recheckWhenIdle(changed: () => void): void {\n if (this.recheck || measuringContext() === null) {\n return;\n }\n\n const run = () => {\n this.recheck = null;\n const before = this.key;\n this.refresh();\n\n if (this.key !== before) {\n changed();\n }\n };\n\n const idle = (globalThis as { requestIdleCallback?: (callback: () => void, options?: { timeout: number }) => number }).requestIdleCallback;\n\n if (typeof idle === 'function') {\n const handle = idle(run, { timeout: 2000 });\n this.recheck = { cancel: () => (globalThis as { cancelIdleCallback?: (handle: number) => void }).cancelIdleCallback?.(handle) };\n } else {\n const handle = setTimeout(run, 250);\n this.recheck = { cancel: () => clearTimeout(handle) };\n }\n }\n\n /** Takes the hidden labels out of the page. */\n destroy(): void {\n this.recheck?.cancel();\n this.recheck = null;\n this.shelf?.remove();\n this.shelf = null;\n this.probes.clear();\n this.measures.clear();\n }\n\n private read(): void {\n if (!this.stale) {\n return;\n }\n\n this.stale = false;\n this.measures.clear();\n this.sunMeasure = undefined;\n this.nameMeasure = undefined;\n this.countMeasure = undefined;\n const keys = [this.measure('planet'), this.measure('sun'), this.count()].map((measure) => measure?.key ?? 'estimate');\n this.currentKey = keys.join(' | ');\n }\n\n private measure(role: NodeRole, node?: OrbitNode): TextMeasure | null {\n if (this.stale) {\n this.read();\n }\n\n const type = node ? this.extensions()?.typeName(node) ?? node.type : undefined;\n\n if (!node || !type) {\n if (role === 'sun') {\n if (this.sunMeasure === undefined) {\n this.sunMeasure = this.measureOf('sun', role, undefined);\n }\n\n return this.sunMeasure;\n }\n\n if (this.nameMeasure === undefined) {\n this.nameMeasure = this.measureOf('name', role, undefined);\n }\n\n return this.nameMeasure;\n }\n\n // A node type may set its own font: measured on its own, or as untyped nodes are.\n const key = `${role === 'sun' ? 'sun' : 'name'} ${type.toLowerCase()}`;\n const known = this.measures.get(key);\n\n if (known !== undefined || this.measures.has(key)) {\n return known ?? null;\n }\n\n const tokens = this.extensions()?.nodeType(node)?.tokens;\n const ownFont = tokens !== undefined && FONT_TOKENS.some((token) => typeof tokens[token] === 'string' && tokens[token] !== '');\n const measure = ownFont ? this.measureOf(key, role, tokens) : this.measure(role);\n this.measures.set(key, measure);\n return measure;\n }\n\n private measureOf(key: string, role: NodeRole, tokens: Record<string, unknown> | undefined): TextMeasure | null {\n const font = this.computedFont(key, `orbit-label orbit-label--${role === 'sun' ? 'sun' : 'planet'}`, tokens);\n return font ? measureFor(font) : null;\n }\n\n /** The font of a hidden element of `className` (a label, or a \"+N\") in the label layer, with a node type's `tokens`. */\n private computedFont(key: string, className: string, tokens: Record<string, unknown> | undefined): LabelFont | null {\n if (typeof getComputedStyle !== 'function' || !this.layer.isConnected || measuringContext() === null) {\n return null;\n }\n\n let probe = this.probes.get(key);\n\n if (!probe) {\n const document = this.layer.ownerDocument;\n\n if (!this.shelf) {\n this.shelf = document.createElement('div');\n this.shelf.className = 'orbit__font-probes';\n this.shelf.style.display = 'none';\n this.shelf.setAttribute('aria-hidden', 'true');\n this.layer.appendChild(this.shelf);\n }\n\n probe = document.createElement('div');\n probe.className = className;\n\n for (const [token, value] of Object.entries(tokens ?? {})) {\n if (typeof value === 'string' && value !== '') {\n probe.style.setProperty(`--_orbit-${token}`, value);\n }\n }\n\n this.shelf.appendChild(probe);\n this.probes.set(key, probe);\n }\n\n const style = getComputedStyle(probe);\n const fontSize = Number.parseFloat(style.fontSize) || 13;\n const spacing = Number.parseFloat(style.letterSpacing);\n const stretch = Number.parseFloat(style.fontStretch);\n\n if (!style.fontFamily) {\n return null;\n }\n\n return {\n family: style.fontFamily,\n weight: style.fontWeight || '400',\n style: style.fontStyle || 'normal',\n stretch: Number.isFinite(stretch) ? stretch : 100,\n letterSpacing: Number.isFinite(spacing) ? spacing / fontSize : 0,\n };\n }\n}\n",
|
|
47
|
+
"/**\n * DOM views for the map content. Nodes are SVG groups drawn at unit radius\n * and positioned with a single `translate() scale()`, so moving or resizing\n * a node is one attribute write per frame; spinning an orbit turns the group\n * its bodies are in instead (see `OrbitTurn`). Labels are HTML in screen\n * space, so text never scales with the camera and keeps a readable size.\n */\n\nimport type { OrbitNode } from '../types.js';\nimport type { DisplayNode, DisplayRing, DisplaySlot } from './display.js';\nimport type { NodeRole } from './scene.js';\nimport { guardUrl, resolveUrl } from '../url-guard.js';\nimport { hasMediaSource, youtubeThumbnailUrl } from '../media.js';\nimport type { MapExtensions, OrbitNodeType } from '../extensions.js';\nimport { breakUnits, graphemes, wordPieces, type TextUnit } from '../text-layout.js';\nimport { COUNT_ESTIMATE, INSIDE_ESTIMATE, onMeasurementsReset, type TextMeasure } from './text-measure.js';\nimport { OrbitWords } from '../languages.js';\n\n\nexport const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n\nexport interface ViewIds {\n /** Unit-circle clip path shared by every node image. */\n clip: string;\n\n /** Sphere shading gradient. */\n shade: string;\n\n /**\n * The shading of specks: the same, turned back by the turn they're drawn in\n * once their orbit rests, so it comes from the top left (see `turnShading`).\n */\n speckShade: string;\n\n /** Blur for the shadow (or glow) of planets and moons. */\n shadow: string;\n\n /** A wider blur for the sun's. */\n sunShadow: string;\n}\n\nexport const svgElement = <Name extends keyof SVGElementTagNameMap>(name: Name, attributes: Record<string, string> = {}): SVGElementTagNameMap[Name] => {\n const element = document.createElementNS(SVG_NAMESPACE, name);\n\n for (const [key, value] of Object.entries(attributes)) {\n element.setAttribute(key, value);\n }\n\n return element;\n};\n\n/**\n * Where the sphere shading changes, from the lit side (top left) to the far\n * edge. The theme colors each stop (`node-highlight`, `node-terminator`,\n * `node-shading`); the stylesheet and the SVG export share these offsets.\n */\nexport const SHADE_STOPS = [\n { offset: 0, part: 'highlight' },\n { offset: 0.45, part: 'highlight-fade' },\n { offset: 0.55, part: 'terminator-start' },\n { offset: 0.78, part: 'terminator' },\n { offset: 1, part: 'shading' },\n] as const;\n\n/**\n * The circle the shading spreads over, in fractions of a node's box: its\n * center, then its radius. The default lights spheres from the top left; a\n * theme moves it with the `node-shade-circle` token, such as to the bottom\n * right so the far stops catch light along the top left rim, as glass does.\n */\nexport interface ShadeCircle {\n x: number;\n y: number;\n radius: number;\n}\n\nexport const DEFAULT_SHADE_CIRCLE: ShadeCircle = { x: 0.34, y: 0.3, radius: 0.78 };\n\n/** A `node-shade-circle` value (`0.34 0.3 0.78`) read, or the default when it isn't three numbers with a radius above 0. */\nexport const readShadeCircle = (value: string | undefined): ShadeCircle => {\n const numbers = (value ?? '').trim().split(/[\\s,]+/).map(Number);\n\n if (numbers.length !== 3 || !numbers.every(Number.isFinite) || numbers[2] <= 0) {\n return DEFAULT_SHADE_CIRCLE;\n }\n\n const [x, y, radius] = numbers;\n return { x, y, radius };\n};\n\n/** Moves the shading of every node (specks follow it) to the theme's circle. */\nexport const placeShading = (defs: SVGDefsElement, ids: ViewIds, circle: ShadeCircle): void => {\n const gradient = Array.from(defs.children).find((child) => child.id === ids.shade);\n gradient?.setAttribute('cx', String(circle.x));\n gradient?.setAttribute('cy', String(circle.y));\n gradient?.setAttribute('r', String(circle.radius));\n};\n\n/** Blur radius of a shadow, in node radii: planets and moons, then the sun. */\nexport const SHADOW_BLUR = { planet: 0.16, sun: 0.3 } as const;\n\n/** Shared definitions: the image clip, sphere shading and shadow blurs, with instance-scoped ids. */\nexport const createDefinitions = (ids: ViewIds): SVGDefsElement => {\n const defs = svgElement('defs');\n const clip = svgElement('clipPath', { id: ids.clip, clipPathUnits: 'userSpaceOnUse' });\n clip.appendChild(svgElement('circle', { r: '1' }));\n defs.appendChild(clip);\n\n const shade = svgElement('radialGradient', {\n id: ids.shade,\n cx: String(DEFAULT_SHADE_CIRCLE.x),\n cy: String(DEFAULT_SHADE_CIRCLE.y),\n r: String(DEFAULT_SHADE_CIRCLE.radius),\n });\n\n for (const stop of SHADE_STOPS) {\n shade.appendChild(svgElement('stop', { offset: String(stop.offset), class: `orbit-shade__${stop.part}` }));\n }\n\n defs.appendChild(shade);\n defs.appendChild(svgElement('radialGradient', { id: ids.speckShade, href: `#${ids.shade}` }));\n\n for (const [id, blur] of [[ids.shadow, SHADOW_BLUR.planet], [ids.sunShadow, SHADOW_BLUR.sun]] as const) {\n const filter = svgElement('filter', { id, x: '-60%', y: '-60%', width: '220%', height: '220%' });\n filter.appendChild(svgElement('feGaussianBlur', { stdDeviation: String(blur) }));\n defs.appendChild(filter);\n }\n\n return defs;\n};\n\n/**\n * Turns the shading of specks back by `turn` degrees, the turn they're drawn\n * in, so their light comes from the top left. One write for every speck, but\n * the browser draws each of them again: not on every frame of a spin.\n */\nexport const turnShading = (defs: SVGDefsElement, ids: ViewIds, turn: number): void => {\n const gradient = Array.from(defs.children).find((child) => child.id === ids.speckShade);\n\n if (turn === 0) {\n gradient?.removeAttribute('gradientTransform');\n } else {\n gradient?.setAttribute('gradientTransform', `rotate(${-turn} 0.5 0.5)`);\n }\n};\n\nconst ENGLISH = new OrbitWords('en');\n\n/** Labels and the assistive name of a node, in the map's language (English without one). */\nexport const describeNode = (\n node: OrbitNode,\n hiddenChildren: number,\n visibleChildren: number,\n extensions?: MapExtensions,\n words: OrbitWords = ENGLISH,\n): string => {\n const type = extensions?.nodeType(node);\n const parts = [[extensions ? extensions.icon(node) : node.icon, node.text || words.text('untitled')].filter(Boolean).join(' ')];\n\n if (type?.label) {\n parts.push(type.label);\n }\n\n if (node.status) {\n parts.push(words.text('status', { status: node.status }));\n }\n\n const total = visibleChildren + hiddenChildren;\n\n if (total > 0) {\n parts.push(words.count('ideaCount', total));\n }\n\n const content = [\n type?.details ? words.text('hasDetails') : '',\n node.note ? words.text('hasNote') : '',\n hasMediaSource(node.image) ? words.text('hasImage') : '',\n hasMediaSource(node.video) ? words.text('hasVideo') : '',\n hasMediaSource(node.embed) ? words.text('hasEmbed') : '',\n node.link ? words.text('hasLink') : '',\n ].filter(Boolean);\n\n if (content.length > 0) {\n parts.push(words.text('has', { list: words.list(content) }));\n }\n\n return parts.join(', ');\n};\n\n/** Bodies smaller than this on screen (px) are drawn flat: there a shadow is a smudge. */\nconst SMALL_BODY_RADIUS = 12;\n/**\n * Flat bodies smaller than this on screen, in device pixels, are specks: too\n * few pixels for their shading or badges to show which way is up (see\n * `NodeView.update`).\n */\nconst SPECK_DEVICE_RADIUS = 5;\n/**\n * A crowded orbit's planets without badges are specks below this instead.\n * Drawn flat, with rims that grow with them, they look the same as specks,\n * and their shading, which turns with the orbit while it spins, is too faint\n * at this size to show which way is up.\n */\nconst CROWDED_SPECK_DEVICE_RADIUS = 16;\n\n/**\n * The on-screen radius (px) below which flat bodies are specks, at\n * `pixelRatio` device pixels per px: bigger for a `plainCrowded` planet, one\n * of a crowded orbit without badges (a status, a note's marker, a play button).\n */\nexport const speckRadius = (pixelRatio: number, plainCrowded = false): number => {\n return (plainCrowded ? CROWDED_SPECK_DEVICE_RADIUS : SPECK_DEVICE_RADIUS) / (pixelRatio > 0 ? pixelRatio : 1);\n};\n\n/** The focus ring's radius, in node radii. */\nconst FOCUS_RING_RADIUS = 1.22;\n\n/** What every node is drawn with this frame, besides its own place (see `NodeView.update`). */\nexport interface NodeDrawing {\n /** In an orbit turned as one, the degrees it's turned (see `OrbitTurn`). */\n turn?: number;\n\n /** The on-screen radius (px) below which flat bodies are specks (see `speckRadius`). */\n speckRadius: number;\n\n /** The same for a crowded orbit's planets without badges. */\n crowdedSpeckRadius: number;\n\n /**\n * How many more nodes may become specks, or stop being them, this frame.\n * The rest wait for the next: a zoom across the size where a whole orbit\n * becomes specks doesn't redraw all of it at once.\n */\n switches: number;\n\n /** Set when a node is waiting for its turn to switch. */\n waiting: boolean;\n\n /**\n * During a flight bodies don't become specks: one shrinking as the camera\n * pulls away costs less to leave as it is until the flight lands.\n */\n flight: boolean;\n}\n\n/**\n * Whether a body leaves out its blurred shadow (and hidden halo): when it's\n * too small on screen for a shadow to show, a planet of a crowded orbit,\n * where shadows overlap into a haze, or one coming or going in a flight,\n * fading in or out while the camera sweeps past it (and may draw it huge).\n * Blurring hundreds of shadows on every frame is also what makes a crowded\n * orbit or a flight slow.\n */\nexport const drawsFlat = (display: DisplayNode, screenRadius: number): boolean => {\n return display.crowded === true || display.cluster !== undefined || screenRadius < SMALL_BODY_RADIUS;\n};\n\nexport class NodeView {\n readonly element: SVGGElement;\n readonly id: string;\n readonly node: OrbitNode;\n\n /** The type the node was drawn as. One given for display can change with the map around it, and the view is drawn again then. */\n readonly typeName: string | undefined;\n\n /** Shows a picture (an image, or a video's thumbnail) rather than a plain color. */\n hasImage = false;\n\n /** Shows a status, a note's marker or a play button: a crowded orbit's planet with one stays a body down to the usual size (see `speckRadius`). */\n private readonly hasBadges: boolean;\n\n private readonly body: SVGGElement;\n private readonly disc: SVGCircleElement;\n private readonly shade: SVGCircleElement;\n private readonly shadeFills: { body: string; speck: string };\n private readonly shadowFilters: { planet: string; sun: string };\n\n /**\n * Created once a node shows them: a shadow when it's drawn with one (not\n * the hundreds of flat planets of a crowded orbit, or overview nodes), the\n * halo when it becomes the sun, the focus ring when it's focused.\n */\n private shadow: SVGCircleElement | null = null;\n\n private halo: SVGCircleElement | null = null;\n private focusRing: SVGCircleElement | null = null;\n private status: SVGCircleElement | null = null;\n private role: NodeRole | null = null;\n private color = '';\n private visible = true;\n\n /** Where the node was last drawn, and how: what its transform (or a speck's circles) is worked out from. */\n private drawn = { x: Number.NaN, y: Number.NaN, radius: Number.NaN, upright: 0, opacity: Number.NaN };\n\n private transform = '';\n private opacity = '';\n private editing = false;\n private lifted = false;\n private dropTarget = false;\n private flat = false;\n private crowded = false;\n private speck = false;\n private turnedBack = false;\n\n constructor(display: DisplayNode, screenRadius: number, ids: ViewIds, baseUrl: string | undefined, extensions: MapExtensions, drawing?: NodeDrawing, onImageError?: () => void) {\n this.id = display.id;\n this.node = display.node;\n const { node } = display;\n const type = extensions.nodeType(node);\n this.typeName = extensions.typeName(node);\n this.element = svgElement('g', { class: 'orbit-node', 'data-orbit-node-id': node.id, tabindex: '-1' });\n this.element.setAttribute('role', 'button');\n markNode(this.element, node, this.typeName);\n applyTypeTokens(this.element, type);\n this.body = svgElement('g', { class: 'orbit-node__body' });\n this.shadowFilters = { planet: `url(#${ids.shadow})`, sun: `url(#${ids.sunShadow})` };\n this.disc = svgElement('circle', { class: 'orbit-node__disc', r: '1' });\n this.body.append(this.disc);\n\n const thumbnail = nodeThumbnail(node);\n const source = thumbnail ? guardUrl(thumbnail, 'image') : null;\n\n if (source) {\n const image = svgElement('image', {\n class: 'orbit-node__image',\n x: '-1',\n y: '-1',\n width: '2',\n height: '2',\n preserveAspectRatio: 'xMidYMid slice',\n 'clip-path': `url(#${ids.clip})`,\n });\n image.setAttribute('href', resolveUrl(source, baseUrl));\n\n image.addEventListener('error', () => {\n image.remove();\n this.hasImage = false;\n // The label planned for a picture (its pill outside) belongs inside now: ask for a paint.\n onImageError?.();\n });\n\n this.body.appendChild(image);\n this.hasImage = true;\n }\n\n // Shading and rim in one element: the gradient fills it, the rim is its stroke.\n this.shadeFills = { body: `url(#${ids.shade})`, speck: `url(#${ids.speckShade})` };\n this.shade = svgElement('circle', { class: 'orbit-node__shade', r: '1', fill: this.shadeFills.body });\n this.body.appendChild(this.shade);\n\n const hasMarker = node.note || hasMediaSource(node.image) || hasMediaSource(node.embed) || node.link || type?.details;\n\n if (hasMediaSource(node.video)) {\n const play = svgElement('g', { class: 'orbit-node__play', transform: 'translate(0.62 0.62) scale(0.3)' });\n play.appendChild(svgElement('circle', { r: '1' }));\n play.appendChild(svgElement('path', { d: 'M-0.32 -0.48 L0.52 0 L-0.32 0.48 Z' }));\n this.body.appendChild(play);\n } else if (hasMarker) {\n this.body.appendChild(svgElement('circle', { class: 'orbit-node__marker', cx: '0.72', cy: '0.72', r: '0.13' }));\n }\n\n this.hasBadges = hasMediaSource(node.video) || Boolean(hasMarker) || Boolean(node.status);\n\n if (node.status) {\n const look = extensions.status(node.status);\n this.status = svgElement('circle', { class: `orbit-node__status orbit-node__status--${look.tone}` });\n\n if (look.color) {\n this.status.style.fill = look.color;\n }\n\n this.body.appendChild(this.status);\n }\n\n this.element.appendChild(this.body);\n // A new node starts out as what it is now, before it's on the map: that costs nothing to switch.\n this.update(display, screenRadius, drawing && { ...drawing, switches: Number.POSITIVE_INFINITY, flight: false });\n }\n\n /**\n * Draws the node as `display` places it, `screenRadius` px across on screen.\n *\n * A speck (see `speckRadius`) is drawn with its circles' own coordinates\n * instead of a transform, its badges left out: the browser handles a\n * thousand of them far faster that way, as long as they hold still. A node\n * `moving` on its own (one travelling in a flight) is drawn as a body:\n * moving it is one write instead of one per circle.\n *\n * In an orbit turned as one (see `OrbitTurn`), a body that turns with it is\n * drawn where it is in the unturned orbit: a speck turns with the orbit,\n * shading and all, and anything bigger is turned back upright.\n */\n update(display: DisplayNode, screenRadius = Infinity, drawing?: NodeDrawing, moving = false): void {\n const flat = drawsFlat(display, screenRadius);\n\n if (flat !== this.flat) {\n this.element.classList.toggle('orbit-node--flat', flat);\n this.flat = flat;\n }\n\n const crowded = display.crowded === true;\n\n if (crowded !== this.crowded) {\n this.element.classList.toggle('orbit-node--crowded', crowded);\n this.crowded = crowded;\n }\n\n if (display.role !== this.role) {\n if (this.role) {\n this.element.classList.remove(`orbit-node--${this.role}`);\n }\n\n this.element.classList.add(`orbit-node--${display.role}`);\n this.role = display.role;\n this.shadow?.setAttribute('filter', display.role === 'sun' ? this.shadowFilters.sun : this.shadowFilters.planet);\n\n if (display.role === 'sun') {\n this.element.setAttribute('aria-current', 'true');\n } else {\n this.element.removeAttribute('aria-current');\n }\n\n // The sun is big: a smaller share of it keeps its status dot in proportion.\n const statusRadius = display.role === 'sun' ? 0.11 : 0.17;\n const statusOffset = display.role === 'sun' ? 0.68 : 0.72;\n this.status?.setAttribute('r', String(statusRadius));\n this.status?.setAttribute('cx', String(statusOffset));\n this.status?.setAttribute('cy', String(-statusOffset));\n }\n\n if (!flat && display.role !== 'node' && !this.shadow) {\n this.shadow = svgElement('circle', { class: 'orbit-node__shadow', r: '1' });\n this.shadow.setAttribute('filter', display.role === 'sun' ? this.shadowFilters.sun : this.shadowFilters.planet);\n this.body.insertBefore(this.shadow, this.halo ?? this.disc);\n }\n\n if (display.role === 'sun' && !this.halo) {\n this.halo = svgElement('circle', { class: 'orbit-node__halo', r: '1' });\n this.body.insertBefore(this.halo, this.disc);\n }\n\n if (display.color !== this.color) {\n this.disc.style.fill = display.color;\n // The rim, shadow and halo mix the theme's colors with this one.\n this.element.style.setProperty('--orbit-node-color', display.color);\n this.color = display.color;\n }\n\n const visible = display.opacity > 0.01 && display.radius > 0.05;\n\n if (visible !== this.visible) {\n this.element.style.display = visible ? '' : 'none';\n this.visible = visible;\n }\n\n // Decided while hidden too: a hidden node switches at almost no cost, and needn't wait.\n const below = crowded && !this.hasBadges ? drawing?.crowdedSpeckRadius ?? speckRadius(1, true) : drawing?.speckRadius ?? speckRadius(1);\n const speck = !moving && flat && !this.hasImage && screenRadius < below;\n\n if (speck !== this.speck && !(visible && speck && drawing?.flight)) {\n // A speck that starts moving can't wait either: each frame it waited would cost more than the switch.\n if (visible && drawing && drawing.switches <= 0 && !moving) {\n drawing.waiting = true;\n } else {\n if (visible && drawing) {\n drawing.switches -= 1;\n }\n\n this.setSpeck(speck);\n }\n }\n\n if (!visible) {\n return;\n }\n\n const turn = drawing?.turn;\n const unturned = turn === undefined ? undefined : display.unturned;\n const place = unturned ?? display;\n this.turnedBack = unturned !== undefined && !this.speck;\n const upright = this.turnedBack && turn ? turn : 0;\n // Only touch the DOM when something moved: panning repaints every node, and a spin every body that turns with its orbit.\n const drawn = this.drawn;\n\n if (place.x !== drawn.x || place.y !== drawn.y || display.radius !== drawn.radius || upright !== drawn.upright) {\n if (this.speck) {\n this.placeSpeck(place.x, place.y, display.radius);\n } else {\n const transform = `translate(${round(place.x)} ${round(place.y)})${upright ? ` rotate(${-upright})` : ''} scale(${round(display.radius, 4)})`;\n\n if (transform !== this.transform) {\n this.element.setAttribute('transform', transform);\n this.transform = transform;\n }\n }\n\n drawn.x = place.x;\n drawn.y = place.y;\n drawn.radius = display.radius;\n drawn.upright = upright;\n }\n\n if (display.opacity !== drawn.opacity) {\n const opacity = display.opacity >= 0.999 ? '' : String(round(display.opacity, 3));\n\n if (opacity !== this.opacity) {\n this.element.style.opacity = opacity;\n this.opacity = opacity;\n }\n\n drawn.opacity = display.opacity;\n }\n }\n\n /** Whether it was last drawn turned back upright in an orbit turned as one: it moves as the orbit turns. */\n get isTurnedBack(): boolean {\n return this.turnedBack;\n }\n\n /** Draws the node as a speck from now on, or as a body again. */\n private setSpeck(speck: boolean): void {\n this.speck = speck;\n this.element.classList.toggle('orbit-node--speck', speck);\n this.shade.setAttribute('fill', speck ? this.shadeFills.speck : this.shadeFills.body);\n\n if (speck) {\n this.element.removeAttribute('transform');\n this.transform = '';\n } else {\n for (const circle of this.unitCircles()) {\n circle.removeAttribute('cx');\n circle.removeAttribute('cy');\n circle.setAttribute('r', circle === this.focusRing ? String(FOCUS_RING_RADIUS) : '1');\n }\n\n this.shade.style.removeProperty('--orbit-speck-radius');\n }\n\n // Drawn again where it is, the new way.\n this.drawn.x = Number.NaN;\n }\n\n /** Puts a speck's circles at (`x`, `y`), `radius` in size, in the map's own units. */\n private placeSpeck(x: number, y: number, radius: number): void {\n const cx = String(round(x));\n const cy = String(round(y));\n\n for (const circle of this.unitCircles()) {\n circle.setAttribute('cx', cx);\n circle.setAttribute('cy', cy);\n circle.setAttribute('r', String(round(radius * (circle === this.focusRing ? FOCUS_RING_RADIUS : 1), 4)));\n }\n\n // The rim grows and shrinks with the speck (see the stylesheet).\n this.shade.style.setProperty('--orbit-speck-radius', String(round(radius, 4)));\n }\n\n /** The circles a body draws at unit radius around its center, and a speck at its own place. */\n private unitCircles(): SVGCircleElement[] {\n return this.focusRing ? [this.disc, this.shade, this.focusRing] : [this.disc, this.shade];\n }\n\n /** The fill as the browser resolved it (theme tokens and color mixes included). */\n resolvedFill(): string {\n return typeof getComputedStyle === 'function' ? getComputedStyle(this.disc).fill : '';\n }\n\n /** Marks the node whose text is being edited on the map. */\n setEditing(editing: boolean): void {\n if (editing !== this.editing) {\n if (editing) {\n this.showFocusRing();\n }\n\n this.element.classList.toggle('orbit-node--editing', editing);\n this.editing = editing;\n }\n }\n\n /** Held up by a press, to be dragged somewhere else: it grows, its shadow deepens. */\n setLifted(lifted: boolean): void {\n if (lifted !== this.lifted) {\n this.element.classList.toggle('orbit-node--lifted', lifted);\n this.lifted = lifted;\n }\n }\n\n /** Where a node being dragged would go if let go now: it grows to take it, ringed. */\n setDropTarget(target: boolean): void {\n if (target !== this.dropTarget) {\n if (target) {\n this.showFocusRing();\n }\n\n this.element.classList.toggle('orbit-node--drop-target', target);\n this.dropTarget = target;\n }\n }\n\n /** Adds the ring that shows while the node has keyboard focus or is being edited. */\n showFocusRing(): void {\n if (!this.focusRing) {\n this.focusRing = svgElement('circle', { class: 'orbit-node__focus-ring', r: String(FOCUS_RING_RADIUS) });\n this.body.appendChild(this.focusRing);\n\n if (this.speck) {\n this.placeSpeck(this.drawn.x, this.drawn.y, this.drawn.radius);\n }\n }\n }\n}\n\n/**\n * The free place in the orbit for a new idea: a dashed circle with a plus,\n * drawn at unit radius like a node. While a new idea is typed there, it\n * fills in around the field.\n */\nexport class AddSlotView {\n readonly element: SVGGElement;\n private shown = false;\n private pending = false;\n private drop: 'target' | 'waiting' | false = false;\n private label = '';\n private transform = '';\n private opacity = '';\n\n get isShown(): boolean {\n return this.shown;\n }\n\n /** `held`: the place held for a node being dragged, which only shows, rather than the + to press. */\n constructor(held = false) {\n this.element = held\n ? svgElement('g', { class: 'orbit-add orbit-add--held', 'aria-hidden': 'true' })\n : svgElement('g', { class: 'orbit-add', 'data-orbit-add': '', tabindex: '-1' });\n\n if (!held) {\n this.element.setAttribute('role', 'button');\n }\n\n const body = svgElement('g', { class: 'orbit-add__body' });\n body.append(\n svgElement('circle', { class: 'orbit-add__disc', r: '1' }),\n svgElement('path', { class: 'orbit-add__plus', d: 'M-0.3 0H0.3M0 -0.3V0.3' }),\n svgElement('circle', { class: 'orbit-add__focus-ring', r: String(FOCUS_RING_RADIUS) }),\n );\n this.element.appendChild(body);\n this.element.style.display = 'none';\n }\n\n /**\n * Draws the slot where `slot` says, or hides it. `label` names it for\n * assistive technology. `drop` shows it as the place held open for a node\n * being dragged, without its plus: the `target`, or `waiting` while the\n * node is over another one. In an orbit turned `turn` degrees, it's drawn\n * where it is in the unturned orbit, turned back upright.\n */\n update(slot: DisplaySlot | undefined, label: string, pending: boolean, turn?: number, drop: 'target' | 'waiting' | false = false): void {\n const shown = slot !== undefined && slot.opacity > 0.01 && slot.radius > 0.05;\n\n if (shown !== this.shown) {\n this.element.style.display = shown ? '' : 'none';\n this.shown = shown;\n }\n\n if (!slot || !shown) {\n return;\n }\n\n if (pending !== this.pending) {\n this.element.classList.toggle('orbit-add--pending', pending);\n this.pending = pending;\n }\n\n if (drop !== this.drop) {\n this.element.classList.toggle('orbit-add--drop', drop !== false);\n this.element.classList.toggle('orbit-add--waiting', drop === 'waiting');\n this.drop = drop;\n }\n\n if (label !== this.label) {\n if (label) {\n this.element.setAttribute('aria-label', label);\n } else {\n this.element.removeAttribute('aria-label');\n }\n\n this.label = label;\n }\n\n const unturned = turn === undefined ? undefined : slot.unturned;\n const place = unturned ?? slot;\n const upright = unturned && turn ? ` rotate(${-turn})` : '';\n const transform = `translate(${round(place.x)} ${round(place.y)})${upright} scale(${round(slot.radius, 4)})`;\n\n if (transform !== this.transform) {\n this.element.setAttribute('transform', transform);\n this.transform = transform;\n }\n\n const opacity = slot.opacity >= 0.999 ? '' : String(round(slot.opacity, 3));\n\n if (opacity !== this.opacity) {\n this.element.style.opacity = opacity;\n this.opacity = opacity;\n }\n }\n}\n\n/** CSS hooks for a node's element and label: `data-orbit-type`, `data-orbit-status` and `data-orbit-tags`. */\nexport const markNode = (element: HTMLElement | SVGElement, node: OrbitNode, type: string | undefined = node.type): void => {\n if (type) {\n element.setAttribute('data-orbit-type', type.toLowerCase());\n }\n\n if (node.status) {\n element.setAttribute('data-orbit-status', node.status.trim().toLowerCase());\n }\n\n if (node.tags?.length) {\n element.setAttribute('data-orbit-tags', node.tags.join(' '));\n }\n};\n\n/** A node type's theme tokens, set on its node's elements so they win over the map's theme there. */\nexport const applyTypeTokens = (element: HTMLElement | SVGElement, type: OrbitNodeType | undefined): void => {\n for (const [token, value] of Object.entries(type?.tokens ?? {})) {\n if (typeof value === 'string' && value !== '') {\n element.style.setProperty(`--_orbit-${token}`, value);\n }\n }\n};\n\n/** The picture a node shows: its image, or its video's thumbnail. */\nexport const nodeThumbnail = (node: OrbitNode): string | undefined => {\n if (hasMediaSource(node.image)) {\n return node.image.src;\n }\n\n if (hasMediaSource(node.video)) {\n if (node.video.thumbnail) {\n return node.video.thumbnail;\n }\n\n if (node.video.provider !== 'vimeo' && node.video.provider !== 'native') {\n return youtubeThumbnailUrl(node.video.src) ?? undefined;\n }\n }\n\n return undefined;\n};\n\n/** Inside the node, as a pill outside it, or not shown. */\nexport type LabelPlacement = 'inside' | 'outside' | 'hidden';\n\n/** The size (px) a node's name starts at inside it, before it shrinks to fit. */\nconst LABEL_FONT_SIZE: Record<NodeRole, number> = { sun: 16, planet: 13, node: 12, moon: 13 };\n/**\n * The smallest a name gets inside its node. Crowded orbits need small text\n * to keep names inside their nodes, the focused node's too, since its own\n * orbit shrinks it; a node too small even for this shows no name until you\n * zoom in (the focused node always shows its name). An overview node's name\n * has its pill to go to, so it stays closer to the pills' size.\n */\nconst MINIMUM_FONT_SIZE: Record<NodeRole, number> = { sun: 9, planet: 9, node: 10, moon: 9 };\n/** The most lines a name wraps to inside its node. */\nconst LABEL_LINES: Record<NodeRole, number> = { sun: 4, planet: 3, node: 3, moon: 2 };\n/** Height of a line of label text, and of the icon above it, in ems (as the stylesheet sets them). */\nconst LINE_HEIGHT = 1.22;\nconst ICON_HEIGHT = 1.45;\n/** Pixels between the icon and the text. */\nconst ICON_GAP = 2;\n/** A name cut short still shows this many characters, or none: a few letters don't say what a node is. */\nconst SHORTEST_CUT = 8;\n\n/** The width (px) of a label typed into a node of this on-screen radius. Snapped to 6 px steps so zooming doesn't re-wrap text every frame. */\nexport const insideLabelWidth = (role: NodeRole, screenRadius: number): number => {\n return Math.max(44, Math.min(260, Math.round((screenRadius * (role === 'sun' ? 1.6 : 1.68)) / 6) * 6));\n};\n\n/** A piece of a name a line can't break inside, its width in ems, and whether a space comes before it. */\ninterface MeasuredUnit {\n text: string;\n ems: number;\n spaced: boolean;\n}\n\n/** A name measured at one font size. */\ninterface SizedText {\n units: MeasuredUnit[];\n\n /** Width (em) of the longest run a line can't break inside: a word piece, or a single wide character. */\n longestUnbreakable: number;\n\n /** Width (em) of the whole text on one line. */\n total: number;\n\n /** A space between words, an ellipsis and a hyphen, in ems. */\n space: number;\n\n ellipsis: number;\n hyphen: number;\n}\n\n/**\n * The size (px) a name is measured at for text of `fontSize`: text shrunk\n * below 12 px at 9 px, and the rest at 12 px. Fonts with optical sizes draw\n * small text a few percent wider, so measuring at the smallest size of each\n * kind never measures a name narrower than it's drawn.\n */\nconst measuredSize = (fontSize: number): number => {\n return fontSize < 12 ? 9 : 12;\n};\n\n/** A name's pieces, measured at the sizes it's fitted at (see `measuredSize`). */\nclass TextMetrics {\n readonly measure: TextMeasure;\n private readonly pieces: TextUnit[];\n private readonly sizes = new Map<number, SizedText>();\n\n constructor(text: string, measure: TextMeasure) {\n this.measure = measure;\n this.pieces = breakUnits(text);\n }\n\n at(fontSize: number): SizedText {\n const size = this.measure.bySize ? measuredSize(fontSize) : 0;\n let sized = this.sizes.get(size);\n\n if (!sized) {\n const { measure } = this;\n const units = this.pieces.map((unit) => ({ text: unit.text, ems: measure.ems(unit.text, size), spaced: unit.spaced }));\n const space = measure.space(size);\n sized = {\n units,\n longestUnbreakable: units.reduce((longest, unit) => Math.max(longest, unit.ems), 0),\n total: units.reduce((sum, unit, index) => sum + unit.ems + (index > 0 && unit.spaced ? space : 0), 0),\n space,\n ellipsis: measure.ellipsis(size),\n hyphen: measure.ems('-', size),\n };\n this.sizes.set(size, sized);\n }\n\n return sized;\n }\n\n /** Width (em) of one character in text of `fontSize`, for cutting a name between characters. */\n character(character: string, fontSize: number): number {\n return this.measure.ems(character, this.measure.bySize ? measuredSize(fontSize) : 0);\n }\n}\n\n/**\n * Metrics by font and text. Every label's fit is worked out each frame while\n * the map moves, but the text rarely changes and measuring it walks every\n * character.\n */\nconst textMetricsCache = new Map<string, TextMetrics>();\n/** More texts than the largest maps have; past it, the measurements start over. */\nconst TEXT_METRICS_LIMIT = 20000;\n\nconst textMetrics = (text: string, measure: TextMeasure): TextMetrics => {\n const key = `${measure.key}\\n${text}`;\n const cached = textMetricsCache.get(key);\n\n if (cached) {\n return cached;\n }\n\n if (textMetricsCache.size >= TEXT_METRICS_LIMIT) {\n textMetricsCache.clear();\n }\n\n const metrics = new TextMetrics(text, measure);\n textMetricsCache.set(key, metrics);\n return metrics;\n};\n\n/**\n * The font size (px) of text typed into a node: the role's size, reduced\n * (down to its minimum) until the longest word fits on one line.\n */\nexport const insideFontSize = (role: NodeRole, width: number, text: string, measure: TextMeasure = INSIDE_ESTIMATE): number => {\n const longest = textMetrics(text, measure).at(LABEL_FONT_SIZE[role]).longestUnbreakable;\n const fitting = longest > 0 ? width / longest : LABEL_FONT_SIZE[role];\n return Math.max(MINIMUM_FONT_SIZE[role], Math.min(LABEL_FONT_SIZE[role], Math.floor(fitting * 2) / 2));\n};\n\nexport interface InsideLabelLayout {\n /** Width of the text block (px): its widest line's room. */\n width: number;\n\n fontSize: number;\n\n /** The name as it shows, line by line; the last ends with an ellipsis when the name is cut short. */\n lines: string[];\n\n /** Whether the node's icon shows above its name. */\n icon: boolean;\n\n /** The name doesn't fit whole. */\n truncated: boolean;\n\n /** A narrower width of the font the name is drawn in, as `font-stretch` (a percentage), when it needs one to fit. */\n stretch?: number;\n\n /** How far above the node's center (px) the lines and icon are centered: they rise to clear the node's \"+N\". */\n lift: number;\n}\n\n/** Joins units onto one line, with their spaces. */\nconst lineText = (units: MeasuredUnit[]): string => {\n return units.map((unit, index) => (index > 0 && unit.spaced ? ` ${unit.text}` : unit.text)).join('');\n};\n\n/** How wide (em) units are on one line, with their spaces. */\nconst lineEms = (units: MeasuredUnit[], sized: SizedText): number => {\n return units.reduce((sum, unit, index) => sum + unit.ems + (index > 0 && unit.spaced ? sized.space : 0), 0);\n};\n\n/** Whether lines this wide (ems) fit the room each has (px), in text of `fontSize`. */\nconst fitRooms = (ems: number[], widths: number[], fontSize: number): boolean => {\n return ems.length <= widths.length && ems.every((width, index) => width * fontSize <= widths[index] + 1e-9);\n};\n\n/**\n * Units of text wrapped onto lines `widths` ems wide, the first unit that\n * doesn't fit starting the next line; null when they need more lines, or a\n * unit is wider than its line.\n */\nconst wrapUnits = (sized: SizedText, widths: number[]): MeasuredUnit[][] | null => {\n const lines: MeasuredUnit[][] = [];\n let line: MeasuredUnit[] = [];\n let used = 0;\n\n for (const unit of sized.units) {\n const space = used > 0 && unit.spaced ? sized.space : 0;\n\n if (used > 0 && used + space + unit.ems > widths[lines.length]) {\n lines.push(line);\n\n if (lines.length >= widths.length) {\n return null;\n }\n\n line = [];\n used = 0;\n }\n\n if (unit.ems > widths[lines.length]) {\n return null;\n }\n\n used += (used > 0 && unit.spaced ? sized.space : 0) + unit.ems;\n line.push(unit);\n }\n\n lines.push(line);\n return lines;\n};\n\n/**\n * The same units on as many lines, broken where every line fills as little\n * of its room as can be (a circle's lines are widest in the middle), so a\n * name's shape follows its node's instead of crowding the first line:\n * \"Lanzamiento / en México\" rather than \"Lanzamiento en / México\".\n */\nconst balanceLines = (lines: MeasuredUnit[][], sized: SizedText, widths: number[]): MeasuredUnit[][] => {\n const count = lines.length;\n\n if (count < 2) {\n return lines;\n }\n\n const units = count === 2 ? [...lines[0], ...lines[1]] : lines.flat();\n const total = units.length;\n\n if (total <= count) {\n return lines;\n }\n\n // Ems before each unit, and the spaces before each unit (a line drops the one before its first unit).\n const ems = new Float64Array(total + 1);\n const spaces = new Float64Array(total + 1);\n\n for (let index = 0; index < total; index += 1) {\n ems[index + 1] = ems[index] + units[index].ems;\n spaces[index + 1] = spaces[index] + (units[index].spaced ? sized.space : 0);\n }\n\n const fill = (start: number, end: number, line: number) => (ems[end] - ems[start] + spaces[end] - spaces[start + 1]) / widths[line];\n const splits = count === 4 ? fourLineSplits(total, fill) : fewLineSplits(count, total, fill);\n\n if (!splits) {\n return lines;\n }\n\n const balanced: MeasuredUnit[][] = [];\n let start = 0;\n\n for (const end of [...splits, total]) {\n balanced.push(units.slice(start, end));\n start = end;\n }\n\n return balanced;\n};\n\n/** Where two or three lines break (the units each starts at, after the first) so the fullest is as empty as can be; null when none fits. */\nconst fewLineSplits = (count: number, total: number, fill: (start: number, end: number, line: number) => number): number[] | null => {\n let best = Infinity;\n let splits: number[] | null = null;\n\n if (count === 2) {\n for (let first = 1; first < total; first += 1) {\n const worst = Math.max(fill(0, first, 0), fill(first, total, 1));\n\n if (worst <= 1 && worst < best - 1e-9) {\n best = worst;\n splits = [first];\n }\n }\n\n return splits;\n }\n\n for (let first = 1; first < total - 1; first += 1) {\n const top = fill(0, first, 0);\n\n if (top > 1) {\n break;\n }\n\n for (let second = first + 1; second < total; second += 1) {\n const worst = Math.max(top, fill(first, second, 1), fill(second, total, 2));\n\n if (worst <= 1 && worst < best - 1e-9) {\n best = worst;\n splits = [first, second];\n }\n }\n }\n\n return splits;\n};\n\n/** As `fewLineSplits`, for four lines (a sun's longest names): the least fullest line, line by line. */\nconst fourLineSplits = (total: number, fill: (start: number, end: number, line: number) => number): number[] | null => {\n // fills[line][end]: the least fullest line for units before `end` on lines up to `line`; starts: where that last line starts.\n const fills = Array.from({ length: 4 }, () => new Float64Array(total + 1).fill(Infinity));\n const starts = Array.from({ length: 4 }, () => new Int32Array(total + 1));\n\n for (let end = 1; end <= total; end += 1) {\n const first = fill(0, end, 0);\n fills[0][end] = first <= 1 ? first : Infinity;\n }\n\n for (let line = 1; line < 4; line += 1) {\n for (let end = line + 1; end <= total; end += 1) {\n for (let start = line; start < end; start += 1) {\n const before = fills[line - 1][start];\n const own = fill(start, end, line);\n const worst = Math.max(before, own);\n\n if (own <= 1 && worst < fills[line][end] - 1e-9) {\n fills[line][end] = worst;\n starts[line][end] = start;\n }\n }\n }\n }\n\n if (fills[3][total] === Infinity) {\n return null;\n }\n\n const splits: number[] = [];\n let end = total;\n\n for (let line = 3; line > 0; line -= 1) {\n end = starts[line][end];\n splits.unshift(end);\n }\n\n return splits;\n};\n\n/** A name cut to fit its lines: the lines, how wide each is (ems), how many characters show, and whether any don't. */\ninterface CutText {\n lines: string[];\n widths: number[];\n shown: number;\n truncated: boolean;\n}\n\n/**\n * As much of the text as `widths` hold, word pieces kept whole, the last line\n * ending with an ellipsis when text was cut (cut between characters if need\n * be), and how many characters show. Null when a line can't hold even its\n * first piece.\n */\nconst cutUnits = (metrics: TextMetrics, fontSize: number, widths: number[]): CutText | null => {\n const sized = metrics.at(fontSize);\n const total = sized.units.reduce((sum, unit) => sum + unit.text.length, 0);\n const lines: string[] = [];\n const usedEms: number[] = [];\n const last = widths.length - 1;\n const widest = Math.max(...widths);\n const room = () => widths[lines.length] - (lines.length === last ? sized.ellipsis : 0);\n let line = '';\n let used = 0;\n let shown = 0;\n\n for (let unit of sized.units) {\n let space = used > 0 && unit.spaced ? sized.space : 0;\n\n if (used + space + unit.ems > room() && lines.length < last) {\n if (used > 0) {\n lines.push(line);\n usedEms.push(used);\n line = '';\n used = 0;\n space = 0;\n }\n\n // A long word wider than any line breaks with a hyphen; anything else waits for a wider line.\n if (unit.ems > room() && unit.ems <= widest) {\n return null;\n }\n\n while (unit.ems > room() && lines.length < last) {\n const split = hyphenate(unit, room(), metrics, fontSize);\n\n if (!split) {\n return null;\n }\n\n lines.push(split.head);\n usedEms.push(split.headEms);\n shown += split.head.length - 1;\n unit = split.rest;\n }\n }\n\n if (used + space + unit.ems <= room()) {\n line += space > 0 ? ` ${unit.text}` : unit.text;\n used += space + unit.ems;\n shown += unit.text.length;\n continue;\n }\n\n // The last line is full: as much of this piece as fits before the ellipsis.\n for (const character of graphemes(unit.text)) {\n const width = metrics.character(character, fontSize);\n\n if (used + space + width > room()) {\n break;\n }\n\n line += space > 0 ? ` ${character}` : character;\n used += space + width;\n space = 0;\n shown += character.length;\n }\n\n break;\n }\n\n // A long word hyphenated across lines can leave everything fitting after all: nothing cut, no ellipsis.\n const truncated = shown < total;\n lines.push(truncated ? `${line.trimEnd()}…` : line.trimEnd());\n usedEms.push(used + (truncated ? sized.ellipsis : 0));\n return { lines, widths: usedEms, shown, truncated };\n};\n\n/** Words this long or longer may break with a hyphen when a name is cut short anyway. */\nconst HYPHENATED_WORD = /^\\p{L}{8,}$/u;\n\n/** A long word's head (with a hyphen) that fits in `room` ems, how wide it is (ems), and the rest of the word; null for anything else. */\nconst hyphenate = (unit: MeasuredUnit, room: number, metrics: TextMetrics, fontSize: number): { head: string; headEms: number; rest: MeasuredUnit } | null => {\n if (!HYPHENATED_WORD.test(unit.text)) {\n return null;\n }\n\n const characters = graphemes(unit.text);\n let head = '';\n let used = metrics.at(fontSize).hyphen;\n let count = 0;\n let headEms = 0;\n\n for (const character of characters) {\n const width = metrics.character(character, fontSize);\n\n if (used + width > room) {\n break;\n }\n\n head += character;\n used += width;\n headEms += width;\n count += 1;\n }\n\n // At least three letters on each side of the hyphen.\n if (count < 3 || characters.length - count < 3) {\n return null;\n }\n\n const rest = characters.slice(count).join('');\n // What's left of the word is as wide as the word less its head (give or take kerning).\n return { head: `${head}-`, headEms: used, rest: { text: rest, ems: Math.max(0, unit.ems - headEms), spaced: false } };\n};\n\n/** The width (px) of a circle of radius `room` at height `y` from its center. */\nconst chordAt = (room: number, y: number): number => {\n return Math.abs(y) >= room ? 0 : 2 * Math.sqrt(room * room - y * y);\n};\n\n/**\n * The \"+N\" of a node with children that aren't drawn (the renderer's\n * `paintCounts`) is centered this share of the node's radius right of and\n * below the node's center.\n */\nexport const COUNT_POSITION = 0.74;\n/** A \"+N\" is this tall (px): its line and padding, as the stylesheet sets them. */\nexport const COUNT_HEIGHT = 15;\n/** A \"+N\"'s text size (px), and its padding on each side (px), as the stylesheet sets them. */\nconst COUNT_FONT_SIZE = 10.5;\nconst COUNT_PADDING = 6;\n/** Pixels a name inside a node keeps from the node's \"+N\". */\nconst COUNT_GAP = 1.5;\n/** The space under a line's letters (ems), which may pass over a \"+N\": the tails of g, p and y end this far above the line's bottom. */\nconst UNDER_TAILS = 0.15;\n\n/** Whether a node of this role and on-screen radius shows a \"+N\" for children that aren't drawn (flights and faded nodes hide it for a while). */\nexport const showsCount = (role: NodeRole, screenRadius: number, hiddenChildren: number): boolean => {\n return hiddenChildren > 0 && role !== 'moon' && screenRadius >= 10;\n};\n\n/** \"+N\" widths (px) by font, then by how many figures the count has: its figures are all as wide (tabular). */\nconst countWidths = new Map<TextMeasure, number[]>();\n\n/** How wide (px) a node's \"+N\" is for `hiddenChildren` children, in `measure` (the font it's drawn in). */\nexport const measureCount = (hiddenChildren: number, measure: TextMeasure = COUNT_ESTIMATE): number => {\n let figures = 1;\n\n for (let rest = hiddenChildren; rest >= 10; rest = Math.floor(rest / 10)) {\n figures += 1;\n }\n\n let widths = countWidths.get(measure);\n\n if (!widths) {\n widths = [];\n countWidths.set(measure, widths);\n }\n\n let width = widths[figures];\n\n if (width === undefined) {\n // Tabular figures are as wide as each other: a canvas, which draws the font's own figures, measures zeros.\n width = 2 * COUNT_PADDING + measure.ems(`+${'0'.repeat(figures)}`, COUNT_FONT_SIZE) * COUNT_FONT_SIZE;\n widths[figures] = width;\n }\n\n return width;\n};\n\n/** A node's \"+N\" as the name inside it keeps clear of it, from the node's center (px): lines reaching below `top` end left of `left`. */\ninterface CountBox {\n top: number;\n left: number;\n}\n\n/**\n * Where a node of this radius shows its \"+N\", `width` px wide, gap included;\n * null when it shows none. Fits round the radius down, so the count is\n * never nearer the center than this.\n */\nconst countBox = (radius: number, width: number): CountBox | null => {\n return width > 0 ? { top: COUNT_POSITION * radius - COUNT_HEIGHT / 2 - COUNT_GAP, left: COUNT_POSITION * radius - width / 2 - COUNT_GAP } : null;\n};\n\n/** The room for each line of a name (px), and how far above the node's center (px) its lines and icon are centered. */\ninterface LineRoom {\n widths: number[];\n lift: number;\n}\n\n/**\n * Room for each of `count` lines of `fontSize` px text centered in a circle of\n * radius `room`, under an icon when `icon` (null when the icon itself doesn't\n * fit). Each line gets the circle's width at its middle. Beside a \"+N\"\n * (`badge`), the lines and icon rise, as far as the circle allows, until the\n * last line's letters clear it, and a line still beside it ends short of it:\n * lines are centered, so they end as far from the center on the left too.\n */\nconst lineWidths = (room: number, fontSize: number, count: number, icon: boolean, badge: CountBox | null = null): LineRoom | null => {\n const lineHeight = fontSize * LINE_HEIGHT;\n const iconHeight = icon ? fontSize * ICON_HEIGHT + ICON_GAP : 0;\n const height = iconHeight + count * lineHeight;\n\n if (height > room * 2) {\n return null;\n }\n\n // How low the bottom of a line may sit: the space under its letters may pass over the \"+N\".\n const lowest = badge ? badge.top + fontSize * UNDER_TAILS : Infinity;\n const lift = badge ? Math.min(Math.max(0, height / 2 - lowest), room - height / 2) : 0;\n const top = -height / 2 - lift;\n\n if (icon && chordAt(room, top + (fontSize * ICON_HEIGHT) / 2) < fontSize * ICON_HEIGHT) {\n return null;\n }\n\n const widths: number[] = [];\n\n for (let index = 0; index < count; index += 1) {\n const lineTop = top + iconHeight + index * lineHeight;\n const width = chordAt(room, lineTop + lineHeight / 2);\n widths.push(badge && lineTop + lineHeight > lowest + 1e-9 ? Math.min(width, 2 * Math.max(0, badge.left)) : width);\n }\n\n return { widths, lift };\n};\n\n/** How far below its node's center (px) a name laid out inside it reaches: its lines and icon are centered `lift` above it. */\nexport const insideLabelReach = (layout: InsideLabelLayout): number => {\n const iconHeight = layout.icon ? layout.fontSize * ICON_HEIGHT + ICON_GAP : 0;\n return (iconHeight + layout.lines.length * layout.fontSize * LINE_HEIGHT) / 2 - layout.lift;\n};\n\n/**\n * A name's fit at one size, in its font's own width, and once tried (when\n * the map is still), the narrower one it may need.\n */\ninterface InsideFits {\n own: InsideLabelLayout | null;\n narrower?: InsideLabelLayout | null;\n}\n\n/** Fitted labels by font, then role, size and text: labels are fitted on every frame while the map moves. */\nconst insideLayouts = new Map<TextMeasure, Map<string, InsideFits>>();\nconst INSIDE_LAYOUTS_LIMIT = 20000;\n\n// Fits made from measurements start over with them (a font finished loading).\nonMeasurementsReset(() => {\n textMetricsCache.clear();\n insideLayouts.clear();\n countWidths.clear();\n});\n\n/**\n * How a node's name fits inside it at this on-screen radius, or null when it\n * doesn't. The name shrinks (down to the role's minimum) and wraps (at\n * spaces, and inside long words where they read), its lines balanced and\n * each as wide as the circle is where it sits. The icon above it stays while\n * the name only shrinks a little. A name too long to fit whole even then\n * shows as much as fits, ending with an ellipsis, as long as that's enough\n * to read. `measure` measures the text in the font it's drawn with (by\n * default, widths are estimated).\n *\n * A name that doesn't fit at its font's width tries narrower ones (see\n * `fitInside`) only when `narrower` allows, as it does while the map is\n * still: while the map moves, trying hundreds of names in each width would\n * make frames late. A fit already made with them is kept, though.\n *\n * A node showing a \"+N\" `countWidth` px wide (see `measureCount`) keeps its\n * name clear of it: the name rises above it, or gets smaller.\n */\nexport const insideLabelLayout = (role: NodeRole, screenRadius: number, text: string, hasIcon = false, measure: TextMeasure = INSIDE_ESTIMATE, narrower = true, countWidth = 0): InsideLabelLayout | null => {\n // In steps of about 6% (2 px at least), so a zoom or a flight doesn't fit and write the text again on every frame.\n const step = Math.max(2, Math.round(screenRadius * 0.06));\n const radius = Math.floor(screenRadius / step) * step;\n\n // Most of a crowded orbit has no room for any name: no need to look each one up on every frame it moves.\n if (insideRoom(radius) < SMALLEST_INSIDE_ROOM) {\n return null;\n }\n\n let inFont = insideLayouts.get(measure);\n\n if (!inFont) {\n inFont = new Map();\n insideLayouts.set(measure, inFont);\n }\n\n const key = `${role}|${radius}|${hasIcon ? 1 : 0}|${countWidth}|${text}`;\n let fits = inFont.get(key);\n\n if (fits === undefined) {\n if (inFont.size >= INSIDE_LAYOUTS_LIMIT) {\n inFont.clear();\n }\n\n const own = fitInFont(role, radius, text, hasIcon, measure, countWidth);\n // A name that shows whole in its font's own width needs nothing narrower.\n fits = own !== null && !own.truncated ? { own, narrower: own } : { own };\n inFont.set(key, fits);\n }\n\n if (fits.narrower !== undefined) {\n return fits.narrower;\n }\n\n if (!narrower) {\n return fits.own;\n }\n\n fits.narrower = fitNarrower(role, radius, text, hasIcon, measure, countWidth) ?? fits.own;\n return fits.narrower;\n};\n\n/** How far below its usual size a name shrinks before its node's icon makes way (px). */\nconst ICON_SHRINK = 3;\n\n/** The radius (px) a name has inside a node of this on-screen radius: text keeps a little off the rim. */\nconst insideRoom = (radius: number): number => {\n return radius - Math.max(2, radius * 0.05);\n};\n\n/** Below this room (px), no name fits inside. */\nconst SMALLEST_INSIDE_ROOM = 6;\n\n/**\n * Only in nodes with at least this much room (px): a crowded orbit's small\n * planets can't show a name whole in any width, and trying each one at\n * every step of a zoom would slow the zoom down.\n */\nconst NARROWER_ROOM = 16;\n\n/**\n * A name that's cut short or has no room in its font's own width, fitted\n * in a narrower width of it (a font with a width axis draws semi-condensed,\n * then condensed), when that shows it whole; null when none does.\n */\nconst fitNarrower = (role: NodeRole, radius: number, text: string, hasIcon: boolean, measure: TextMeasure, countWidth: number): InsideLabelLayout | null => {\n const narrower = insideRoom(radius) >= NARROWER_ROOM ? measure.narrower() : null;\n\n if (!narrower || !mightFitWhole(role, radius, text, narrower.narrower() ?? narrower)) {\n return null;\n }\n\n for (let width: TextMeasure | null = narrower; width; width = width.narrower()) {\n const attempt = fitInFont(role, radius, text, hasIcon, width, countWidth);\n\n if (attempt && !attempt.truncated) {\n return { ...attempt, stretch: width.stretch };\n }\n }\n\n return null;\n};\n\n/**\n * Whether a name could fit whole in this node in `measure`, at the role's\n * smallest size: its longest piece across the circle, and all of it in the\n * circle's area. Most names in a crowded orbit can't, at any width.\n */\nconst mightFitWhole = (role: NodeRole, radius: number, text: string, measure: TextMeasure): boolean => {\n const smallest = MINIMUM_FONT_SIZE[role];\n const sized = textMetrics(text, measure).at(smallest);\n const room = insideRoom(radius);\n const breakable = Math.max(sized.total - sized.space * LABEL_LINES[role], 0.01);\n return sized.longestUnbreakable * smallest <= 2 * room && smallest <= room * Math.sqrt((1.25 * Math.PI) / (LINE_HEIGHT * breakable));\n};\n\nconst fitInFont = (role: NodeRole, radius: number, text: string, hasIcon: boolean, measure: TextMeasure, countWidth: number): InsideLabelLayout | null => {\n const room = insideRoom(radius);\n const badge = countBox(radius, countWidth);\n\n if (room < SMALLEST_INSIDE_ROOM) {\n return null;\n }\n\n const metrics = textMetrics(text, measure);\n const largest = LABEL_FONT_SIZE[role];\n const smallest = MINIMUM_FONT_SIZE[role];\n // No size above these fits: the longest piece must fit the circle's width, and the text (less the\n // spaces lines break at) its area, with room to spare, since lines are as wide as the circle at their middle.\n const breakableAt = (sized: SizedText) => Math.max(sized.total - sized.space * LABEL_LINES[role], 0.01);\n const widest = metrics.at(largest);\n const fitting = Math.min(largest, (2 * room) / Math.max(widest.longestUnbreakable, 0.01), room * Math.sqrt((1.25 * Math.PI) / (LINE_HEIGHT * breakableAt(widest))));\n const start = Math.floor(fitting * 2) / 2;\n const attempts: [boolean, number][] = [];\n\n if (hasIcon) {\n for (let fontSize = start; fontSize >= Math.max(smallest, largest - ICON_SHRINK); fontSize -= 0.5) {\n attempts.push([true, fontSize]);\n }\n }\n\n for (let fontSize = start; fontSize >= smallest; fontSize -= 0.5) {\n attempts.push([false, fontSize]);\n }\n\n for (const [icon, fontSize] of attempts) {\n const sized = metrics.at(fontSize);\n const breakable = breakableAt(sized);\n\n // No fewer lines than the text's width (less the spaces lines break at) over the circle's.\n for (let count = Math.max(1, Math.ceil((breakable * fontSize) / (2 * room))); count <= LABEL_LINES[role]; count += 1) {\n const tried = lineWidths(room, fontSize, count, icon, badge);\n\n if (!tried) {\n break;\n }\n\n const wrapped = wrapUnits(sized, tried.widths.map((width) => width / fontSize));\n\n if (!wrapped) {\n continue;\n }\n\n // Balanced over the lines it takes, each as wide as the circle where those lines sit. Fewer lines than\n // tried sit elsewhere, where the circle may be narrower or the \"+N\" nearer: they show only if they fit there.\n const shown = wrapped.length === count ? tried : lineWidths(room, fontSize, wrapped.length, icon, badge);\n\n if (!shown) {\n continue;\n }\n\n const lines = balanceLines(wrapped, sized, shown.widths.map((width) => width / fontSize));\n\n if (!fitRooms(lines.map((units) => lineEms(units, sized)), shown.widths, fontSize)) {\n continue;\n }\n\n return { width: Math.floor(Math.max(...shown.widths.slice(0, lines.length))), fontSize, lines: lines.map(lineText), icon, truncated: false, lift: shown.lift };\n }\n }\n\n // An overview node's name that doesn't fit whole reads better whole, on its pill.\n if (role === 'node') {\n return null;\n }\n\n // Too long to fit whole: as many lines of the smallest text as show the most of it.\n let best: InsideLabelLayout | null = null;\n let mostShown = 0;\n\n for (let count = 1; count <= LABEL_LINES[role]; count += 1) {\n const tried = lineWidths(room, smallest, count, false, badge);\n\n if (!tried) {\n break;\n }\n\n const cut = cutUnits(metrics, smallest, tried.widths.map((width) => width / smallest));\n\n if (!cut || cut.shown <= mostShown) {\n continue;\n }\n\n // A word hyphenated across lines can leave fewer lines than tried, drawn elsewhere: shown only if they fit there.\n const shown = cut.lines.length === count ? tried : lineWidths(room, smallest, cut.lines.length, false, badge);\n\n if (!shown || !fitRooms(cut.widths, shown.widths, smallest)) {\n continue;\n }\n\n mostShown = cut.shown;\n best = { width: Math.floor(Math.max(...shown.widths)), fontSize: smallest, lines: cut.lines, icon: false, truncated: cut.truncated, lift: shown.lift };\n }\n\n return role === 'sun' || mostShown >= SHORTEST_CUT ? best : null;\n};\n\n/**\n * Where a node's label goes at this on-screen size. A name goes inside its\n * node whenever it fits there (see `insideLabelLayout`). A pill beside the\n * node is for the nodes that need one: nodes showing a picture, the focused\n * node when its name doesn't fit inside, and overview nodes too small for\n * their names. Any other node too small for its name shows none until you\n * zoom in. A name inside a node keeps clear of its \"+N\", `countWidth` px wide.\n */\nexport const labelPlacement = (role: NodeRole, screenRadius: number, text: string, hasImage: boolean, hasIcon = false, measure: TextMeasure = INSIDE_ESTIMATE, narrower = true, countWidth = 0): LabelPlacement => {\n if (!hasImage && insideLabelLayout(role, screenRadius, text, hasIcon, measure, narrower, countWidth)) {\n return 'inside';\n }\n\n if (role === 'sun') {\n return 'outside';\n }\n\n if (hasImage || role === 'node') {\n return screenRadius >= (role === 'moon' ? 11 : 4) ? 'outside' : 'hidden';\n }\n\n return 'hidden';\n};\n\n/** Fills `element` with `text`, marking where long words may break (`wordPieces`), as fitting the label assumes. */\nconst setBreakableText = (element: HTMLElement, text: string): void => {\n element.textContent = '';\n\n for (const part of text.split(/(\\s+)/)) {\n if (!part) {\n continue;\n }\n\n if (/^\\s+$/.test(part)) {\n element.append(part);\n continue;\n }\n\n wordPieces(part).forEach((piece, index) => {\n if (index > 0) {\n element.append(document.createElement('wbr'));\n }\n\n element.append(piece);\n });\n }\n};\n\n/** How a node's label is drawn on a frame (see `NodeLabel.update`). */\nexport interface LabelDrawing {\n /** The node's center on screen (px). */\n x: number;\n\n y: number;\n\n /** The node's radius on screen (px). */\n screenRadius: number;\n\n role: NodeRole;\n placement: LabelPlacement;\n opacity: number;\n\n /** Whether a name inside its node takes the theme's light text. */\n light?: boolean;\n\n /** The font a name inside its node is fitted in, as its placement was (default: estimated widths). */\n measure?: TextMeasure;\n\n /** Whether a name inside its node may try narrower widths of its font, as it does while the map is still (default: true). */\n narrower?: boolean;\n\n /** The width (px) of the node's \"+N\", which a name inside it keeps clear of (default: 0, when it shows none). */\n countWidth?: number;\n\n /** The side of its node a pill touches, a unit vector (default: below). */\n direction?: { x: number; y: number };\n\n /** How far from the node's center a pill sits (px; see `pillDistance` in `labels.ts`; default: 5 px past its edge). */\n distance?: number;\n\n /** Pixels a pill above or below its node slid sideways to stay on the map. */\n offset?: number;\n\n /** A pill's lines, and the width (px) it wraps at on two. */\n lines?: 1 | 2;\n\n width?: number;\n\n /** What a pill says (default: the node's name). */\n pillText?: string;\n}\n\n/** Where a pill goes when nothing says: below its node. */\nconst BELOW = { x: 0, y: 1 };\n\nexport class NodeLabel {\n readonly element: HTMLDivElement;\n readonly node: OrbitNode;\n\n /** The type the node was drawn as, as for its view. */\n readonly typeName: string | undefined;\n\n private readonly text: HTMLSpanElement;\n\n /** Whether the node has an icon, shown above its name when there's room. */\n private readonly hasIcon: boolean;\n\n /** The side an outside label sat on last (a unit vector), or null. */\n direction: { x: number; y: number } | null = null;\n\n private placement: LabelPlacement | null = null;\n private role: NodeRole | null = null;\n private fontSize = 0;\n\n /** The `font-stretch` written for a name drawn narrower to fit (0: the font's own width). */\n private stretch = 0;\n\n /** The lines written into the label inside its node, or null while it holds the whole name (pills wrap it themselves). */\n private shownLines: string | null = null;\n\n /** What the label's pill says, while it's a pill. */\n private pillText: string | null = null;\n\n private iconHidden = false;\n private light: boolean | null = null;\n\n /** An outside pill on two lines, and the width it wraps at. */\n private wrapped = false;\n\n private pillWidth = 0;\n\n /** What was last written, so a label that didn't move isn't touched: the map repaints every frame while it moves. */\n private shown = true;\n\n private transform = '';\n private opacity = '';\n\n constructor(node: OrbitNode, extensions: MapExtensions) {\n this.node = node;\n this.element = document.createElement('div');\n this.element.className = 'orbit-label';\n this.element.setAttribute('aria-hidden', 'true');\n this.element.dataset.orbitFor = node.id;\n this.typeName = extensions.typeName(node);\n markNode(this.element, node, this.typeName);\n applyTypeTokens(this.element, extensions.nodeType(node));\n const iconText = extensions.icon(node);\n this.hasIcon = Boolean(iconText);\n\n if (iconText) {\n const icon = document.createElement('span');\n icon.className = 'orbit-label__icon';\n icon.textContent = iconText;\n this.element.appendChild(icon);\n }\n\n this.text = document.createElement('span');\n this.text.className = 'orbit-label__text';\n setBreakableText(this.text, node.text);\n this.element.appendChild(this.text);\n }\n\n get currentPlacement(): LabelPlacement {\n return this.placement ?? 'hidden';\n }\n\n /** Whether the label shows: placed somewhere and not hidden. */\n get isShown(): boolean {\n return this.shown && this.placement !== null && this.placement !== 'hidden';\n }\n\n /** Draws the label as `drawing` says: inside its node, fitted as its placement was, or as a pill beside it. */\n update(drawing: LabelDrawing): void {\n const { x, y, screenRadius, role, placement, opacity } = drawing;\n\n if (placement !== this.placement || role !== this.role) {\n this.element.className = `orbit-label orbit-label--${role}${placement === 'outside' ? ' orbit-label--outside' : ''}`;\n this.placement = placement;\n this.role = role;\n this.light = null;\n this.wrapped = false;\n }\n\n const shown = placement !== 'hidden' && opacity > 0.01;\n\n if (shown !== this.shown) {\n this.element.style.display = shown ? '' : 'none';\n this.shown = shown;\n }\n\n if (!shown) {\n return;\n }\n\n let transform: string;\n\n if (placement === 'inside') {\n const layout = insideLabelLayout(role, screenRadius, this.node.text, this.hasIcon, drawing.measure, drawing.narrower, drawing.countWidth) ?? {\n width: insideLabelWidth(role, screenRadius),\n fontSize: MINIMUM_FONT_SIZE[role],\n lines: [this.node.text],\n icon: false,\n truncated: true,\n lift: 0,\n };\n const light = drawing.light ?? false;\n\n if (light !== this.light) {\n this.element.classList.toggle('orbit-label--light', light);\n this.light = light;\n }\n\n if (layout.fontSize !== this.fontSize) {\n this.element.style.fontSize = `${layout.fontSize}px`;\n this.fontSize = layout.fontSize;\n }\n\n const stretch = layout.stretch ?? 0;\n\n if (stretch !== this.stretch) {\n this.element.style.fontStretch = stretch ? `${stretch}%` : '';\n this.stretch = stretch;\n }\n\n // The lines the fit chose, exactly: the browser doesn't wrap them again.\n const shownLines = layout.lines.join('\\n');\n\n if (shownLines !== this.shownLines) {\n this.text.textContent = shownLines;\n this.shownLines = shownLines;\n this.pillText = null;\n }\n\n const iconHidden = this.hasIcon && !layout.icon;\n\n if (iconHidden !== this.iconHidden) {\n this.element.classList.toggle('orbit-label--no-icon', iconHidden);\n this.iconHidden = iconHidden;\n }\n\n transform = `translate3d(${round(x, 1)}px, ${round(y - layout.lift, 1)}px, 0) translate(-50%, -50%)`;\n } else {\n const { direction = BELOW, distance = screenRadius + 5, offset = 0, lines = 1, width = 0, pillText = this.node.text } = drawing;\n\n if (this.fontSize !== 0) {\n this.element.style.fontSize = '';\n this.fontSize = 0;\n }\n\n if (this.stretch !== 0) {\n this.element.style.fontStretch = '';\n this.stretch = 0;\n }\n\n if (this.shownLines !== null || this.pillText !== pillText) {\n setBreakableText(this.text, pillText);\n this.shownLines = null;\n this.pillText = pillText;\n }\n\n const wrapped = lines === 2;\n\n if (wrapped !== this.wrapped) {\n this.element.classList.toggle('orbit-label--wrapped', wrapped);\n this.wrapped = wrapped;\n }\n\n // No wider than the box label planning kept on the map.\n if (wrapped && width !== this.pillWidth) {\n this.element.style.setProperty('--orbit-pill-width', `${Math.floor(width)}px`);\n this.pillWidth = width;\n }\n\n // The pill's point that matches its side sits `distance` from the node's center (see `pillDistance`).\n this.direction = direction;\n const shiftX = round(-50 + direction.x * 50, 1);\n const shiftY = round(-50 + direction.y * 50, 1);\n transform = `translate3d(${round(x + direction.x * distance + offset, 1)}px, ${round(y + direction.y * distance, 1)}px, 0) translate(${shiftX}%, ${shiftY}%)`;\n }\n\n if (transform !== this.transform) {\n this.element.style.transform = transform;\n this.transform = transform;\n }\n\n const opacityValue = opacity >= 0.999 ? '' : String(round(opacity, 3));\n\n if (opacityValue !== this.opacity) {\n this.element.style.opacity = opacityValue;\n this.opacity = opacityValue;\n }\n }\n}\n\n/** Dashed ring arcs between the bodies on a ring (centered on the origin). */\nexport const ringPath = (radius: number, gaps: DisplayRing['gaps']): string => {\n if (radius <= 0) {\n return '';\n }\n\n const openings = gaps\n .map((gap) => ({ start: normalizeAngle(gap.angle - gap.halfWidth), width: gap.halfWidth * 2 }))\n .filter((gap) => gap.width > 0)\n .sort((left, right) => left.start - right.start);\n\n if (openings.length === 0) {\n return `M ${round(radius)} 0 A ${round(radius)} ${round(radius)} 0 1 1 ${round(-radius)} 0 A ${round(radius)} ${round(radius)} 0 1 1 ${round(radius)} 0`;\n }\n\n const commands: string[] = [];\n\n for (let index = 0; index < openings.length; index += 1) {\n const current = openings[index];\n const next = openings[(index + 1) % openings.length];\n const arcStart = current.start + current.width;\n let arcEnd = next.start;\n\n if (index === openings.length - 1) {\n arcEnd += 360;\n }\n\n const sweep = arcEnd - arcStart;\n\n if (sweep <= 0.5) {\n continue;\n }\n\n const from = polar(radius, arcStart);\n const to = polar(radius, arcEnd);\n commands.push(`M ${round(from.x)} ${round(from.y)} A ${round(radius)} ${round(radius)} 0 ${sweep > 180 ? 1 : 0} 1 ${round(to.x)} ${round(to.y)}`);\n }\n\n return commands.join(' ');\n};\n\nconst polar = (radius: number, degrees: number): { x: number; y: number } => {\n const radians = (degrees * Math.PI) / 180;\n return { x: radius * Math.cos(radians), y: radius * Math.sin(radians) };\n};\n\nconst normalizeAngle = (degrees: number): number => {\n return ((degrees % 360) + 360) % 360;\n};\n\nconst round = (value: number, decimals = 2): number => {\n const factor = 10 ** decimals;\n return Math.round(value * factor) / factor;\n};\n",
|
|
48
|
+
"/**\n * Where a node being dragged would go if it were let go now: into another\n * node, at a place in the focused orbit, or nowhere. Pure functions over what\n * is on screen, so the renderer only tracks the finger.\n */\n\nimport type { OrbitNode } from '../types.js';\nimport type { Display, DisplayNode } from './display.js';\nimport { toDegrees, type Scene } from './scene.js';\n\n/** Where a dragged node would go: under `parentId`, at `index` among its children (null: after the last). */\nexport interface DropPlace {\n parentId: string;\n index: number | null;\n\n /** Dropped on a node rather than on a place in the orbit. */\n into: boolean;\n}\n\ninterface Point {\n readonly x: number;\n readonly y: number;\n}\n\n/**\n * The ids a node can't be dropped into: itself and everything under it\n * (a node can't go inside itself), and its parent, which it is already in.\n */\nexport const unreachableIds = (node: OrbitNode, parentId: string | undefined): Set<string> => {\n const ids = new Set<string>();\n const stack = [node];\n\n while (stack.length > 0) {\n const current = stack.pop() as OrbitNode;\n ids.add(current.id);\n stack.push(...current.children);\n }\n\n if (parentId !== undefined) {\n ids.add(parentId);\n }\n\n return ids;\n};\n\n/**\n * The node under `point` (world coordinates) to drop into, or null. Each\n * node catches the point within `catchRadius` of its center (world units),\n * given whether it's the target so far, so a target can hold on a little\n * further than it caught; the most central catch wins.\n */\nexport const nodeUnder = (\n display: Display,\n point: Point,\n unreachable: ReadonlySet<string>,\n catchRadius: (node: DisplayNode, current: boolean) => number,\n current: string | null,\n): DisplayNode | null => {\n let best: DisplayNode | null = null;\n let bestShare = Infinity;\n\n for (const entry of display.nodes.values()) {\n if (unreachable.has(entry.id) || entry.opacity < 0.6 || entry.radius <= 0) {\n continue;\n }\n\n const limit = catchRadius(entry, entry.id === current);\n const distance = Math.hypot(point.x - entry.x, point.y - entry.y);\n\n if (distance > limit) {\n continue;\n }\n\n // How far out from its center, as a share of what it catches: the most central catch wins.\n const share = distance / limit;\n\n if (share < bestShare) {\n best = entry;\n bestShare = share;\n }\n }\n\n return best;\n};\n\n/**\n * The place in a focused orbit for node `draggedId` dropped at `point`\n * (relative to the sun, in an orbit turned `rotation` degrees), counted among\n * the sun's children without it, or null when the point is off the orbit.\n * `layout` is the orbit as it's drawn, with the place it's held at (it, laid\n * out there, or the slot), so the place under the press is the one on\n * screen: it stays put while the press stays near it, and moves past a\n * planet the press crosses. `ringRadius` is used when the orbit is empty.\n * Orbits of more than one ring take drops on their planets only.\n *\n * The first place and the last are the same gap, between the last planet\n * and the first: there, the place held now (`current`) stays, rather than\n * turning the whole orbit a step.\n */\nexport const orbitPlaceAt = (\n layout: Scene,\n point: Point,\n rotation: number,\n ringRadius: number,\n band: number,\n draggedId: string,\n current: number | null = null,\n): number | null => {\n if (layout.kind !== 'focus' || layout.rings.length > 1) {\n return null;\n }\n\n const radius = layout.rings[0]?.radius ?? ringRadius;\n\n if (Math.abs(Math.hypot(point.x, point.y) - radius) > band) {\n return null;\n }\n\n const clockwise = (angle: number): number => ((angle % 360) + 360) % 360;\n const planets = Array.from(layout.nodes.values()).filter((node) => node.role === 'planet' && node.orbitAngle !== undefined);\n const siblings = planets.filter((node) => node.id !== draggedId).map((node) => node.orbitAngle as number);\n\n if (siblings.length === 0) {\n return 0;\n }\n\n // Everything on the ring, going round from where the orbit starts (the top): count from halfway before the first.\n const around = planets.map((node) => node.orbitAngle as number);\n\n if (layout.addSlot) {\n around.push(layout.addSlot.orbitAngle);\n }\n\n around.sort((first, second) => clockwise(first + 90) - clockwise(second + 90));\n const half = around.length > 1 ? clockwise(around[1] - around[0]) / 2 : 180;\n const from = around[0] - half;\n const pointer = clockwise(toDegrees(Math.atan2(point.y, point.x)) - rotation - from);\n const place = siblings.filter((angle) => clockwise(angle - from) < pointer).length;\n const ends = (index: number | null) => index === 0 || index === siblings.length;\n return ends(place) && ends(current) ? (current as number) : place;\n};\n\n/** Whether two places are the same. */\nexport const samePlace = (first: DropPlace | null, second: DropPlace | null): boolean => {\n if (first === null || second === null) {\n return first === second;\n }\n\n return first.parentId === second.parentId && first.index === second.index && first.into === second.into;\n};\n",
|
|
49
|
+
"/**\n * Small color helpers: parse the formats browsers report for computed\n * colors, mix in OKLab like CSS `color-mix(in oklab, …)`, measure WCAG\n * contrast to choose label colors, and resolve the map's theme tokens into\n * plain hex colors for exports that leave the page.\n */\n\n/** sRGB channels and alpha, each 0–1. */\nexport interface Rgb {\n red: number;\n green: number;\n blue: number;\n alpha: number;\n}\n\nconst NAMED: Record<string, string> = {\n white: '#ffffff',\n black: '#000000',\n transparent: '#00000000',\n};\n\n/**\n * A CSS number: signed, with or without digits before the point, with an\n * exponent. Browsers report a mixed node's fill as `oklab(0.73 -0.089 0.027)`,\n * and people write `rgba(0, 0, 0, .5)`. Malformed text like `1.2.3` or\n * `1-2` doesn't match, so it never becomes a NaN channel.\n */\nconst NUMBER = String.raw`[-+]?(?:\\d*\\.\\d+|\\d+)(?:e[-+]?\\d+)?`;\nconst RGB = new RegExp(String.raw`^rgba?\\(\\s*(${NUMBER})(%?)[\\s,]+(${NUMBER})(%?)[\\s,]+(${NUMBER})(%?)(?:\\s*[,/]\\s*(${NUMBER})(%?))?\\s*\\)$`);\nconst SRGB = new RegExp(String.raw`^color\\(srgb\\s+(${NUMBER})\\s+(${NUMBER})\\s+(${NUMBER})(?:\\s*\\/\\s*(${NUMBER})(%?))?\\s*\\)$`);\nconst OKLAB = new RegExp(String.raw`^oklab\\(\\s*(${NUMBER})(%?)\\s+(${NUMBER})\\s+(${NUMBER})(?:\\s*\\/\\s*(${NUMBER})(%?))?\\s*\\)$`);\nconst OKLCH = new RegExp(String.raw`^oklch\\(\\s*(${NUMBER})(%?)\\s+(${NUMBER})\\s+(${NUMBER})(?:deg)?(?:\\s*\\/\\s*(${NUMBER})(%?))?\\s*\\)$`);\n\nexport const parseColor = (input: string): Rgb | null => {\n const value = input.trim().toLowerCase();\n\n if (NAMED[value]) {\n return parseColor(NAMED[value]);\n }\n\n let match = /^#([0-9a-f]{3,8})$/.exec(value);\n\n if (match) {\n return parseHex(match[1]);\n }\n\n match = RGB.exec(value);\n\n if (match) {\n // A channel is out of 255, or out of 100 when written as a percentage.\n const channel = (amount: string, percent: string) => Number(amount) / (percent === '%' ? 100 : 255);\n return {\n red: channel(match[1], match[2]),\n green: channel(match[3], match[4]),\n blue: channel(match[5], match[6]),\n alpha: readAlpha(match[7], match[8]),\n };\n }\n\n match = SRGB.exec(value);\n\n if (match) {\n return { red: Number(match[1]), green: Number(match[2]), blue: Number(match[3]), alpha: readAlpha(match[4], match[5]) };\n }\n\n match = OKLAB.exec(value);\n\n if (match) {\n const lightness = Number(match[1]) / (match[2] === '%' ? 100 : 1);\n return fromOklab(lightness, Number(match[3]), Number(match[4]), readAlpha(match[5], match[6]));\n }\n\n match = OKLCH.exec(value);\n\n if (match) {\n const lightness = Number(match[1]) / (match[2] === '%' ? 100 : 1);\n const chroma = Number(match[3]);\n const hue = (Number(match[4]) * Math.PI) / 180;\n return fromOklab(lightness, chroma * Math.cos(hue), chroma * Math.sin(hue), readAlpha(match[5], match[6]));\n }\n\n return null;\n};\n\nconst parseHex = (digits: string): Rgb | null => {\n const expanded = digits.length === 3 || digits.length === 4\n ? digits.split('').map((digit) => digit + digit).join('')\n : digits;\n\n if (expanded.length !== 6 && expanded.length !== 8) {\n return null;\n }\n\n const channel = (index: number) => parseInt(expanded.slice(index, index + 2), 16) / 255;\n return { red: channel(0), green: channel(2), blue: channel(4), alpha: expanded.length === 8 ? channel(6) : 1 };\n};\n\nconst readAlpha = (value: string | undefined, percent: string | undefined): number => {\n if (value === undefined) {\n return 1;\n }\n\n return Number(value) / (percent === '%' ? 100 : 1);\n};\n\nexport const toHex = (color: Rgb): string => {\n const channel = (value: number) => Math.round(Math.min(1, Math.max(0, value)) * 255).toString(16).padStart(2, '0');\n const alpha = color.alpha < 1 ? channel(color.alpha) : '';\n return `#${channel(color.red)}${channel(color.green)}${channel(color.blue)}${alpha}`;\n};\n\nconst toLinear = (channel: number): number => {\n return channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;\n};\n\nconst fromLinear = (channel: number): number => {\n return channel <= 0.0031308 ? channel * 12.92 : 1.055 * channel ** (1 / 2.4) - 0.055;\n};\n\nconst toOklab = (color: Rgb): [number, number, number] => {\n const red = toLinear(color.red);\n const green = toLinear(color.green);\n const blue = toLinear(color.blue);\n const long = Math.cbrt(0.4122214708 * red + 0.5363325363 * green + 0.0514459929 * blue);\n const medium = Math.cbrt(0.2119034982 * red + 0.6806995451 * green + 0.1073969566 * blue);\n const short = Math.cbrt(0.0883024619 * red + 0.2817188376 * green + 0.6299787005 * blue);\n return [\n 0.2104542553 * long + 0.793617785 * medium - 0.0040720468 * short,\n 1.9779984951 * long - 2.428592205 * medium + 0.4505937099 * short,\n 0.0259040371 * long + 0.7827717662 * medium - 0.808675766 * short,\n ];\n};\n\n/** An OKLab color's linear-light sRGB channels, unclamped: outside 0–1 when sRGB can't show it. */\nconst oklabToLinear = (lightness: number, a: number, b: number): [number, number, number] => {\n const long = (lightness + 0.3963377774 * a + 0.2158037573 * b) ** 3;\n const medium = (lightness - 0.1055613458 * a - 0.0638541728 * b) ** 3;\n const short = (lightness - 0.0894841775 * a - 1.291485548 * b) ** 3;\n return [\n 4.0767416621 * long - 3.3077115913 * medium + 0.2309699292 * short,\n -1.2684380046 * long + 2.6097574011 * medium - 0.3413193965 * short,\n -0.0041960863 * long - 0.7034186147 * medium + 1.707614701 * short,\n ];\n};\n\nconst fromOklab = (lightness: number, a: number, b: number, alpha: number): Rgb => {\n const [red, green, blue] = oklabToLinear(lightness, a, b);\n return { red: fromLinear(red), green: fromLinear(green), blue: fromLinear(blue), alpha };\n};\n\n/** A color's OKLCH coordinates: lightness (0–1), chroma and hue in degrees. */\nexport interface Oklch {\n lightness: number;\n chroma: number;\n hue: number;\n}\n\nexport const toOklch = (color: Rgb): Oklch => {\n const [lightness, a, b] = toOklab(color);\n const chroma = Math.hypot(a, b);\n const hue = chroma < 1e-4 ? 0 : ((Math.atan2(b, a) * 180) / Math.PI + 360) % 360;\n return { lightness, chroma, hue };\n};\n\n/**\n * The relative luminance of a Material tone, which is CIELAB's L*: tone 0 is\n * black, 50 a middle gray and 100 white. Two tones 50 apart always have at\n * least 4.5:1 contrast, which is how Material keeps text readable.\n */\nconst toneLuminance = (tone: number): number => {\n return tone > 8 ? ((tone + 16) / 116) ** 3 : tone / 903.2962962962963;\n};\n\n/** Luminance and whether sRGB can show the OKLCH color. */\nconst measureOklch = (lightness: number, chroma: number, hue: number): { luminance: number; shown: boolean } => {\n const angle = (hue * Math.PI) / 180;\n const channels = oklabToLinear(lightness, chroma * Math.cos(angle), chroma * Math.sin(angle));\n const [red, green, blue] = channels;\n return {\n luminance: 0.2126 * red + 0.7152 * green + 0.0722 * blue,\n shown: channels.every((channel) => channel >= -1e-5 && channel <= 1 + 1e-5),\n };\n};\n\n/** The OKLab lightness that gives a color of this chroma and hue the luminance asked for. */\nconst lightnessFor = (luminance: number, chroma: number, hue: number): number => {\n let low = 0;\n let high = 1;\n\n for (let step = 0; step < 32; step += 1) {\n const middle = (low + high) / 2;\n\n if (measureOklch(middle, chroma, hue).luminance < luminance) {\n low = middle;\n } else {\n high = middle;\n }\n }\n\n return (low + high) / 2;\n};\n\n/**\n * A color of `hue` (OKLCH degrees) at a Material tone: as much of `chroma` as\n * sRGB can show at that luminance, so every hue at one tone has the same\n * contrast with every other tone.\n */\nexport const toneColor = (hue: number, chroma: number, tone: number): Rgb => {\n const luminance = toneLuminance(Math.min(100, Math.max(0, tone)));\n const fits = (candidate: number) => measureOklch(lightnessFor(luminance, candidate, hue), candidate, hue).shown;\n let shown = chroma;\n\n if (!fits(chroma)) {\n let low = 0;\n let high = chroma;\n\n for (let step = 0; step < 20; step += 1) {\n const middle = (low + high) / 2;\n\n if (fits(middle)) {\n low = middle;\n } else {\n high = middle;\n }\n }\n\n shown = low;\n }\n\n const lightness = lightnessFor(luminance, shown, hue);\n const angle = (hue * Math.PI) / 180;\n const color = fromOklab(lightness, shown * Math.cos(angle), shown * Math.sin(angle), 1);\n const clamp = (channel: number) => Math.min(1, Math.max(0, channel));\n return { red: clamp(color.red), green: clamp(color.green), blue: clamp(color.blue), alpha: 1 };\n};\n\n/** `color-mix(in oklab, first amount, second)` with `amount` from 0 to 1. */\nexport const mixOklab = (first: Rgb, second: Rgb, amount: number): Rgb => {\n const [firstLightness, firstA, firstB] = toOklab(first);\n const [secondLightness, secondA, secondB] = toOklab(second);\n const mix = (from: number, to: number) => from * amount + to * (1 - amount);\n return fromOklab(\n mix(firstLightness, secondLightness),\n mix(firstA, secondA),\n mix(firstB, secondB),\n mix(first.alpha, second.alpha),\n );\n};\n\n/** WCAG relative luminance (0–1) of a color's sRGB channels, ignoring alpha. */\nexport const relativeLuminance = (color: Rgb): number => {\n return 0.2126 * toLinear(color.red) + 0.7152 * toLinear(color.green) + 0.0722 * toLinear(color.blue);\n};\n\n/** WCAG contrast ratio (1–21) between two opaque colors. */\nexport const contrastRatio = (first: Rgb, second: Rgb): number => {\n const [lighter, darker] = [relativeLuminance(first), relativeLuminance(second)].sort((left, right) => right - left);\n return (lighter + 0.05) / (darker + 0.05);\n};\n\n/**\n * Whether `lightText` reads better than `darkText` on `fill`: the one with\n * more contrast wins, a tie going to the light text. When the text colors\n * can't be parsed, light text goes on fills darker than mid-gray.\n */\nexport const prefersLightText = (fill: string, lightText: string, darkText: string): boolean => {\n const background = parseColor(fill);\n\n if (!background) {\n return false;\n }\n\n const light = parseColor(lightText);\n const dark = parseColor(darkText);\n\n if (!light || !dark) {\n return relativeLuminance(background) < 0.18;\n }\n\n return contrastRatio(background, light) >= contrastRatio(background, dark);\n};\n\n/** A color as an opaque hex value and an opacity, for SVG attributes that design tools read. */\nexport const splitAlpha = (color: string): { color: string; opacity: number } => {\n const parsed = parseColor(color);\n\n if (!parsed) {\n return { color, opacity: 1 };\n }\n\n return { color: toHex({ ...parsed, alpha: 1 }), opacity: Math.round(parsed.alpha * 1000) / 1000 };\n};\n\n/**\n * Resolves `var(--_orbit-token)` references and `color-mix(in oklab, …)`\n * into a hex color using concrete token values. Returns the input unchanged\n * when part of it can't be resolved.\n */\nexport const resolveColor = (value: string, tokens: Record<string, string>): string => {\n const substituted = value.replace(/var\\(--_?orbit-([a-z0-9-]+)(?:\\s*,\\s*([^()]+))?\\)/gi, (whole, token: string, fallback?: string) => {\n return tokens[token] ?? fallback?.trim() ?? whole;\n });\n\n const mix = /^color-mix\\(\\s*in\\s+oklab\\s*,\\s*(.+?)\\s+(\\d*\\.\\d+|\\d+)%\\s*,\\s*(.+?)\\s*\\)$/i.exec(substituted.trim());\n\n if (mix) {\n const first = parseColor(resolveColor(mix[1], tokens));\n const second = parseColor(resolveColor(mix[3], tokens));\n\n if (first && second) {\n return toHex(mixOklab(first, second, Number(mix[2]) / 100));\n }\n\n return value;\n }\n\n const parsed = parseColor(substituted);\n return parsed ? toHex(parsed) : substituted;\n};\n",
|
|
50
|
+
"/**\n * Where every label goes, frame by frame: inside its node, on a chip, as a\n * pill beside the node, or nowhere. Pills try the sides of their node in\n * order of preference and take the first one that covers no other label,\n * no other node and doesn't run off the map. The browser renderer and the\n * SVG export both use this, so an export looks like the live map.\n */\n\nimport type { Viewport } from './camera.js';\nimport { worldToScreen } from './camera.js';\nimport type { Display, DisplayNode } from './display.js';\nimport { labelPlacement, measureCount, showsCount, type LabelPlacement } from './views.js';\nimport { breakUnits, joinUnits } from '../text-layout.js';\nimport { ESTIMATED_LABELS, INSIDE_ESTIMATE, PILL_ESTIMATE, onMeasurementsReset, type LabelMeasures, type TextMeasure } from './text-measure.js';\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface Box {\n left: number;\n right: number;\n top: number;\n bottom: number;\n}\n\nexport interface PlannedLabel {\n entry: DisplayNode;\n\n /** The node's center on screen. */\n x: number;\n\n y: number;\n screenRadius: number;\n placement: Exclude<LabelPlacement, 'hidden'>;\n\n /** Which side of the node an outside label sits on (a unit vector). */\n direction: Point;\n\n /** How far from the node's center a pill sits (px; see `pillDistance`). */\n distance: number;\n\n /** Pixels a pill above or below its node slid sideways to stay on the map. */\n offset: number;\n\n /** A pill's lines: two when one line fits nowhere. */\n lines: 1 | 2;\n\n /** A pill's estimated width. */\n width: number;\n\n opacity: number;\n\n /** What a pill says: the node's name, after its icon when `pillIcon` gives one. */\n text: string;\n\n /** The width (px) of the node's \"+N\", which a name inside it keeps clear of; 0 when it shows none. */\n countWidth: number;\n}\n\nexport interface LabelPlanOptions {\n viewport: Viewport;\n\n /** Whether the node shows a picture, which pushes its label outside. */\n hasImage(entry: DisplayNode): boolean;\n\n /** Whether the node has an icon to show above its name (the fit is the label's own, cached). */\n hasIcon?(entry: DisplayNode): boolean;\n\n /**\n * An icon to show on the node's pill, before its name: for a node whose\n * picture or content fills it, so the icon has no place inside.\n */\n pillIcon?(entry: DisplayNode): string | undefined;\n\n /** The side a label sat on last frame, so labels don't hop around while the map moves. */\n previousSide?(id: string): Point | null;\n\n /** While nodes fly between views, pills stay hidden; they'd flicker as nodes grow and shrink. */\n inFlight?: boolean;\n\n /** Measures names in the fonts the map draws them with; by default, widths are estimated. */\n measures?: LabelMeasures;\n\n /**\n * While the map moves, names that don't fit at their font's width don't\n * try narrower ones, and names not yet showing only start to when they'd\n * fit by the estimate too (`isShown` says which show): measured names fit\n * more often, and hundreds starting to show mid-zoom would make frames\n * late. Once the map is still (and by default), every name that fits shows.\n */\n moving?: boolean;\n\n /** Whether a node's label shows now. */\n isShown?(id: string): boolean;\n\n /** Whether nodes show a \"+N\" for children that aren't drawn, which names inside them keep clear of: the map does, an export doesn't. */\n counts?: boolean;\n}\n\nconst BELOW: Point = { x: 0, y: 1 };\nconst ABOVE: Point = { x: 0, y: -1 };\n/** Nodes this far outside the map get no label at all. */\nconst OFF_SCREEN_MARGIN = 120;\n/** A pill slid sideways still reaches this far past its node's center, so it reads as the node's. */\nconst NUDGE_REACH = 10;\n\nconst ROLE_PRIORITY = { sun: 0, planet: 1, node: 1, moon: 2 } as const;\n\n/** What covering a body with a pill costs: the sun's own label matters most. */\nconst COVER_COST = { sun: 4, planet: 1, node: 1, moon: 0.5 } as const;\n\n/** The order labels are placed in, so the important ones win when they would overlap. */\nexport const labelOrder = (nodes: Iterable<DisplayNode>): DisplayNode[] => {\n return Array.from(nodes).sort((left, right) => (\n ROLE_PRIORITY[left.role] - ROLE_PRIORITY[right.role] || left.depth - right.depth || right.radius - left.radius\n ));\n};\n\ninterface Disc extends Point {\n id: string;\n radius: number;\n cost: number;\n}\n\ninterface Spot {\n side: Point;\n offset: number;\n lines: 1 | 2;\n box: Box;\n}\n\n/** The labels to show this frame, in `order`. Nodes missing from the result show no label. */\nexport const planLabels = (display: Display, order: DisplayNode[], options: LabelPlanOptions): PlannedLabel[] => {\n const { camera } = display;\n const { viewport } = options;\n // Every body a pill keeps clear of, with how much covering it would cost\n // when a planet's pill has nowhere free to go. Bodies 2 px or smaller don't count.\n const discs = new ScreenGrid<Disc>(viewport);\n\n const addDisc = (id: string, center: Point, radius: number, cost: number) => {\n if (radius > 2) {\n discs.add({ id, x: center.x, y: center.y, radius, cost }, { left: center.x - radius, right: center.x + radius, top: center.y - radius, bottom: center.y + radius });\n }\n };\n\n for (const entry of display.nodes.values()) {\n if (entry.opacity > 0.3) {\n addDisc(entry.id, worldToScreen(camera, viewport, entry), entry.radius * camera.scale, COVER_COST[entry.role]);\n }\n }\n\n // Pills keep clear of the + in the orbit too.\n if (display.addSlot && display.addSlot.opacity > 0.3) {\n addDisc('', worldToScreen(camera, viewport, display.addSlot), display.addSlot.radius * camera.scale, 0.75);\n }\n\n const taken = new ScreenGrid<Box>(viewport);\n const measures = options.measures ?? ESTIMATED_LABELS;\n const countMeasure = options.counts ? measures.count() : null;\n const planned: PlannedLabel[] = [];\n\n for (const entry of order) {\n const point = worldToScreen(camera, viewport, entry);\n const screenRadius = entry.radius * camera.scale;\n const opacity = entry.opacity * entry.labelOpacity;\n\n if (opacity <= 0.01 || isOffScreen(point, screenRadius, viewport)) {\n continue;\n }\n\n const countWidth = countMeasure && showsCount(entry.role, screenRadius, entry.hiddenChildren) ? measureCount(entry.hiddenChildren, countMeasure) : 0;\n const placement = labelPlacement(entry.role, screenRadius, entry.node.text, options.hasImage(entry), options.hasIcon?.(entry), measures.inside(entry.role, entry.node), !options.moving, countWidth);\n\n if (placement === 'hidden' || (placement === 'outside' && options.inFlight)) {\n continue;\n }\n\n // While the map moves, a name starts to show only where the estimate would show it too, and during a\n // flight between views, only such names show at all; the rest wait for the map to be still.\n if (placement === 'inside' && options.moving && measures !== ESTIMATED_LABELS && (options.inFlight || !options.isShown?.(entry.id))\n && labelPlacement(entry.role, screenRadius, entry.node.text, false, options.hasIcon?.(entry), INSIDE_ESTIMATE, true, countWidth) !== 'inside') {\n continue;\n }\n\n let direction = BELOW;\n let fromCenter = 0;\n let offset = 0;\n let lines: 1 | 2 = 1;\n let width = 0;\n const icon = placement === 'outside' ? options.pillIcon?.(entry) : undefined;\n const text = icon ? `${icon} ${entry.node.text}`.trim() : entry.node.text;\n\n if (placement === 'outside') {\n const sides = labelSides(entry, display);\n const previous = options.previousSide?.(entry.id);\n\n if (previous) {\n sides.sort((left, right) => distance(left, previous) - distance(right, previous));\n }\n\n const maximumWidth = entry.role === 'sun' ? 280 : 160;\n const pill = measures.pill(entry.role, entry.node);\n\n const spotFor = (side: Point, lineCount: 1 | 2): Spot => {\n const box = outsideLabelBox(text, point, screenRadius, side, maximumWidth, 0, lineCount, pill);\n const nudge = side.x === 0 ? horizontalNudge(box, point.x, viewport) : 0;\n return { side, offset: nudge, lines: lineCount, box: nudge === 0 ? box : outsideLabelBox(text, point, screenRadius, side, maximumWidth, nudge, lineCount, pill) };\n };\n\n const coversNode = (box: Box) => discs.some(box, (disc) => disc.id !== entry.id && discOverlapsBox(disc, box));\n const coverCost = (box: Box) => discs.sum(box, (disc) => (disc.id !== entry.id && discOverlapsBox(disc, box) ? disc.cost : 0));\n const coversLabel = (box: Box) => taken.some(box, (other) => overlaps(box, other));\n const isFree = ({ box }: Spot) => insideViewport(box, viewport) && !coversLabel(box) && !coversNode(box);\n const spots = sides.map((side) => spotFor(side, 1));\n // A pill too wide for every side tries again on two lines, narrower.\n let wrapped: Spot[] | undefined;\n const wrappedSpots = () => (wrapped ??= canWrap(text, pill) ? sides.map((side) => spotFor(side, 2)) : []);\n let spot = spots.find(isFree) ?? wrappedSpots().find(isFree);\n\n if (!spot && entry.role === 'sun') {\n // The focused node always says what it is, even over its neighbors…\n spot = spots.find(({ box }) => insideViewport(box, viewport)) ?? spots[0];\n } else if (!spot && entry.role === 'planet') {\n // …and so does each planet: over as few nodes as it can, never over another label.\n let cheapest = Infinity;\n\n for (const candidate of [...spots, ...wrappedSpots()]) {\n if (insideViewport(candidate.box, viewport) && !coversLabel(candidate.box)) {\n const cost = coverCost(candidate.box);\n\n if (cost < cheapest) {\n spot = candidate;\n cheapest = cost;\n }\n }\n }\n }\n\n if (!spot) {\n continue;\n }\n\n direction = spot.side;\n offset = spot.offset;\n lines = spot.lines;\n width = spot.box.right - spot.box.left;\n fromCenter = pillDistance(screenRadius, direction, width, lines);\n taken.add(spot.box, spot.box);\n }\n\n planned.push({ entry, x: point.x, y: point.y, screenRadius, placement, direction, distance: fromCenter, offset, lines, width, opacity, text, countWidth });\n }\n\n return planned;\n};\n\n/**\n * The sides a node's pill may go, best first. Toward the parent is usually\n * free (a planet's moons and a branch's children sit on the far side); a\n * leaf in the overview has its far side free too. Moons look away from\n * their planet. Below and above are the fallbacks.\n */\nexport const labelSides = (entry: DisplayNode, display: Display): Point[] => {\n const parent = entry.parentId === undefined ? undefined : display.nodes.get(entry.parentId);\n const length = parent ? Math.hypot(parent.x - entry.x, parent.y - entry.y) : 0;\n\n if (!parent || length < 1e-6) {\n return [BELOW, ABOVE];\n }\n\n const inward = { x: (parent.x - entry.x) / length, y: (parent.y - entry.y) / length };\n const outward = { x: -inward.x, y: -inward.y };\n\n if (entry.role === 'moon') {\n return [outward];\n }\n\n const isLeaf = entry.node.children.length === 0 || entry.hiddenChildren >= entry.node.children.length;\n return isLeaf && entry.role === 'node' ? [outward, inward, BELOW, ABOVE] : [inward, BELOW, ABOVE, outward];\n};\n\n/**\n * Where an outside label will be, from its text's width in `measure` (by\n * default, an estimate), slid `offset` pixels sideways, on `lines` lines.\n * The pill is drawn no bigger than this box: its width holds the text, the\n * pill's padding (16 px) and 2 px to spare, and the stylesheet counts the\n * padding in a pill's width, capped at the same 160 px (280 px for the\n * focused node).\n */\nexport const outsideLabelBox = (text: string, point: Point, screenRadius: number, direction: Point, maximumWidth: number, offset = 0, lines: 1 | 2 = 1, measure: TextMeasure = PILL_ESTIMATE): Box => {\n const width = Math.min(maximumWidth, pillTextWidth(text, lines, measure) + 18);\n const height = PILL_HEIGHT[lines];\n const distance = pillDistance(screenRadius, direction, width, lines);\n const centerX = point.x + direction.x * (distance + width / 2) + offset;\n const centerY = point.y + direction.y * (distance + height / 2);\n return { left: centerX - width / 2, right: centerX + width / 2, top: centerY - height / 2, bottom: centerY + height / 2 };\n};\n\n/** The room (px) between a node's edge and its pill. */\nconst PILL_GAP = 5;\n\n/** A pill's height (px) on one line and on two: the stylesheet's, and a little to spare. */\nconst PILL_HEIGHT = { 1: 21, 2: 35 } as const;\n\n/** How round a pill's corners are (px): half a one-line pill's height (the stylesheet rounds two-line pills by 11 px). */\nconst PILL_CORNER = 10.5;\n\n/**\n * How far from its node's center a pill toward `direction` sits. A pill is\n * placed by its point that matches its side: the middle of its top when it's\n * below the node, the middle of its left end when it's to the right, and on a\n * slant a point between them, inside the pill. That point sits past the node's\n * edge by the gap, which keeps a pill on a side clear of its node, but on a\n * slant the pill's nearest end would reach back over it: there the pill sits\n * farther out, as far as that end keeps the same gap.\n */\nexport const pillDistance = (screenRadius: number, direction: Point, width: number, lines: 1 | 2): number => {\n const gap = screenRadius + PILL_GAP;\n const corner = Math.min(PILL_CORNER, width / 2);\n const x = Math.abs(direction.x);\n const y = Math.abs(direction.y);\n // Placed `distance` from the node's center, the pill has the center of its nearest corner's rounding\n // `distance * x - backX` across and `distance * y - backY` up or down from the node's center. It keeps\n // the gap while that point keeps the gap and the rounding from the node's center (or, once the pill\n // reaches across the node's middle, while its straight side does).\n const backX = ((1 - x) * width) / 2 - corner;\n const backY = ((1 - y) * PILL_HEIGHT[lines]) / 2 - corner;\n const clearance = gap + corner;\n\n if (keepsClear(gap, x, y, backX, backY, clearance)) {\n return gap;\n }\n\n // Otherwise it first keeps the gap where its rounded corner does, where its top or bottom does (a wide\n // pill across the node's middle) or where its end does: the nearest of these that keeps it.\n const along = backX * x + backY * y;\n const cornerDistance = along + Math.sqrt(Math.max(0, along * along + clearance * clearance - backX * backX - backY * backY));\n const sideDistance = y > 0 ? (clearance + backY) / y : Infinity;\n const endDistance = x > 0 ? (clearance + backX) / x : Infinity;\n let distance = Infinity;\n\n if (keepsClear(cornerDistance, x, y, backX, backY, clearance)) {\n distance = cornerDistance;\n }\n\n if (sideDistance < distance && keepsClear(sideDistance, x, y, backX, backY, clearance)) {\n distance = sideDistance;\n }\n\n if (endDistance < distance && keepsClear(endDistance, x, y, backX, backY, clearance)) {\n distance = endDistance;\n }\n\n // One of them always does, give or take rounding.\n return Number.isFinite(distance) ? distance : gap;\n};\n\n/** Whether a pill `distance` from its node's center keeps the gap, give or take a thousandth of a pixel (see `pillDistance`). */\nconst keepsClear = (distance: number, x: number, y: number, backX: number, backY: number, clearance: number): boolean => {\n return Math.hypot(Math.max(0, distance * x - backX), Math.max(0, distance * y - backY)) >= clearance - 0.001;\n};\n\n/** The size (px) of a pill's text, as the stylesheet sets it. */\nconst PILL_FONT_SIZE = 11.5;\n\ninterface PillMeasure {\n /** The text's width on one line (px). */\n oneLine: number;\n\n /** The longer line's width when the text breaks where its two lines balance best. */\n twoLines: number;\n\n /** Whether the text can break onto a second line: at a space, or between CJK characters. */\n wraps: boolean;\n}\n\n/**\n * Pill measurements by font and text. Labels are planned every frame while\n * the map moves, but their text rarely changes, and measuring it means\n * splitting it into characters.\n */\nconst pillMeasures = new Map<string, PillMeasure>();\n/** More texts than the largest maps have; past it, the measurements start over. */\nconst PILL_MEASURES_LIMIT = 20000;\n\n// Measurements start over when a font finishes loading.\nonMeasurementsReset(() => pillMeasures.clear());\n\nconst measurePill = (text: string, measure: TextMeasure): PillMeasure => {\n const key = `${measure.key}\\n${text}`;\n const cached = pillMeasures.get(key);\n\n if (cached) {\n return cached;\n }\n\n const width = (part: string) => measure.ems(part, PILL_FONT_SIZE) * PILL_FONT_SIZE;\n const oneLine = width(text);\n const units = breakUnits(text);\n let twoLines = oneLine;\n\n for (let index = 1; index < units.length; index += 1) {\n const first = width(joinUnits(units.slice(0, index)));\n const second = width(joinUnits(units.slice(index)));\n twoLines = Math.min(twoLines, Math.max(first, second));\n }\n\n if (pillMeasures.size >= PILL_MEASURES_LIMIT) {\n pillMeasures.clear();\n }\n\n const measured = { oneLine, twoLines, wraps: units.length > 1 };\n pillMeasures.set(key, measured);\n return measured;\n};\n\nconst canWrap = (text: string, measure: TextMeasure): boolean => {\n return measurePill(text, measure).wraps;\n};\n\n/** A pill's text width (px): on two lines, its longer line when it breaks where the two balance best. Estimated, unless `measure` measures it. */\nexport const pillTextWidth = (text: string, lines: 1 | 2, measure: TextMeasure = PILL_ESTIMATE): number => {\n const measured = measurePill(text, measure);\n return lines === 1 ? measured.oneLine : measured.twoLines;\n};\n\n/** Side of a cell of the grid that finds what a label spot covers (px). */\nconst GRID_CELL = 64;\n/** The grid reaches a little past the map's edges, so boxes along them fall in its cells. */\nconst GRID_MARGIN = 8;\n\n/**\n * Items bucketed by where their boxes sit on the map, so a label spot only\n * checks the bodies and labels near it. Only the map (and its margin) is\n * covered: spots are checked against it only when they fit on the map.\n */\nclass ScreenGrid<Item> {\n private readonly cells = new Map<number, Item[]>();\n private readonly columns: number;\n private readonly rows: number;\n private readonly seen = new Set<Item>();\n\n constructor(viewport: Viewport) {\n this.columns = Math.max(1, Math.ceil((viewport.width + 2 * GRID_MARGIN) / GRID_CELL));\n this.rows = Math.max(1, Math.ceil((viewport.height + 2 * GRID_MARGIN) / GRID_CELL));\n }\n\n add(item: Item, box: Box): void {\n this.visitCells(box, (key) => {\n const cell = this.cells.get(key);\n\n if (cell) {\n cell.push(item);\n } else {\n this.cells.set(key, [item]);\n }\n\n return false;\n });\n }\n\n /** Whether `test` holds for any item near `box`. */\n some(box: Box, test: (item: Item) => boolean): boolean {\n return this.visitCells(box, (key) => this.cells.get(key)?.some(test) ?? false);\n }\n\n /** The sum of `value` over the items near `box`, each counted once. */\n sum(box: Box, value: (item: Item) => number): number {\n let total = 0;\n this.seen.clear();\n\n this.visitCells(box, (key) => {\n for (const item of this.cells.get(key) ?? []) {\n if (!this.seen.has(item)) {\n this.seen.add(item);\n total += value(item);\n }\n }\n\n return false;\n });\n\n return total;\n }\n\n /** Calls `visit` with each cell `box` touches, until it returns true. */\n private visitCells(box: Box, visit: (key: number) => boolean): boolean {\n const firstColumn = Math.max(0, Math.floor((box.left + GRID_MARGIN) / GRID_CELL));\n const lastColumn = Math.min(this.columns - 1, Math.floor((box.right + GRID_MARGIN) / GRID_CELL));\n const firstRow = Math.max(0, Math.floor((box.top + GRID_MARGIN) / GRID_CELL));\n const lastRow = Math.min(this.rows - 1, Math.floor((box.bottom + GRID_MARGIN) / GRID_CELL));\n\n for (let row = firstRow; row <= lastRow; row += 1) {\n for (let column = firstColumn; column <= lastColumn; column += 1) {\n if (visit(row * this.columns + column)) {\n return true;\n }\n }\n }\n\n return false;\n }\n}\n\n/**\n * How far a pill above or below a node near the edge slides sideways to\n * stay on the map, as long as it still reaches past the node's center.\n */\nconst horizontalNudge = (box: Box, nodeX: number, viewport: Viewport): number => {\n const shift = box.left < 0 ? -box.left : box.right > viewport.width ? viewport.width - box.right : 0;\n const left = box.left + shift;\n const right = box.right + shift;\n return nodeX >= left + NUDGE_REACH && nodeX <= right - NUDGE_REACH ? shift : 0;\n};\n\nconst isOffScreen = (point: Point, radius: number, viewport: Viewport): boolean => {\n return point.x + radius < -OFF_SCREEN_MARGIN || point.x - radius > viewport.width + OFF_SCREEN_MARGIN\n || point.y + radius < -OFF_SCREEN_MARGIN || point.y - radius > viewport.height + OFF_SCREEN_MARGIN;\n};\n\n/** How far (px) a label box may reach past the map's edges: boxes are worked out in fractions of a pixel. */\nconst ROUNDING = 0.5;\n\n/** Whether a label box fits on the map, all of it: a pill is drawn as wide as its box, or narrower. */\nconst insideViewport = (box: Box, viewport: Viewport): boolean => {\n return box.left >= -ROUNDING && box.top >= -ROUNDING && box.right <= viewport.width + ROUNDING && box.bottom <= viewport.height + ROUNDING;\n};\n\nconst overlaps = (first: Box, second: Box): boolean => {\n return first.left < second.right && second.left < first.right && first.top < second.bottom && second.top < first.bottom;\n};\n\nconst discOverlapsBox = (disc: Point & { radius: number }, box: Box): boolean => {\n const nearestX = Math.min(box.right, Math.max(box.left, disc.x));\n const nearestY = Math.min(box.bottom, Math.max(box.top, disc.y));\n const dx = disc.x - nearestX;\n const dy = disc.y - nearestY;\n return dx * dx + dy * dy < disc.radius * disc.radius;\n};\n\nconst distance = (first: Point, second: Point): number => {\n return Math.hypot(first.x - second.x, first.y - second.y);\n};\n",
|
|
51
|
+
"/**\n * A theme's `surface-pattern` (CSS backgrounds) drawn as SVG, so exported\n * pictures keep the wallpaper glass shows through, a starfield or a grid.\n * Reads the kinds of layers Orbit's own themes use: radial gradients of one\n * color fading out, `linear-gradient` lines tiled by a size, and tiled\n * images. A layer of any other kind is left out of the picture.\n */\n\nimport { splitAlpha } from './colors.js';\n\nexport interface PatternLayers {\n /** `<defs>` entries the layers use. */\n definitions: string[];\n\n /** One full-size rectangle per layer, bottom layer first. */\n layers: string[];\n}\n\n/**\n * The layers of `pattern` for a picture `width` × `height`, with ids made\n * from `prefix`. `color` resolves a theme color to a plain value.\n */\nexport const patternLayers = (pattern: string, width: number, height: number, prefix: string, color: (value: string) => string): PatternLayers => {\n const definitions: string[] = [];\n const layers: string[] = [];\n\n // CSS draws the first layer on top: SVG paints in order, so they go last first.\n splitLayers(pattern).reverse().forEach((layer, index) => {\n const id = `${prefix}-surface-${index}`;\n const drawn = radialLayer(layer, width, height, id, color) ?? lineLayer(layer, id, color) ?? imageLayer(layer, id);\n\n if (drawn) {\n definitions.push(drawn);\n layers.push(`<rect width=\"${width}\" height=\"${height}\" fill=\"url(#${id})\"/>`);\n }\n });\n\n return { definitions, layers };\n};\n\n/** The layers of a CSS background list, split at the commas between them. */\nexport const splitLayers = (value: string): string[] => {\n const layers: string[] = [];\n let depth = 0;\n let quote = '';\n let start = 0;\n\n for (let index = 0; index < value.length; index += 1) {\n const character = value[index];\n\n if (quote) {\n quote = character === quote ? '' : quote;\n } else if (character === '\"' || character === \"'\") {\n quote = character;\n } else if (character === '(') {\n depth += 1;\n } else if (character === ')') {\n depth -= 1;\n } else if (character === ',' && depth === 0) {\n layers.push(value.slice(start, index).trim());\n start = index + 1;\n }\n }\n\n layers.push(value.slice(start).trim());\n return layers.filter((layer) => layer !== '' && layer !== 'none');\n};\n\n/** The arguments inside `name(…)`, split at their top-level commas. */\nconst argumentsOf = (layer: string, name: string): string[] | null => {\n const open = layer.indexOf(`${name}(`);\n\n if (open !== 0) {\n return null;\n }\n\n let depth = 0;\n\n for (let index = name.length; index < layer.length; index += 1) {\n if (layer[index] === '(') {\n depth += 1;\n } else if (layer[index] === ')') {\n depth -= 1;\n\n if (depth === 0) {\n return splitLayers(layer.slice(name.length + 1, index));\n }\n }\n }\n\n return null;\n};\n\n/** `radial-gradient(70% 55% at 12% 14%, <color>, transparent 70%)`: an ellipse of one color fading out. */\nconst radialLayer = (layer: string, width: number, height: number, id: string, color: (value: string) => string): string | null => {\n const parts = argumentsOf(layer, 'radial-gradient');\n\n if (!parts || parts.length < 3) {\n return null;\n }\n\n const shape = /^(\\d+(?:\\.\\d+)?)%\\s+(\\d+(?:\\.\\d+)?)%\\s+at\\s+(\\d+(?:\\.\\d+)?)%\\s+(\\d+(?:\\.\\d+)?)%$/.exec(parts[0]);\n\n if (!shape) {\n return null;\n }\n\n const [radiusX, radiusY, x, y] = shape.slice(1).map(Number);\n\n const stops = parts.slice(1).map((part, index, all) => {\n const match = /^(.*?)(?:\\s+(\\d+(?:\\.\\d+)?)%)?$/.exec(part)!;\n const offset = match[2] !== undefined ? Number(match[2]) / 100 : index / (all.length - 1);\n return { color: match[1].trim(), offset };\n });\n\n // Faded to `transparent`, a stop keeps the color it fades from, so the edge doesn't go grey.\n const solid = stops.find((stop) => stop.color !== 'transparent')?.color ?? 'transparent';\n const centerX = (x / 100) * width;\n const centerY = (y / 100) * height;\n const rx = (radiusX / 100) * width;\n const ry = (radiusY / 100) * height;\n\n if (rx <= 0 || ry <= 0) {\n return null;\n }\n\n const stopElements = stops.map((stop) => {\n const { color: value, opacity } = stop.color === 'transparent' ? { color: splitAlpha(color(solid)).color, opacity: 0 } : splitAlpha(color(stop.color));\n return `<stop offset=\"${round(stop.offset)}\" stop-color=\"${escapeXml(value)}\" stop-opacity=\"${round(opacity)}\"/>`;\n });\n\n return `<radialGradient id=\"${id}\" gradientUnits=\"userSpaceOnUse\" cx=\"${round(centerX)}\" cy=\"${round(centerY)}\" r=\"${round(rx)}\" gradientTransform=\"translate(${round(centerX)} ${round(centerY)}) scale(1 ${round(ry / rx)}) translate(${round(-centerX)} ${round(-centerY)})\">${stopElements.join('')}</radialGradient>`;\n};\n\n/** `linear-gradient([90deg, ]<color> 1px, transparent 1px) 0 0 / 120px 120px`: a line along each tile's top (or left) edge. */\nconst lineLayer = (layer: string, id: string, color: (value: string) => string): string | null => {\n const parts = argumentsOf(layer, 'linear-gradient');\n const tile = /\\)\\s*0\\s+0\\s*\\/\\s*(\\d+(?:\\.\\d+)?)px\\s+(\\d+(?:\\.\\d+)?)px\\s*$/.exec(layer);\n\n if (!parts || !tile) {\n return null;\n }\n\n const vertical = parts[0] === '90deg';\n const stops = vertical ? parts.slice(1) : parts;\n const line = /^(.*?)\\s+(\\d+(?:\\.\\d+)?)px$/.exec(stops[0] ?? '');\n\n if (!line || stops.length !== 2 || !/^transparent\\s/.test(stops[1])) {\n return null;\n }\n\n const [tileWidth, tileHeight] = [Number(tile[1]), Number(tile[2])];\n const thickness = Number(line[2]);\n const { color: value, opacity } = splitAlpha(color(line[1].trim()));\n const rect = vertical ? `width=\"${thickness}\" height=\"${tileHeight}\"` : `width=\"${tileWidth}\" height=\"${thickness}\"`;\n return `<pattern id=\"${id}\" patternUnits=\"userSpaceOnUse\" width=\"${tileWidth}\" height=\"${tileHeight}\"><rect ${rect} fill=\"${escapeXml(value)}\" fill-opacity=\"${round(opacity)}\"/></pattern>`;\n};\n\n/** `url(\"data:image/svg+xml,…\") 0 0 / 640px 640px`: an image tiled at its size. */\nconst imageLayer = (layer: string, id: string): string | null => {\n // The image's own markup may hold the other kind of quote: the URL ends at its closing quote and `)`.\n const match = /^url\\(([\"']?)(data:image\\/.+?)\\1\\)\\s*0\\s+0\\s*\\/\\s*(\\d+(?:\\.\\d+)?)px\\s+(\\d+(?:\\.\\d+)?)px$/s.exec(layer);\n\n if (!match) {\n return null;\n }\n\n const [source, tileWidth, tileHeight] = [match[2], match[3], match[4]];\n return `<pattern id=\"${id}\" patternUnits=\"userSpaceOnUse\" width=\"${tileWidth}\" height=\"${tileHeight}\"><image href=\"${escapeXml(source)}\" width=\"${tileWidth}\" height=\"${tileHeight}\"/></pattern>`;\n};\n\nconst round = (value: number): number => {\n return Math.round(value * 1000) / 1000;\n};\n\nconst escapeXml = (text: string): string => {\n return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n};\n",
|
|
52
|
+
"/**\n * Standalone SVG for a display. Every color is resolved to a plain value,\n * labels are SVG text and nothing depends on the page's stylesheet, so the\n * file looks the same in any viewer or editor.\n */\n\nimport type { Display, DisplayNode } from './display.js';\nimport { worldToScreen, type Viewport } from './camera.js';\nimport { mixOklab, parseColor, prefersLightText, resolveColor, splitAlpha, toHex } from './colors.js';\nimport { SHADE_STOPS, SHADOW_BLUR, drawsFlat, insideLabelLayout, nodeThumbnail, readShadeCircle, ringPath } from './views.js';\nimport { labelOrder, outsideLabelBox, planLabels, type PlannedLabel } from './labels.js';\nimport { hasMediaSource } from '../media.js';\nimport { statusTone } from '../ui/detail-sheet.js';\nimport type { MapExtensions } from '../extensions.js';\nimport type { OrbitWords } from '../languages.js';\nimport { wrapText } from '../text-layout.js';\nimport { patternLayers } from './surface-pattern.js';\nimport { ESTIMATED_LABELS, type LabelMeasures } from './text-measure.js';\nimport { guardUrl, resolveUrl } from '../url-guard.js';\n\nexport interface ExportOptions {\n viewport: Viewport;\n\n /** Concrete theme values, keyed by token name (`surface`, `color-1`, …). */\n tokens: Record<string, string>;\n\n showRings: boolean;\n title: string;\n\n /** The fill the page resolved for a node, when it is on screen. */\n fills?: (node: DisplayNode) => string;\n\n baseUrl?: string;\n\n /** Size the SVG to its container (100% wide and tall) instead of in pixels. */\n responsive?: boolean;\n\n /** Prefix for the SVG's ids; give each SVG inlined in one page its own. */\n idPrefix?: string;\n\n /** The map's node types and status words, for icons, status colors and type tokens. */\n extensions?: MapExtensions;\n\n /** Measures names in the fonts the map draws them with, so labels break as on the live map; by default, widths are estimated. */\n measures?: LabelMeasures;\n\n /** The map's words, for the name of an idea without text. Default: English. */\n words?: OrbitWords;\n}\n\nconst ROLE_ORDER = { moon: 0, node: 1, planet: 1, sun: 2 } as const;\nconst FONT_SIZE = { sun: 16, planet: 13, node: 12, moon: 13 } as const;\nconst LINES = { sun: 3, planet: 2, node: 2, moon: 2 } as const;\n\n/** Theme values read as plain colors, numbers and mixes. */\nclass ThemeReader {\n readonly tokens: Record<string, string>;\n\n constructor(tokens: Record<string, string>) {\n this.tokens = tokens;\n }\n\n value(name: string, fallback = ''): string {\n return this.tokens[name] ?? fallback;\n }\n\n color(value: string): string {\n return resolveColor(value, this.tokens);\n }\n\n token(name: string, fallback = '#000000'): string {\n return this.color(this.value(name, fallback));\n }\n\n number(name: string, fallback: number): number {\n const parsed = Number.parseFloat(this.value(name));\n return Number.isFinite(parsed) ? parsed : fallback;\n }\n\n /** `color-mix(in oklab, own <tint>, <base token>)`, as the stylesheet mixes rims, shadows, rings and links. */\n tinted(own: string, base: string, tint: string): string {\n const ownColor = parseColor(this.color(own));\n const baseColor = parseColor(this.token(base));\n const amount = this.number(tint, 0) / 100;\n\n if (!ownColor || !baseColor) {\n return this.token(base);\n }\n\n return toHex(mixOklab(ownColor, baseColor, Math.min(1, Math.max(0, amount))));\n }\n}\n\n/**\n * `fill=\"#rrggbb\" fill-opacity=\"…\"`: the color's alpha times `opacity`, written\n * apart for design tools. A color Orbit can't read is written as given (SVG\n * takes any CSS color), escaped, since maps and themes can hold any text.\n */\nconst paint = (kind: 'fill' | 'stroke' | 'stop', color: string, opacity = 1): string => {\n const { color: value, opacity: alpha } = splitAlpha(color);\n const hex = escapeXml(value);\n const total = round(alpha * opacity);\n const name = kind === 'stop' ? 'stop-color' : kind;\n const opacityName = kind === 'stop' ? 'stop-opacity' : `${kind}-opacity`;\n return total < 1 || kind === 'stop' ? `${name}=\"${hex}\" ${opacityName}=\"${total}\"` : `${name}=\"${hex}\"`;\n};\n\nconst dashAttribute = (dash: string): string => {\n return dash.trim() === '' || dash.trim() === 'none' ? '' : ` stroke-dasharray=\"${escapeXml(dash.trim())}\"`;\n};\n\nexport const exportDisplay = (display: Display | null, options: ExportOptions): string => {\n const { viewport } = options;\n const theme = new ThemeReader(options.tokens);\n const width = Math.round(viewport.width);\n const height = Math.round(viewport.height);\n const prefix = escapeXml(options.idPrefix ?? 'orbit-export');\n const untitled = options.words?.text('untitled') ?? 'Untitled';\n const size = options.responsive ? 'width=\"100%\" height=\"100%\" preserveAspectRatio=\"xMidYMid meet\"' : `width=\"${width}\" height=\"${height}\"`;\n const parts: string[] = [\n `<svg xmlns=\"http://www.w3.org/2000/svg\" ${size} viewBox=\"0 0 ${width} ${height}\" role=\"img\" aria-label=\"${escapeXml(options.title)}\">`,\n `<title>${escapeXml(options.title)}</title>`,\n ];\n const definitions: string[] = [shadeGradient(`${prefix}-shade`, theme)];\n const body: string[] = [];\n // The surface color, and the theme's pattern over it: the wallpaper glass shows through, stars, a grid.\n const surface = theme.token('surface', 'transparent');\n const surfaceColor = parseColor(surface);\n\n if (surfaceColor && surfaceColor.alpha > 0) {\n body.push(`<rect width=\"${width}\" height=\"${height}\" ${paint('fill', surface)}/>`);\n }\n\n const pattern = patternLayers(theme.value('surface-pattern', 'none'), width, height, prefix, (value) => theme.color(value));\n definitions.push(...pattern.definitions);\n body.push(...pattern.layers);\n\n if (display) {\n const { camera } = display;\n const place = (node: { x: number; y: number }) => worldToScreen(camera, viewport, node);\n\n if (options.showRings) {\n const ringOpacity = theme.number('ring-opacity', 0.5);\n const ringWidth = theme.number('ring-width', 1.5);\n const ringDash = dashAttribute(theme.value('ring-dash', 'none'));\n\n for (const ring of display.rings) {\n if (ring.opacity <= 0.01) {\n continue;\n }\n\n const center = place({ x: ring.cx, y: ring.cy });\n const d = ringPath(ring.radius * camera.scale, ring.gaps);\n const stroke = theme.tinted(ring.color, 'ring-stroke', 'ring-tint');\n body.push(`<path d=\"${d}\" transform=\"translate(${round(center.x)} ${round(center.y)}) rotate(${round(ring.rotation)})\" fill=\"none\" ${paint('stroke', stroke, ringOpacity)} stroke-width=\"${ringWidth}\"${ringDash} stroke-linecap=\"round\"/>`);\n }\n }\n\n const linkOpacity = theme.number('link-opacity', 0.5);\n const linkWidth = theme.number('link-width', 1.5);\n const linkDash = dashAttribute(theme.value('link-dash', 'none'));\n\n for (const link of display.links) {\n const from = display.nodes.get(link.fromId);\n const to = display.nodes.get(link.toId);\n\n if (!from || !to) {\n continue;\n }\n\n const start = place(from);\n const end = place(to);\n const length = Math.hypot(end.x - start.x, end.y - start.y);\n const fromRadius = from.radius * camera.scale;\n const toRadius = to.radius * camera.scale;\n\n if (length <= fromRadius + toRadius) {\n continue;\n }\n\n const unitX = (end.x - start.x) / length;\n const unitY = (end.y - start.y) / length;\n const stroke = theme.tinted(link.color, 'link-stroke', 'link-tint');\n body.push(`<line x1=\"${round(start.x + unitX * fromRadius)}\" y1=\"${round(start.y + unitY * fromRadius)}\" x2=\"${round(end.x - unitX * toRadius)}\" y2=\"${round(end.y - unitY * toRadius)}\" ${paint('stroke', stroke, linkOpacity)} stroke-width=\"${linkWidth}\"${linkDash} stroke-linecap=\"round\"/>`);\n }\n\n const nodes = Array.from(display.nodes.values())\n .filter((node) => node.opacity > 0.01 && node.radius > 0)\n .sort((left, right) => ROLE_ORDER[left.role] - ROLE_ORDER[right.role]);\n const fills = new Map<string, string>();\n const pictures = new Set<string>();\n // A node type's tokens win over the theme for its nodes.\n const typeThemes = new Map<string, ThemeReader>();\n\n const themeFor = (node: DisplayNode): ThemeReader => {\n const tokens = options.extensions?.nodeType(node.node)?.tokens;\n const type = options.extensions?.typeName(node.node) ?? node.node.type;\n\n if (!tokens || !type) {\n return theme;\n }\n\n const key = type.toLowerCase();\n let reader = typeThemes.get(key);\n\n if (!reader) {\n const own = Object.fromEntries(Object.entries(tokens).filter((entry): entry is [string, string] => typeof entry[1] === 'string' && entry[1] !== ''));\n reader = new ThemeReader({ ...options.tokens, ...own });\n typeThemes.set(key, reader);\n }\n\n return reader;\n };\n\n const hasShadow = (node: DisplayNode) => node.role !== 'node'\n && !drawsFlat(node, node.radius * camera.scale)\n && themeFor(node).number(node.role === 'sun' ? 'sun-shadow-opacity' : 'node-shadow-opacity', 0) > 0;\n\n if (nodes.some(hasShadow)) {\n for (const [id, blur] of [[`${prefix}-shadow`, SHADOW_BLUR.planet], [`${prefix}-sun-shadow`, SHADOW_BLUR.sun]] as const) {\n definitions.push(`<filter id=\"${id}\" x=\"-60%\" y=\"-60%\" width=\"220%\" height=\"220%\"><feGaussianBlur stdDeviation=\"${blur}\"/></filter>`);\n }\n }\n\n nodes.forEach((node, index) => {\n const nodeTheme = themeFor(node);\n const center = place(node);\n const radius = node.radius * camera.scale;\n const resolved = options.fills?.(node);\n const own = resolved ? nodeTheme.color(resolved) : nodeTheme.color(node.color);\n fills.set(node.id, own);\n const isSun = node.role === 'sun';\n const fillOpacity = nodeTheme.number('node-fill-opacity', 1);\n const strokeWidth = nodeTheme.number('node-stroke-width', 1.5);\n\n if (hasShadow(node)) {\n const shadow = nodeTheme.tinted(own, 'node-shadow', 'node-shadow-tint');\n const opacity = nodeTheme.number(isSun ? 'sun-shadow-opacity' : 'node-shadow-opacity', 0);\n const scale = radius * nodeTheme.number(isSun ? 'sun-shadow-size' : 'node-shadow-size', 1);\n const offset = radius * nodeTheme.number('node-shadow-offset', 0);\n // A unit circle, scaled like the live map's, so one blur fits every size.\n body.push(`<circle r=\"1\" transform=\"translate(${round(center.x)} ${round(center.y + offset)}) scale(${round(scale, 3)})\" ${paint('fill', shadow, opacity)} filter=\"url(#${prefix}-${isSun ? 'sun-shadow' : 'shadow'})\"/>`);\n }\n\n if (isSun) {\n body.push(...halo(center, radius, own, nodeTheme));\n }\n\n const circle = `cx=\"${round(center.x)}\" cy=\"${round(center.y)}\" r=\"${round(radius)}\"`;\n body.push(`<circle ${circle} ${paint('fill', own, node.role === 'moon' ? nodeTheme.number('moon-opacity', fillOpacity) : fillOpacity)}/>`);\n const thumbnail = nodeThumbnail(node.node);\n const source = thumbnail ? guardUrl(thumbnail, 'image') : null;\n\n if (source) {\n pictures.add(node.id);\n const clip = `${prefix}-clip-${index}`;\n definitions.push(`<clipPath id=\"${clip}\"><circle ${circle}/></clipPath>`);\n body.push(`<image href=\"${escapeXml(resolveUrl(source, options.baseUrl))}\" x=\"${round(center.x - radius)}\" y=\"${round(center.y - radius)}\" width=\"${round(radius * 2)}\" height=\"${round(radius * 2)}\" preserveAspectRatio=\"xMidYMid slice\" clip-path=\"url(#${clip})\"/>`);\n }\n\n const rim = nodeTheme.tinted(own, 'node-stroke', 'node-stroke-tint');\n // A crowded orbit's rims grow with their planets, as on the live map.\n const rimWidth = node.crowded ? strokeWidth * 0.04 * radius : node.role === 'moon' ? strokeWidth * 0.7 : strokeWidth;\n body.push(`<circle ${circle} fill=\"url(#${prefix}-shade)\" ${paint('stroke', rim)} stroke-width=\"${round(rimWidth)}\"/>`);\n body.push(...badges(node, center, radius, nodeTheme, options.extensions));\n });\n\n const iconOf = (entry: DisplayNode) => (options.extensions ? options.extensions.icon(entry.node) : entry.node.icon);\n const measures = options.measures ?? ESTIMATED_LABELS;\n const planned = planLabels(display, labelOrder(nodes), {\n viewport,\n hasImage: (entry) => pictures.has(entry.id),\n hasIcon: (entry) => Boolean(iconOf(entry)),\n // A picture fills the node: its icon goes on the pill, as on the live map.\n pillIcon: (entry) => (pictures.has(entry.id) ? iconOf(entry) : undefined),\n measures,\n });\n\n for (const plan of planned) {\n body.push(...exportLabel(plan, fills.get(plan.entry.id) ?? '#ffffff', themeFor(plan.entry), iconOf(plan.entry), measures, untitled));\n }\n }\n\n parts.push(`<defs>${definitions.join('')}</defs>`, ...body, '</svg>');\n return parts.join('');\n};\n\n/** The sphere shading, with the stops the stylesheet colors from the theme. */\nconst shadeGradient = (id: string, theme: ThemeReader): string => {\n const highlight = theme.token('node-highlight', 'rgba(255, 255, 255, 0.5)');\n const terminator = theme.token('node-terminator', 'rgba(0, 0, 0, 0)');\n const shading = theme.token('node-shading', 'rgba(0, 0, 0, 0.12)');\n\n const stops = SHADE_STOPS.map(({ offset, part }) => {\n switch (part) {\n case 'highlight':\n return `<stop offset=\"${offset}\" ${paint('stop', highlight)}/>`;\n case 'highlight-fade':\n return `<stop offset=\"${offset}\" ${paint('stop', highlight, 0.2)}/>`;\n case 'terminator-start':\n return `<stop offset=\"${offset}\" ${paint('stop', terminator, 0)}/>`;\n case 'terminator':\n return `<stop offset=\"${offset}\" ${paint('stop', terminator)}/>`;\n default:\n return `<stop offset=\"${offset}\" ${paint('stop', shading)}/>`;\n }\n });\n\n const circle = readShadeCircle(theme.value('node-shade-circle', ''));\n return `<radialGradient id=\"${id}\" cx=\"${circle.x}\" cy=\"${circle.y}\" r=\"${circle.radius}\">${stops.join('')}</radialGradient>`;\n};\n\n/** The ring the theme draws around the sun, if any. */\nconst halo = (center: { x: number; y: number }, radius: number, own: string, theme: ThemeReader): string[] => {\n const opacity = theme.number('sun-halo-opacity', 0);\n const width = theme.number('sun-halo-width', 0);\n\n if (opacity <= 0 || width <= 0) {\n return [];\n }\n\n const stroke = theme.tinted(own, 'sun-halo', 'sun-halo-tint');\n const dash = dashAttribute(theme.value('sun-halo-dash', 'none'));\n return [`<circle cx=\"${round(center.x)}\" cy=\"${round(center.y)}\" r=\"${round(radius * theme.number('sun-halo-size', 1.15))}\" fill=\"none\" ${paint('stroke', stroke, opacity)} stroke-width=\"${width}\"${dash}/>`];\n};\n\n/** Status dot, content marker and video badge, placed as on the live map. */\nconst badges = (node: DisplayNode, center: { x: number; y: number }, radius: number, theme: ThemeReader, extensions?: MapExtensions): string[] => {\n const parts: string[] = [];\n const stroke = paint('stroke', theme.token('badge-stroke', '#ffffff'));\n const isSun = node.role === 'sun';\n\n if (node.node.status && radius > 6) {\n const offset = (isSun ? 0.68 : 0.72) * radius;\n const look = extensions?.status(node.node.status) ?? { tone: statusTone(node.node.status) };\n const color = look.color ?? theme.token(`status-${look.tone}`, '#94a3b8');\n parts.push(`<circle cx=\"${round(center.x + offset)}\" cy=\"${round(center.y - offset)}\" r=\"${round((isSun ? 0.11 : 0.17) * radius)}\" ${paint('fill', color)} ${stroke} stroke-width=\"${round((isSun ? 0.025 : 0.04) * radius)}\"/>`);\n }\n\n // The focused node's buttons offer its content, so it has no marker or badge.\n if (isSun || radius <= 8) {\n return parts;\n }\n\n if (hasMediaSource(node.node.video)) {\n const x = center.x + 0.62 * radius;\n const y = center.y + 0.62 * radius;\n const size = 0.3 * radius;\n parts.push(`<circle cx=\"${round(x)}\" cy=\"${round(y)}\" r=\"${round(size)}\" fill=\"#0f172a\" fill-opacity=\"0.62\"/>`);\n parts.push(`<path d=\"M${round(x - 0.32 * size)} ${round(y - 0.48 * size)} L${round(x + 0.52 * size)} ${round(y)} L${round(x - 0.32 * size)} ${round(y + 0.48 * size)} Z\" fill=\"#ffffff\"/>`);\n } else if (node.node.note || hasMediaSource(node.node.image) || hasMediaSource(node.node.embed) || node.node.link || extensions?.nodeType(node.node)?.details) {\n parts.push(`<circle cx=\"${round(center.x + 0.72 * radius)}\" cy=\"${round(center.y + 0.72 * radius)}\" r=\"${round(0.13 * radius)}\" ${paint('fill', theme.token('note-indicator', '#1b2333'))} ${stroke} stroke-width=\"${round(0.04 * radius)}\"/>`);\n }\n\n return parts;\n};\n\nconst exportLabel = (plan: PlannedLabel, fill: string, theme: ThemeReader, icon: string | undefined, measures: LabelMeasures, untitled: string): string[] => {\n const { entry, x, y, screenRadius } = plan;\n const text = entry.node.text || untitled;\n const isSun = entry.role === 'sun';\n const font = escapeXml(theme.value(isSun ? 'display-font' : 'label-font', theme.value('font-family', 'sans-serif')));\n const weight = escapeXml(theme.value(isSun ? 'display-weight' : 'label-weight', isSun ? '650' : '600'));\n const letterSpacing = theme.value('label-letter-spacing', '0').trim();\n const spacing = letterSpacing === '0' || letterSpacing === '' || letterSpacing === 'normal' ? '' : ` letter-spacing=\"${escapeXml(letterSpacing)}\"`;\n const opacity = plan.opacity >= 0.999 ? '' : ` opacity=\"${round(plan.opacity)}\"`;\n const inside = plan.placement === 'inside' ? insideLabelLayout(entry.role, screenRadius, text, Boolean(icon), measures.inside(entry.role, entry.node)) : null;\n\n if (plan.placement === 'outside') {\n const fontSize = 11.5;\n const lineCount = plan.lines;\n const pill = measures.pill(entry.role, entry.node);\n // The pill's own text: the name, after the node's icon when a picture fills the node.\n const pillText = plan.text || untitled;\n const box = outsideLabelBox(pillText, { x, y }, screenRadius, plan.direction, isSun ? 280 : 160, plan.offset, lineCount, pill);\n const width = box.right - box.left;\n const pillLines = wrapText(pillText, width - 12, fontSize, lineCount, pill).lines;\n const middle = (box.top + box.bottom) / 2;\n const height = lineCount === 1 ? 20 : 34;\n const lineHeight = 14;\n const firstBaseline = middle - ((pillLines.length - 1) * lineHeight) / 2 + fontSize * 0.36;\n const spans = pillLines\n .map((line, index) => `<tspan x=\"${round((box.left + box.right) / 2)}\" y=\"${round(firstBaseline + index * lineHeight)}\">${escapeXml(line)}</tspan>`)\n .join('');\n return [\n `<g${opacity}>`,\n `<rect x=\"${round(box.left)}\" y=\"${round(middle - height / 2)}\" width=\"${round(width)}\" height=\"${height}\" rx=\"10\" ${paint('fill', theme.token('control-background', '#ffffff'))}/>`,\n `<text text-anchor=\"middle\" font-family=\"${font}\" font-size=\"${fontSize}\" font-weight=\"${weight}\"${spacing} ${paint('fill', theme.token('control-text', '#1b2333'))}>${spans}</text>`,\n '</g>',\n ];\n }\n\n const fontSize = inside?.fontSize ?? FONT_SIZE[entry.role];\n // The lines the live map shows; a label that doesn't fit falls back to wrapping at the usual width.\n const textLines = inside?.lines ?? wrapText(text, screenRadius * 1.68, fontSize, LINES[entry.role], measures.inside(entry.role, entry.node)).lines;\n const lines = icon && (inside?.icon ?? true) ? [icon, ...textLines] : textLines;\n const lineHeight = fontSize * 1.22;\n const lightText = theme.token('node-text-inverse', '#ffffff');\n const darkText = theme.token(isSun ? 'root-text' : 'node-text', '#1b2333');\n const textColor = prefersLightText(fill, lightText, darkText) ? lightText : darkText;\n const firstBaseline = y - ((lines.length - 1) * lineHeight) / 2 + fontSize * 0.35;\n const spans = lines\n .map((line, index) => `<tspan x=\"${round(x)}\" y=\"${round(firstBaseline + index * lineHeight)}\">${escapeXml(line)}</tspan>`)\n .join('');\n // A name drawn narrower to fit, as on the live map.\n const stretch = inside?.stretch ? ` font-stretch=\"${inside.stretch}%\"` : '';\n return [`<text text-anchor=\"middle\" font-family=\"${font}\" font-size=\"${fontSize}\" font-weight=\"${weight}\"${stretch}${spacing} ${paint('fill', textColor)}${opacity}>${spans}</text>`];\n};\n\nexport const escapeXml = (value: string): string => {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n};\n\nconst round = (value: number, decimals = 2): number => {\n const factor = 10 ** decimals;\n return Math.round(value * factor) / factor;\n};\n",
|
|
53
|
+
"/**\n * Map controls: real, themable buttons in an HTML layer over the map.\n * Wide containers show breadcrumbs; narrow ones a back chip with the\n * parent's name (switched by a container query in the stylesheet).\n */\n\nimport type { OrbitNode, ViewMode } from '../types.js';\nimport type { OrbitWords } from '../languages.js';\nimport { pointsCoarsely } from '../browser.js';\nimport { createIcon, type IconName } from './icons.js';\n\nexport interface ControlsCallbacks {\n onNavigate(nodeId: string): void;\n onViewMode(mode: ViewMode): void;\n onZoom(direction: 1 | -1): void;\n onFit(): void;\n onToggleOutline(): void;\n}\n\nexport interface ControlsState {\n viewMode: ViewMode;\n\n /** From the root to the focused node. */\n path: OrbitNode[];\n\n outlineOpen: boolean;\n}\n\n/** Breadcrumbs longer than this collapse their middle into \"…\". */\nconst MAXIMUM_CRUMBS = 4;\n\n/**\n * The zoom buttons' panel, as the stylesheet draws it: this far from the\n * map's lower right corner (`.orbit-controls__zoom`), and three icon buttons\n * 2 px apart in 3 px of padding and a 1 px border (`.orbit-panel`), 32 px\n * each, or 40 px where the page is used with a finger (`.orbit-button--icon`).\n */\nconst ZOOM_PANEL_INSET = 12;\nconst ZOOM_PANEL = { width: 40, height: 108 };\nconst COARSE_ZOOM_PANEL = { width: 48, height: 132 };\n\n/** A rectangle on the map, in px from its top left corner. */\nexport interface ScreenBox {\n left: number;\n top: number;\n right: number;\n bottom: number;\n}\n\nexport class Controls {\n readonly element: HTMLDivElement;\n private readonly callbacks: ControlsCallbacks;\n private readonly back: HTMLButtonElement;\n private readonly backLabel: HTMLSpanElement;\n private readonly breadcrumbs: HTMLElement;\n private readonly breadcrumbPanel: HTMLDivElement;\n private readonly viewGroup: HTMLDivElement;\n private readonly focusButton: HTMLButtonElement;\n private readonly overviewButton: HTMLButtonElement;\n private readonly outlineButton: HTMLButtonElement;\n private readonly zoomPanel: HTMLDivElement;\n private readonly zoomInButton: HTMLButtonElement;\n private readonly fitButton: HTMLButtonElement;\n private readonly zoomOutButton: HTMLButtonElement;\n private readonly hint: HTMLDivElement;\n private hintTimer: ReturnType<typeof setTimeout> | null = null;\n private parentId: string | null = null;\n private words: OrbitWords;\n private state: ControlsState | null = null;\n\n constructor(callbacks: ControlsCallbacks, words: OrbitWords) {\n this.callbacks = callbacks;\n this.words = words;\n this.element = element('div', 'orbit-controls');\n\n const top = element('div', 'orbit-controls__top');\n const start = element('div', 'orbit-controls__start');\n\n this.back = button('orbit-button orbit-panel orbit-back', 'back');\n this.backLabel = element('span', '');\n this.back.appendChild(this.backLabel);\n\n this.back.addEventListener('click', () => {\n if (this.parentId) {\n this.callbacks.onNavigate(this.parentId);\n }\n });\n\n this.breadcrumbPanel = element('div', 'orbit-panel orbit-controls__crumbs');\n this.breadcrumbs = element('nav', 'orbit-breadcrumbs');\n this.breadcrumbPanel.appendChild(this.breadcrumbs);\n start.append(this.back, this.breadcrumbPanel);\n\n this.viewGroup = element('div', 'orbit-panel');\n this.viewGroup.setAttribute('role', 'group');\n this.focusButton = labelledButton('focus');\n this.focusButton.addEventListener('click', () => this.callbacks.onViewMode('focus'));\n this.overviewButton = labelledButton('overview');\n this.overviewButton.addEventListener('click', () => this.callbacks.onViewMode('all'));\n this.outlineButton = iconButton('list', () => this.callbacks.onToggleOutline());\n this.viewGroup.append(this.focusButton, this.overviewButton, this.outlineButton);\n top.append(start, this.viewGroup);\n\n const zoom = element('div', 'orbit-controls__zoom');\n this.zoomPanel = element('div', 'orbit-panel orbit-panel--vertical');\n this.zoomPanel.setAttribute('role', 'group');\n this.zoomInButton = iconButton('zoom-in', () => this.callbacks.onZoom(1));\n this.fitButton = iconButton('fit', () => this.callbacks.onFit());\n this.zoomOutButton = iconButton('zoom-out', () => this.callbacks.onZoom(-1));\n this.zoomPanel.append(this.zoomInButton, this.fitButton, this.zoomOutButton);\n zoom.appendChild(this.zoomPanel);\n\n this.hint = element('div', 'orbit-hint');\n this.hint.setAttribute('role', 'status');\n\n this.element.append(top, zoom, this.hint);\n this.relabel(words);\n }\n\n /** Writes every label in `words`' language. */\n relabel(words: OrbitWords): void {\n this.words = words;\n this.breadcrumbs.setAttribute('aria-label', words.text('mapPath'));\n this.viewGroup.setAttribute('aria-label', words.text('view'));\n setLabel(this.focusButton, words.text('focus'));\n setLabel(this.overviewButton, words.text('overview'));\n setLabel(this.outlineButton, words.text('showOutline'));\n this.zoomPanel.setAttribute('aria-label', words.text('zoom'));\n setLabel(this.zoomInButton, words.text('zoomIn'));\n setLabel(this.fitButton, words.text('fitMap'));\n setLabel(this.zoomOutButton, words.text('zoomOut'));\n\n if (this.state) {\n this.update(this.state);\n }\n }\n\n update(state: ControlsState): void {\n this.state = state;\n this.focusButton.setAttribute('aria-pressed', String(state.viewMode === 'focus'));\n this.overviewButton.setAttribute('aria-pressed', String(state.viewMode === 'all'));\n this.outlineButton.setAttribute('aria-pressed', String(state.outlineOpen));\n\n const showPath = state.viewMode === 'focus' && state.path.length > 1;\n const parent = showPath ? state.path[state.path.length - 2] : null;\n this.parentId = parent?.id ?? null;\n this.back.hidden = !parent;\n this.backLabel.textContent = parent ? parent.text || this.words.text('back') : '';\n this.back.setAttribute('aria-label', parent?.text ? this.words.text('backTo', { name: parent.text }) : parent ? this.words.text('backToParent') : this.words.text('back'));\n this.breadcrumbPanel.hidden = !showPath;\n this.breadcrumbs.replaceChildren(...(showPath ? this.crumbs(state.path) : []));\n }\n\n /**\n * Where the zoom buttons are on a map `width` by `height` px, known\n * without laying them out, or null while the controls are hidden.\n */\n zoomBox(width: number, height: number): ScreenBox | null {\n if (this.element.hidden) {\n return null;\n }\n\n const panel = pointsCoarsely(this.element) ? COARSE_ZOOM_PANEL : ZOOM_PANEL;\n const right = width - ZOOM_PANEL_INSET;\n const bottom = height - ZOOM_PANEL_INSET;\n return { left: right - panel.width, top: bottom - panel.height, right, bottom };\n }\n\n /** Shows a short message at the bottom of the map. */\n showHint(text: string, duration = 1800): void {\n this.hint.textContent = text;\n this.hint.classList.add('orbit-hint--visible');\n\n if (this.hintTimer) {\n clearTimeout(this.hintTimer);\n }\n\n this.hintTimer = setTimeout(() => {\n this.hint.classList.remove('orbit-hint--visible');\n this.hintTimer = null;\n }, duration);\n }\n\n destroy(): void {\n if (this.hintTimer) {\n clearTimeout(this.hintTimer);\n }\n\n this.element.remove();\n }\n\n private crumbs(path: OrbitNode[]): HTMLElement[] {\n const indexes = path.length > MAXIMUM_CRUMBS\n ? [0, -1, path.length - 2, path.length - 1]\n : path.map((_, index) => index);\n const items: HTMLElement[] = [];\n\n indexes.forEach((pathIndex, position) => {\n if (position > 0) {\n const separator = createIcon('chevron');\n separator.classList.add('orbit-breadcrumbs__separator');\n items.push(separator as unknown as HTMLElement);\n }\n\n if (pathIndex === -1) {\n const ellipsis = element('span', 'orbit-button orbit-breadcrumbs__item');\n ellipsis.textContent = '…';\n ellipsis.title = path.slice(1, path.length - 2).map((node) => node.text).join(' › ');\n items.push(ellipsis);\n return;\n }\n\n const node = path[pathIndex];\n const isCurrent = pathIndex === path.length - 1;\n const crumb = element('button', 'orbit-button orbit-breadcrumbs__item');\n crumb.type = 'button';\n\n if (pathIndex === 0) {\n crumb.appendChild(createIcon('home'));\n }\n\n const label = element('span', '');\n label.textContent = node.text || this.words.text('untitled');\n crumb.appendChild(label);\n crumb.title = node.text;\n\n if (isCurrent) {\n crumb.setAttribute('aria-current', 'location');\n crumb.disabled = true;\n } else {\n crumb.addEventListener('click', () => this.callbacks.onNavigate(node.id));\n }\n\n items.push(crumb);\n });\n\n return items;\n }\n}\n\nconst element = <Name extends keyof HTMLElementTagNameMap>(name: Name, className: string): HTMLElementTagNameMap[Name] => {\n const created = document.createElement(name);\n\n if (className) {\n created.className = className;\n }\n\n return created;\n};\n\nconst button = (className: string, icon: IconName): HTMLButtonElement => {\n const created = element('button', className);\n created.type = 'button';\n created.appendChild(createIcon(icon));\n return created;\n};\n\n/** A button with its icon and its label beside it, which `setLabel` writes. */\nconst labelledButton = (icon: IconName): HTMLButtonElement => {\n const created = button('orbit-button', icon);\n created.appendChild(element('span', 'orbit-segmented__label'));\n return created;\n};\n\nconst iconButton = (icon: IconName, onClick: () => void): HTMLButtonElement => {\n const created = button('orbit-button orbit-button--icon', icon);\n created.addEventListener('click', onClick);\n return created;\n};\n\n/** A button's name, its tooltip and the label beside its icon, if it has one. */\nconst setLabel = (target: HTMLButtonElement, label: string): void => {\n target.setAttribute('aria-label', label);\n target.title = label;\n const text = target.querySelector('.orbit-segmented__label');\n\n if (text) {\n text.textContent = label;\n }\n};\n",
|
|
54
|
+
"/**\n * The map as a nested list. Screen readers can always browse it (it is\n * visually hidden but present), the list button shows it to everyone, and\n * a polite live region announces where navigation landed.\n */\n\nimport type { OrbitNode } from '../types.js';\nimport type { OrbitWords } from '../languages.js';\nimport { overlayTransform } from '../browser.js';\n\nexport class AccessibleOutline {\n readonly element: HTMLElement;\n readonly live: HTMLDivElement;\n private readonly onSelect: (nodeId: string) => void;\n private visible = false;\n private icon: (node: OrbitNode) => string | undefined = (node) => node.icon;\n\n /** Each node's entry, so moving between nodes only moves the current marker. */\n private readonly entries = new Map<string, HTMLElement>();\n\n private currentId: string | null = null;\n private words: OrbitWords;\n\n constructor(onSelect: (nodeId: string) => void, words: OrbitWords) {\n this.onSelect = onSelect;\n this.words = words;\n this.element = document.createElement('nav');\n this.element.className = 'orbit-outline orbit-visually-hidden';\n this.live = document.createElement('div');\n this.live.className = 'orbit__live';\n this.live.setAttribute('aria-live', 'polite');\n this.live.setAttribute('role', 'status');\n this.relabel(words);\n }\n\n /** Names the list in `words`' language; the next `update` writes its entries in it. */\n relabel(words: OrbitWords): void {\n this.words = words;\n this.element.setAttribute('aria-label', words.text('outline'));\n }\n\n get isVisible(): boolean {\n return this.visible;\n }\n\n /**\n * Rebuilds the list. Without `interactive`, entries are plain text instead\n * of buttons. `icon` gives a node's icon, its type's when it has none.\n */\n update(\n tree: OrbitNode,\n focusId: string | null,\n maxDepth: number | undefined,\n interactive: boolean,\n icon: (node: OrbitNode) => string | undefined = (node) => node.icon,\n ): void {\n this.icon = icon;\n this.entries.clear();\n this.currentId = null;\n const list = document.createElement('ul');\n list.appendChild(this.item(tree, maxDepth, interactive));\n this.element.replaceChildren(list);\n this.setCurrent(focusId);\n }\n\n /** Marks the focused node's entry, without rebuilding the list: a big map's outline has thousands. */\n setCurrent(focusId: string | null): void {\n if (focusId === this.currentId) {\n return;\n }\n\n if (this.currentId !== null) {\n this.entries.get(this.currentId)?.removeAttribute('aria-current');\n }\n\n this.currentId = focusId;\n\n if (focusId !== null) {\n this.entries.get(focusId)?.setAttribute('aria-current', 'true');\n }\n }\n\n setVisible(visible: boolean): void {\n this.visible = visible;\n this.element.classList.toggle('orbit-visually-hidden', !visible);\n this.element.classList.toggle('orbit-outline--visible', visible);\n\n for (const button of this.element.querySelectorAll('button')) {\n button.tabIndex = visible ? 0 : -1;\n }\n\n if (visible) {\n this.element.querySelector<HTMLButtonElement>('[aria-current=\"true\"]')?.focus();\n }\n }\n\n announce(text: string): void {\n // Clear first so repeating the same announcement still speaks.\n this.live.textContent = '';\n\n setTimeout(() => {\n this.live.textContent = text;\n }, 30);\n }\n\n private item(node: OrbitNode, maxDepth: number | undefined, interactive: boolean): HTMLLIElement {\n const item = document.createElement('li');\n const entry = document.createElement(interactive ? 'button' : 'span');\n entry.textContent = [this.icon(node), node.text || this.words.text('untitled')].filter(Boolean).join(' ');\n\n if (node.status) {\n entry.textContent += ` (${node.status})`;\n }\n\n if (!this.entries.has(node.id)) {\n this.entries.set(node.id, entry);\n }\n\n if (entry instanceof HTMLButtonElement) {\n entry.type = 'button';\n entry.tabIndex = this.visible ? 0 : -1;\n entry.addEventListener('click', () => this.onSelect(node.id));\n }\n\n item.appendChild(entry);\n const showChildren = maxDepth === undefined || node.level < maxDepth;\n\n if (showChildren && node.children.length > 0) {\n const children = document.createElement('ul');\n\n for (const child of node.children) {\n children.appendChild(this.item(child, maxDepth, interactive));\n }\n\n item.appendChild(children);\n }\n\n return item;\n }\n}\n\n/** A hover and keyboard-focus tooltip for nodes. */\nexport class Tooltip {\n readonly element: HTMLDivElement;\n private readonly title: HTMLSpanElement;\n private readonly detail: HTMLSpanElement;\n\n constructor() {\n this.element = document.createElement('div');\n this.element.className = 'orbit-tooltip';\n this.element.setAttribute('role', 'tooltip');\n this.element.setAttribute('aria-hidden', 'true');\n this.title = document.createElement('span');\n this.title.className = 'orbit-tooltip__title';\n this.detail = document.createElement('span');\n this.detail.className = 'orbit-tooltip__detail';\n this.element.append(this.title, this.detail);\n }\n\n get isVisible(): boolean {\n return this.element.classList.contains('orbit-tooltip--visible');\n }\n\n show(title: string, detail: string, x: number, y: number): void {\n this.title.textContent = title;\n this.detail.textContent = detail;\n this.detail.hidden = detail === '';\n this.place(x, y);\n this.element.classList.add('orbit-tooltip--visible');\n }\n\n /** Puts the tooltip's tip at `x`, `y`, the tooltip centered above it. */\n place(x: number, y: number): void {\n this.element.style.transform = overlayTransform(Math.round(x), Math.round(y), '-50%, calc(-100% - 10px)');\n }\n\n hide(): void {\n this.element.classList.remove('orbit-tooltip--visible');\n }\n}\n",
|
|
55
|
+
"/**\n * Videos in the media viewer, behind one interface: a file plays in a\n * `<video>` element, and YouTube and Vimeo in their own players, framed and\n * driven through the messages those players take (the same ones their\n * JavaScript APIs send). A video on any other site is framed as the detail\n * sheet frames it, with nothing to drive.\n */\n\nimport type { OrbitNode } from '../types.js';\nimport { guardUrl, resolveUrl } from '../url-guard.js';\nimport { detectVideoProvider, isNativeVideoUrl, isYouTubeShort, toVideoEmbedUrl } from '../media.js';\nimport { embedFrame, playerFrame } from './frames.js';\n\n/** A video as it plays. */\nexport interface PlaybackState {\n /** Playing, rather than paused, not started yet, or ended. */\n playing: boolean;\n\n /** Seconds from the start. */\n time: number;\n\n /** Seconds, once known. */\n duration: number | null;\n\n /** It played to the end. */\n ended: boolean;\n\n /** Its sound is off. */\n muted: boolean;\n}\n\nexport interface MediaPlayer {\n /** What shows the video: a `<video>` element or a frame. */\n readonly element: HTMLVideoElement | HTMLIFrameElement;\n\n /** Width over height, as far as it's known yet. */\n readonly ratio: number;\n\n /** Whether `play`, `pause` and `seek` reach the video, and it reports its state. */\n readonly controllable: boolean;\n\n readonly state: PlaybackState;\n play(): void;\n pause(): void;\n\n /** Moves to `seconds` from the start. */\n seek(seconds: number): void;\n\n /** Turns its sound on. */\n unmute(): void;\n\n /** Shows or hides the player's own controls, where that can change while it plays. */\n setControls(controls: boolean): void;\n\n /** Stops the video and lets go of it. */\n destroy(): void;\n}\n\nexport interface PlayerOptions {\n /** Start playing as soon as it can. */\n autoplay: boolean;\n\n /** Show the player's own controls. */\n controls: boolean;\n\n /** Seconds into the video to start at. */\n startAt?: number;\n\n /** The frame's or video's accessible name. */\n title: string;\n\n /** A picture to show before a video file plays. */\n poster?: string;\n\n baseUrl?: string;\n\n /** It played, paused, moved on, ended or was muted. */\n onState(state: PlaybackState): void;\n\n /** It learned its width over height. */\n onRatio(ratio: number): void;\n\n /** A video file couldn't be played. */\n onError(): void;\n}\n\nconst WIDE = 16 / 9;\nconst UPRIGHT = 9 / 16;\n/** While a video plays, its time alone is reported at most this often (ms). */\nconst TIME_REPORT = 250;\n/** YouTube's player answers once it hears that someone listens: say so this often (ms), this many times. */\nconst LISTEN_INTERVAL = 250;\nconst LISTEN_TRIES = 40;\n/** YouTube's player states, from its API. */\nconst YOUTUBE_ENDED = 0;\nconst YOUTUBE_PLAYING = 1;\nconst YOUTUBE_BUFFERING = 3;\nconst VIMEO_EVENTS = ['play', 'playing', 'pause', 'ended', 'timeupdate', 'seeked', 'volumechange'];\n\n/**\n * The player for a node's video, or null when its URL isn't allowed. Files\n * (`.mp4`, `.webm`, `.mov`, `blob:` URLs, or `provider: native`) play in a\n * `<video>` element; YouTube and Vimeo in their players.\n */\nexport const createPlayer = (video: NonNullable<OrbitNode['video']>, options: PlayerOptions): MediaPlayer | null => {\n const guarded = guardUrl(video.src, 'video');\n\n if (!guarded) {\n return null;\n }\n\n const source = resolveUrl(guarded, options.baseUrl);\n const provider = video.provider === 'youtube' || video.provider === 'vimeo' || video.provider === 'native' ? video.provider : detectVideoProvider(source);\n\n if (provider === 'native' || isNativeVideoUrl(source) || /^blob:/i.test(source)) {\n return new FilePlayer(source, options);\n }\n\n const embed = provider === 'youtube' || provider === 'vimeo' ? toVideoEmbedUrl(source, provider) : null;\n\n if (embed && provider === 'youtube') {\n const frame = playerFrame(youTubeAddress(embed, options), options.title);\n return frame ? new YouTubePlayer(frame, options, isYouTubeShort(source) ? UPRIGHT : WIDE) : null;\n }\n\n if (embed && provider === 'vimeo') {\n const frame = playerFrame(vimeoAddress(embed, options), options.title);\n return frame ? new VimeoPlayer(frame, options) : null;\n }\n\n const frame = embedFrame(source, options.baseUrl, options.title);\n return frame ? new PagePlayer(frame) : null;\n};\n\n/** YouTube's player, taking messages from this page and answering them, and starting on its own if asked. */\nconst youTubeAddress = (embed: string, options: PlayerOptions): string => {\n const url = new URL(embed);\n url.searchParams.set('enablejsapi', '1');\n url.searchParams.set('autoplay', options.autoplay ? '1' : '0');\n url.searchParams.set('playsinline', '1');\n url.searchParams.set('rel', '0');\n\n if (!options.controls) {\n url.searchParams.set('controls', '0');\n }\n\n const start = wholeSeconds(options.startAt);\n\n if (start > 0) {\n url.searchParams.set('start', String(start));\n }\n\n const origin = pageOrigin();\n\n if (origin) {\n url.searchParams.set('origin', origin);\n }\n\n return url.href;\n};\n\nconst vimeoAddress = (embed: string, options: PlayerOptions): string => {\n const url = new URL(embed);\n url.searchParams.set('autoplay', options.autoplay ? '1' : '0');\n url.searchParams.set('playsinline', '1');\n // Vimeo's player without its tracking, as YouTube's comes from youtube-nocookie.com.\n url.searchParams.set('dnt', '1');\n\n if (!options.controls) {\n url.searchParams.set('controls', '0');\n }\n\n const start = wholeSeconds(options.startAt);\n\n if (start > 0) {\n url.hash = `t=${start}s`;\n }\n\n return url.href;\n};\n\n/** A time to start at, as the players' addresses take it: whole seconds, 0 for none. */\nconst wholeSeconds = (seconds: number | undefined): number => {\n return Number.isFinite(seconds) ? Math.max(0, Math.floor(seconds as number)) : 0;\n};\n\n/** The page's origin, which YouTube's player sends its messages to; none for pages without one (files). */\nconst pageOrigin = (): string | null => {\n if (typeof location === 'undefined' || !/^https?:$/.test(location.protocol)) {\n return null;\n }\n\n return location.origin;\n};\n\n/**\n * Reports a player's state: at once when it starts, pauses, ends, is muted,\n * learns its length or jumps to another time, and otherwise at most every\n * `TIME_REPORT` ms while it plays.\n */\nclass StateReporter {\n private last: PlaybackState | null = null;\n private lastAt = 0;\n private readonly listener: (state: PlaybackState) => void;\n\n constructor(listener: (state: PlaybackState) => void) {\n this.listener = listener;\n }\n\n report(state: PlaybackState): void {\n const now = performance.now();\n const last = this.last;\n\n if (last) {\n const same = last.playing === state.playing && last.ended === state.ended && last.muted === state.muted && last.duration === state.duration;\n const expected = last.time + (last.playing ? (now - this.lastAt) / 1000 : 0);\n const jumped = Math.abs(state.time - expected) > 1;\n\n if (same && !jumped && (state.time === last.time || now - this.lastAt < TIME_REPORT)) {\n return;\n }\n }\n\n this.last = { ...state };\n this.lastAt = now;\n this.listener({ ...state });\n }\n}\n\nconst VIDEO_EVENTS = ['loadedmetadata', 'durationchange', 'play', 'playing', 'pause', 'ended', 'seeked', 'timeupdate', 'volumechange', 'error'];\n\nclass FilePlayer implements MediaPlayer {\n readonly element: HTMLVideoElement;\n readonly controllable = true;\n ratio = WIDE;\n private readonly options: PlayerOptions;\n private readonly reporter: StateReporter;\n private startAt: number;\n\n constructor(source: string, options: PlayerOptions) {\n this.options = options;\n this.reporter = new StateReporter(options.onState);\n this.startAt = Number.isFinite(options.startAt) ? Math.max(0, options.startAt as number) : 0;\n const video = document.createElement('video');\n this.element = video;\n video.className = 'orbit-viewer__video';\n video.controls = options.controls;\n video.playsInline = true;\n video.setAttribute('playsinline', '');\n video.preload = 'metadata';\n\n if (options.autoplay) {\n video.autoplay = true;\n video.setAttribute('autoplay', '');\n }\n\n if (options.poster) {\n video.setAttribute('poster', options.poster);\n }\n\n video.setAttribute('aria-label', options.title);\n\n for (const type of VIDEO_EVENTS) {\n video.addEventListener(type, this.handleEvent);\n }\n\n video.src = source;\n\n if (options.autoplay) {\n this.play();\n }\n }\n\n get state(): PlaybackState {\n const video = this.element;\n return {\n playing: !video.paused && !video.ended,\n time: Number.isFinite(video.currentTime) ? video.currentTime : 0,\n duration: Number.isFinite(video.duration) && video.duration > 0 ? video.duration : null,\n ended: video.ended,\n muted: video.muted,\n };\n }\n\n play(): void {\n const video = this.element;\n const attempt = video.play() as Promise<void> | undefined;\n\n // A browser that won't let a video start with sound before the reader\n // has interacted with the page lets it start muted.\n attempt?.catch?.((error: unknown) => {\n if ((error as { name?: string } | null)?.name === 'NotAllowedError' && !video.muted) {\n video.muted = true;\n (video.play() as Promise<void> | undefined)?.catch?.(() => undefined);\n }\n });\n }\n\n pause(): void {\n this.element.pause();\n }\n\n seek(seconds: number): void {\n if (Number.isFinite(seconds)) {\n this.element.currentTime = Math.max(0, seconds);\n }\n }\n\n unmute(): void {\n const video = this.element;\n video.muted = false;\n\n if (video.volume === 0) {\n video.volume = 1;\n }\n }\n\n setControls(controls: boolean): void {\n this.element.controls = controls;\n }\n\n destroy(): void {\n const video = this.element;\n\n for (const type of VIDEO_EVENTS) {\n video.removeEventListener(type, this.handleEvent);\n }\n\n video.pause();\n // Letting go of the source stops the download too.\n video.removeAttribute('src');\n\n try {\n video.load();\n } catch {\n // Some environments can't load media at all.\n }\n }\n\n private readonly handleEvent = (event: Event): void => {\n const video = this.element;\n\n if (event.type === 'error') {\n this.options.onError();\n return;\n }\n\n if (event.type === 'loadedmetadata') {\n if (video.videoWidth > 0 && video.videoHeight > 0) {\n this.ratio = video.videoWidth / video.videoHeight;\n this.options.onRatio(this.ratio);\n }\n\n if (this.startAt > 0) {\n video.currentTime = this.startAt;\n this.startAt = 0;\n }\n }\n\n this.reporter.report(this.state);\n };\n}\n\n/** A player in a frame, from another origin: what it says arrives as messages. */\nabstract class FramedPlayer implements MediaPlayer {\n readonly element: HTMLIFrameElement;\n readonly controllable = true;\n ratio: number;\n protected readonly options: PlayerOptions;\n protected readonly reporter: StateReporter;\n protected readonly current: PlaybackState = { playing: false, time: 0, duration: null, ended: false, muted: false };\n\n /** Where the player's messages come from, and where ours go. */\n protected readonly origin: string;\n\n /** The player answered: what's sent now reaches it. */\n protected ready = false;\n\n private queue: unknown[] = [];\n private autoplayed = false;\n private readonly owner: Window | null;\n\n constructor(frame: HTMLIFrameElement, options: PlayerOptions, ratio: number) {\n this.element = frame;\n this.options = options;\n this.ratio = ratio;\n this.reporter = new StateReporter(options.onState);\n this.origin = new URL(frame.src).origin;\n this.owner = frame.ownerDocument.defaultView ?? (typeof window === 'undefined' ? null : window);\n this.owner?.addEventListener('message', this.handleMessage);\n frame.addEventListener('load', this.handleLoad);\n }\n\n get state(): PlaybackState {\n return { ...this.current };\n }\n\n abstract play(): void;\n abstract pause(): void;\n abstract seek(seconds: number): void;\n abstract unmute(): void;\n\n setControls(): void {\n // A framed player takes its controls from its address: changing them would reload it.\n }\n\n destroy(): void {\n this.owner?.removeEventListener('message', this.handleMessage);\n this.element.removeEventListener('load', this.handleLoad);\n this.queue = [];\n }\n\n /** The frame loaded: the player may have said it's ready already, or wait to be asked. */\n protected abstract loaded(): void;\n\n /** A message from the player. */\n protected abstract received(message: Record<string, unknown>): void;\n\n /** The message that starts the video. */\n protected abstract playMessage(): unknown;\n\n /** Sends a message to the player, or keeps it until the player answers. */\n protected send(message: unknown): void {\n if (this.ready) {\n this.post(message);\n } else {\n this.queue.push(message);\n }\n }\n\n protected post(message: unknown): void {\n this.element.contentWindow?.postMessage(message, this.origin);\n }\n\n /** The player answered: start it if asked to, then send what was waiting. */\n protected becomeReady(): void {\n if (this.ready) {\n return;\n }\n\n this.ready = true;\n\n if (this.options.autoplay && !this.autoplayed) {\n this.autoplayed = true;\n this.post(this.playMessage());\n }\n\n const waiting = this.queue;\n this.queue = [];\n\n for (const message of waiting) {\n this.post(message);\n }\n }\n\n protected report(): void {\n this.reporter.report(this.current);\n }\n\n private readonly handleLoad = (): void => {\n this.loaded();\n };\n\n private readonly handleMessage = (event: MessageEvent): void => {\n if (event.source !== this.element.contentWindow || event.origin !== this.origin) {\n return;\n }\n\n const message = readMessage(event.data);\n\n if (message) {\n this.received(message);\n }\n };\n}\n\nclass YouTubePlayer extends FramedPlayer {\n private static channels = 0;\n\n /** This player's id in the messages, as YouTube's API numbers its players. */\n private readonly channel = ++YouTubePlayer.channels;\n\n private listening: ReturnType<typeof setInterval> | null = null;\n\n play(): void {\n this.command('playVideo');\n }\n\n pause(): void {\n this.command('pauseVideo');\n }\n\n seek(seconds: number): void {\n if (Number.isFinite(seconds)) {\n this.command('seekTo', [Math.max(0, seconds), true]);\n }\n }\n\n unmute(): void {\n this.command('unMute');\n }\n\n destroy(): void {\n this.stopListening();\n super.destroy();\n }\n\n protected playMessage(): unknown {\n return this.message('playVideo');\n }\n\n protected loaded(): void {\n // YouTube's player only talks to a page that says it listens: say so\n // until it answers, as YouTube's own API does.\n this.stopListening();\n\n if (this.ready) {\n return;\n }\n\n let tries = 0;\n const listen = () => this.post(JSON.stringify({ event: 'listening', id: this.channel, channel: 'widget' }));\n listen();\n\n this.listening = setInterval(() => {\n tries += 1;\n\n if (tries >= LISTEN_TRIES || this.ready) {\n this.stopListening();\n return;\n }\n\n listen();\n }, LISTEN_INTERVAL);\n }\n\n protected received(message: Record<string, unknown>): void {\n switch (message.event) {\n case 'initialDelivery':\n case 'onReady':\n case 'infoDelivery':\n this.stopListening();\n this.becomeReady();\n this.apply(message.info);\n break;\n case 'onStateChange':\n if (typeof message.info === 'number') {\n this.apply({ playerState: message.info });\n }\n\n break;\n }\n }\n\n private apply(info: unknown): void {\n if (!info || typeof info !== 'object') {\n return;\n }\n\n const values = info as Record<string, unknown>;\n const state = this.current;\n\n if (typeof values.currentTime === 'number' && Number.isFinite(values.currentTime)) {\n state.time = values.currentTime;\n }\n\n if (typeof values.duration === 'number' && values.duration > 0) {\n state.duration = values.duration;\n }\n\n if (typeof values.muted === 'boolean') {\n state.muted = values.muted;\n }\n\n if (typeof values.playerState === 'number' && values.playerState !== YOUTUBE_BUFFERING) {\n // Buffering keeps whether it's playing.\n state.playing = values.playerState === YOUTUBE_PLAYING;\n state.ended = values.playerState === YOUTUBE_ENDED;\n }\n\n this.report();\n }\n\n private command(func: string, args: unknown[] = []): void {\n this.send(this.message(func, args));\n }\n\n private message(func: string, args: unknown[] = []): string {\n return JSON.stringify({ event: 'command', func, args, id: this.channel, channel: 'widget' });\n }\n\n private stopListening(): void {\n if (this.listening !== null) {\n clearInterval(this.listening);\n this.listening = null;\n }\n }\n}\n\nclass VimeoPlayer extends FramedPlayer {\n private width = 0;\n private height = 0;\n\n constructor(frame: HTMLIFrameElement, options: PlayerOptions) {\n super(frame, options, WIDE);\n }\n\n play(): void {\n this.send({ method: 'play' });\n }\n\n pause(): void {\n this.send({ method: 'pause' });\n }\n\n seek(seconds: number): void {\n if (Number.isFinite(seconds)) {\n this.send({ method: 'setCurrentTime', value: Math.max(0, seconds) });\n }\n }\n\n unmute(): void {\n this.send({ method: 'setMuted', value: false });\n }\n\n protected playMessage(): unknown {\n return { method: 'play' };\n }\n\n protected loaded(): void {\n // Vimeo's player answers a ping once it's ready, if it said so before this page listened.\n this.post({ method: 'ping' });\n }\n\n protected received(message: Record<string, unknown>): void {\n if (message.event === 'ready' || message.method === 'ping') {\n if (!this.ready) {\n for (const name of VIMEO_EVENTS) {\n this.post({ method: 'addEventListener', value: name });\n }\n\n for (const method of ['getDuration', 'getVideoWidth', 'getVideoHeight', 'getPaused', 'getMuted']) {\n this.post({ method });\n }\n }\n\n this.becomeReady();\n return;\n }\n\n const state = this.current;\n const data = message.data && typeof message.data === 'object' ? (message.data as Record<string, unknown>) : {};\n\n if (typeof data.seconds === 'number') {\n state.time = data.seconds;\n }\n\n if (typeof data.duration === 'number' && data.duration > 0) {\n state.duration = data.duration;\n }\n\n switch (message.event) {\n case 'play':\n case 'playing':\n state.playing = true;\n state.ended = false;\n break;\n case 'pause':\n state.playing = false;\n break;\n case 'ended':\n state.playing = false;\n state.ended = true;\n break;\n case 'volumechange':\n state.muted = data.muted === true || data.volume === 0;\n break;\n }\n\n switch (message.method) {\n case 'getDuration':\n if (typeof message.value === 'number' && message.value > 0) {\n state.duration = message.value;\n }\n\n break;\n case 'getPaused':\n if (typeof message.value === 'boolean') {\n state.playing = !message.value;\n }\n\n break;\n case 'getMuted':\n if (typeof message.value === 'boolean') {\n state.muted = message.value;\n }\n\n break;\n case 'getVideoWidth':\n case 'getVideoHeight':\n if (typeof message.value === 'number' && message.value > 0) {\n if (message.method === 'getVideoWidth') {\n this.width = message.value;\n } else {\n this.height = message.value;\n }\n\n if (this.width > 0 && this.height > 0) {\n this.ratio = this.width / this.height;\n this.options.onRatio(this.ratio);\n }\n }\n\n return;\n }\n\n this.report();\n }\n}\n\n/** A video on a site Orbit has no player for: framed, with nothing to drive. */\nclass PagePlayer implements MediaPlayer {\n readonly element: HTMLIFrameElement;\n readonly ratio = WIDE;\n readonly controllable = false;\n readonly state: PlaybackState = { playing: false, time: 0, duration: null, ended: false, muted: false };\n\n constructor(frame: HTMLIFrameElement) {\n this.element = frame;\n }\n\n play(): void {}\n\n pause(): void {}\n\n seek(): void {}\n\n unmute(): void {}\n\n setControls(): void {}\n\n destroy(): void {}\n}\n\n/** A message from a player: an object, or JSON text of one. */\nconst readMessage = (data: unknown): Record<string, unknown> | null => {\n let value = data;\n\n if (typeof value === 'string') {\n try {\n value = JSON.parse(value);\n } catch {\n return null;\n }\n }\n\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : null;\n};\n",
|
|
56
|
+
"/**\n * Geometry for pictures in the media viewer: fitting a picture to the\n * window, zooming around a point that stays where it is, and keeping a\n * zoomed picture over the stage while it is panned.\n *\n * Points are in px from the stage's center. A view is the picture's zoom\n * relative to its fitted size, and where its center is.\n */\n\nexport interface Size {\n width: number;\n height: number;\n}\n\nexport interface Point {\n x: number;\n y: number;\n}\n\n/** A picture shown `scale` times its fitted size, its center `x`, `y` px from the stage's center. */\nexport interface PictureView {\n scale: number;\n x: number;\n y: number;\n}\n\nexport const FITTED: PictureView = { scale: 1, x: 0, y: 0 };\n\n/** Fitting never draws a picture more than this many times its own size: a small one would only blur. */\nconst FIT_UPSCALE = 2;\n/** Zooming goes at least to this many times the fitted size… */\nconst ZOOM_IN = 4;\n/** …and on until the picture shows at this many times its own size. */\nconst OWN_SIZE_ZOOM = 2;\n/** A double click or tap zooms in at least this much. */\nconst DOUBLE_TAP_ZOOM = 2;\n\n/**\n * The size a picture is drawn at to fit `room`: as large as fits, but no\n * more than twice its own size, unless it's `scalable` (a vector picture).\n */\nexport const fittedSize = (natural: Size, room: Size, scalable = false): Size => {\n if (!(natural.width > 0 && natural.height > 0 && room.width > 0 && room.height > 0)) {\n return { width: 0, height: 0 };\n }\n\n let scale = Math.min(room.width / natural.width, room.height / natural.height);\n\n if (!scalable) {\n scale = Math.min(scale, FIT_UPSCALE);\n }\n\n return { width: natural.width * scale, height: natural.height * scale };\n};\n\n/** The furthest a picture zooms in, relative to its fitted size. */\nexport const maximumZoom = (natural: Size, fitted: Size): number => {\n if (!(fitted.width > 0 && natural.width > 0)) {\n return 1;\n }\n\n return Math.max(ZOOM_IN, (OWN_SIZE_ZOOM * natural.width) / fitted.width);\n};\n\n/**\n * `view` within its limits: zoomed between the fitted size and `maximum`,\n * and placed so a picture bigger than the stage leaves no gap at its edges,\n * while one smaller than the stage (in either direction) stays centered.\n */\nexport const clampView = (view: PictureView, fitted: Size, stage: Size, maximum: number): PictureView => {\n const scale = clamp(view.scale, 1, Math.max(1, maximum));\n const roomX = Math.max(0, (fitted.width * scale - stage.width) / 2);\n const roomY = Math.max(0, (fitted.height * scale - stage.height) / 2);\n // `|| 0` turns -0 into 0.\n return { scale, x: clamp(view.x, -roomX, roomX) || 0, y: clamp(view.y, -roomY, roomY) || 0 };\n};\n\n/**\n * Zooms by `factor`, keeping the point of the picture under `anchor` where\n * it is, as far as the limits allow.\n */\nexport const zoomAround = (view: PictureView, factor: number, anchor: Point, fitted: Size, stage: Size, maximum: number): PictureView => {\n const scale = clamp(view.scale * factor, 1, Math.max(1, maximum));\n const ratio = scale / view.scale;\n const zoomed = { scale, x: anchor.x - (anchor.x - view.x) * ratio, y: anchor.y - (anchor.y - view.y) * ratio };\n return clampView(zoomed, fitted, stage, maximum);\n};\n\n/** Moves the picture by `deltaX`, `deltaY`, as far as its edges allow. */\nexport const panView = (view: PictureView, deltaX: number, deltaY: number, fitted: Size, stage: Size, maximum: number): PictureView => {\n return clampView({ scale: view.scale, x: view.x + deltaX, y: view.y + deltaY }, fitted, stage, maximum);\n};\n\n/**\n * A double click or tap: back to the fitted view when zoomed in; otherwise\n * in at `anchor`, to the picture's own size, or to twice the fitted size\n * when that is further.\n */\nexport const toggleZoom = (view: PictureView, anchor: Point, natural: Size, fitted: Size, stage: Size, maximum: number): PictureView => {\n if (isZoomed(view)) {\n return FITTED;\n }\n\n const ownSize = fitted.width > 0 ? natural.width / fitted.width : 1;\n return zoomAround(view, Math.max(DOUBLE_TAP_ZOOM, ownSize) / view.scale, anchor, fitted, stage, maximum);\n};\n\n/** Whether the picture is zoomed in past its fitted size. */\nexport const isZoomed = (view: PictureView): boolean => {\n return view.scale > 1.001;\n};\n\nconst clamp = (value: number, minimum: number, maximum: number): number => {\n return Math.min(maximum, Math.max(minimum, value));\n};\n",
|
|
57
|
+
"/**\n * The media viewer: a node's picture or video over the whole window, to see\n * the one up close and to play the other. A native `<dialog>` opened as a\n * modal, so it sits in the top layer above a map of any size, keeps focus\n * inside and makes the page behind it inert.\n *\n * Pictures fit the window. The wheel, a pinch, a double click or tap, the\n * +, − and 0 keys and the zoom buttons zoom them around the point under the\n * pointer, and a zoomed picture pans with a drag. Previous and next step\n * through the map's pictures and videos in reading order; so do the arrow\n * keys and, on touch screens, a swipe, while the picture isn't zoomed. Esc,\n * a click around the media or a swipe down closes it.\n *\n * On a map that isn't interactive, the viewer is the page's to drive: no\n * buttons, no input of its own and no controls on videos.\n */\n\nimport type { OrbitNode } from '../types.js';\nimport type { OrbitWords } from '../languages.js';\nimport { guardUrl, resolveUrl } from '../url-guard.js';\nimport { detectVideoProvider, hasMediaSource, videoPageUrl } from '../media.js';\nimport { wheelZoomFactor } from '../input-controller.js';\nimport { createIcon, type IconName } from './icons.js';\nimport { createPlayer, type MediaPlayer, type PlaybackState } from './media-players.js';\nimport {\n FITTED,\n clampView,\n fittedSize,\n isZoomed,\n maximumZoom,\n panView,\n toggleZoom,\n zoomAround,\n type PictureView,\n type Point,\n type Size,\n} from './media-zoom.js';\n\nexport type MediaKind = 'image' | 'video';\n\n/** A node's picture or its video. */\nexport interface MediaItem {\n node: OrbitNode;\n kind: MediaKind;\n}\n\n/** What the viewer asks the map, and tells it. */\nexport interface MediaViewerContext {\n /** The map's pictures and videos, in reading order. */\n items(): MediaItem[];\n\n /** The map's node with this id, while it has one. */\n node(id: string): OrbitNode | null;\n\n baseUrl(): string | undefined;\n\n /** Whether the map takes input; without it, neither does the viewer. */\n interactive(): boolean;\n\n /** The icon before a node's title: its own, or its type's. */\n icon(node: OrbitNode): string | undefined;\n\n /** It shows `item`, `index` of `total`: as it opens, and at every step. */\n onShow(item: MediaItem, index: number, total: number): void;\n\n /** It closed while showing `item`. */\n onClose(item: MediaItem, index: number, total: number): void;\n\n /** The video it shows started, paused, moved on, ended or was muted. */\n onState(node: OrbitNode, state: PlaybackState): void;\n\n /** The map's words, in its language. */\n words(): OrbitWords;\n}\n\nexport interface MediaShowOptions {\n /** Start a video playing. Default true. */\n autoplay?: boolean;\n\n /** Start a video this many seconds in: where the detail sheet's player was, or where the page says. */\n startAt?: number;\n}\n\n/** Room (px) kept around the media… */\nconst MEDIA_MARGIN = 16;\n/** …and beside it on wide stages, for the previous and next buttons. */\nconst STEP_ROOM = 72;\nconst WIDE_STAGE = 720;\n/**\n * On narrower stages the buttons go over a picture's sides, but under a\n * video, clear of its player's own controls: a row this tall (px) for\n * buttons this big.\n */\nconst STEP_ROW = 60;\nconst STEP_SIZE = 44;\n/** Zoom per press of a zoom button, +, or −. */\nconst STEP_ZOOM = 1.5;\n/** The arrow keys pan a zoomed picture by this share of the stage. */\nconst KEY_PAN = 0.15;\n/** A press moves this far (px) before it's a drag, not a tap: a mouse, then a finger or pen. */\nconst MOUSE_SLOP = 4;\nconst TOUCH_SLOP = 8;\n/** A swipe across this far (px) steps to the previous or next item… */\nconst SWIPE_STEP = 60;\n/** …and one down this far closes the viewer. */\nconst SWIPE_CLOSE = 100;\nconst DOUBLE_TAP_TIME = 320;\nconst DOUBLE_TAP_DISTANCE = 28;\n/** Elements that handle presses themselves: gestures never start on them. */\nconst CONTROLS = 'button, a, video, iframe, input, select, textarea';\n\n/** Whether a node's picture or video can be shown: it has one, at a URL allowed there. */\nexport const showsMedia = (node: OrbitNode, kind: MediaKind): boolean => {\n if (kind === 'image') {\n return hasMediaSource(node.image) && guardUrl(node.image.src, 'image') !== null;\n }\n\n return hasMediaSource(node.video) && guardUrl(node.video.src, 'video') !== null;\n};\n\n/**\n * The map's pictures and videos in reading order: depth first, as the\n * outline lists the map, a node's picture before its video. Nodes below\n * `maxDepth` are left out, as they are from the map.\n */\nexport const galleryItems = (tree: OrbitNode, maxDepth?: number): MediaItem[] => {\n const items: MediaItem[] = [];\n const stack: OrbitNode[] = [tree];\n\n while (stack.length > 0) {\n const node = stack.pop() as OrbitNode;\n\n if (showsMedia(node, 'image')) {\n items.push({ node, kind: 'image' });\n }\n\n if (showsMedia(node, 'video')) {\n items.push({ node, kind: 'video' });\n }\n\n if (maxDepth === undefined || node.level < maxDepth) {\n for (let index = node.children.length - 1; index >= 0; index -= 1) {\n stack.push(node.children[index]);\n }\n }\n }\n\n return items;\n};\n\n/** The parts of the viewer, made once. */\ninterface ViewerParts {\n bar: HTMLElement;\n counter: HTMLElement;\n zoomOut: HTMLButtonElement;\n zoomIn: HTMLButtonElement;\n fit: HTMLButtonElement;\n zoomGroup: HTMLElement;\n link: HTMLAnchorElement;\n close: HTMLButtonElement;\n stage: HTMLElement;\n\n /** What the media sits in: it follows a swipe. */\n layer: HTMLElement;\n\n status: HTMLElement;\n previous: HTMLButtonElement;\n next: HTMLButtonElement;\n caption: HTMLElement;\n title: HTMLElement;\n text: HTMLElement;\n description: HTMLElement;\n}\n\ninterface Picture {\n element: HTMLImageElement;\n\n /** Its own size, once it's loaded. */\n natural: Size | null;\n\n /** A vector picture: it fits the window at any size. */\n scalable: boolean;\n\n fitted: Size;\n view: PictureView;\n maximum: number;\n}\n\n/** A press on the stage: still a tap, or a drag that pans, swipes across (`swipe`) or pulls down (`pull`). */\ninterface Press {\n id: number;\n type: string;\n start: Point;\n last: Point;\n moved: boolean;\n mode: 'none' | 'pan' | 'swipe' | 'pull';\n}\n\ninterface StageBox {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\nexport class MediaViewer {\n private static count = 0;\n private readonly host: HTMLElement;\n private readonly context: MediaViewerContext;\n private readonly id = `orbit-viewer-${(++MediaViewer.count).toString(36)}`;\n private dialog: HTMLDialogElement | null = null;\n private parts: ViewerParts | null = null;\n private shown = false;\n private items: MediaItem[] = [];\n private index = 0;\n private picture: Picture | null = null;\n private player: MediaPlayer | null = null;\n\n /** The player's frame or video, in the box fitted to its width over height. */\n private playerBox: HTMLElement | null = null;\n\n private returnFocus: HTMLElement | SVGElement | null = null;\n private resizeObserver: ResizeObserver | null = null;\n private readonly pointers = new Map<number, Point>();\n private press: Press | null = null;\n\n /** A pinch, from where it started: the picture's view, and the fingers' distance and middle (from the stage's center). */\n private pinch: { view: PictureView; distance: number; center: Point } | null = null;\n\n private suppressClick = false;\n private lastTap: { time: number; point: Point } | null = null;\n private settleTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(host: HTMLElement, context: MediaViewerContext) {\n this.host = host;\n this.context = context;\n }\n\n get isOpen(): boolean {\n return this.shown;\n }\n\n /** What it shows, while it's open. */\n get item(): MediaItem | null {\n return this.shown ? this.items[this.index] ?? null : null;\n }\n\n /** The video it shows, while it shows one that can be driven. */\n get video(): MediaPlayer | null {\n return this.shown && this.player?.controllable ? this.player : null;\n }\n\n /**\n * Shows a node's picture or video, opening the viewer if it's closed.\n * Returns false when the node has no such media to show.\n */\n open(item: MediaItem, options: MediaShowOptions = {}): boolean {\n if (!showsMedia(item.node, item.kind)) {\n return false;\n }\n\n let items = this.context.items();\n let index = items.findIndex((candidate) => candidate.node.id === item.node.id && candidate.kind === item.kind);\n\n if (index === -1) {\n // Opened from code on a node the map doesn't show: just this one.\n items = [item];\n index = 0;\n }\n\n const dialog = this.ensureDialog();\n const opening = !this.shown;\n\n if (opening) {\n this.returnFocus = focusedElement(this.host);\n }\n\n this.items = items;\n this.show(index, options);\n\n if (opening) {\n this.shown = true;\n\n if (!dialog.open) {\n try {\n dialog.showModal();\n } catch {\n dialog.setAttribute('open', '');\n }\n }\n\n this.observeStage();\n dialog.focus({ preventScroll: true });\n }\n\n this.layout();\n this.context.onShow(this.items[this.index], this.index, this.items.length);\n return true;\n }\n\n close(): void {\n if (!this.shown) {\n return;\n }\n\n const dialog = this.dialog as HTMLDialogElement;\n\n if (dialog.open) {\n if (typeof dialog.close === 'function') {\n dialog.close();\n } else {\n dialog.removeAttribute('open');\n }\n }\n\n this.finish();\n }\n\n /** Steps to the previous (-1) or next (1) picture or video. Returns false at either end. */\n step(direction: 1 | -1): boolean {\n return this.go(this.index + direction);\n }\n\n /**\n * The map changed: what the viewer shows takes the node's new title and\n * media, or the viewer closes if the node or its media went away.\n */\n refresh(): void {\n if (!this.shown) {\n return;\n }\n\n const current = this.items[this.index];\n let items = this.context.items();\n let index = items.findIndex((candidate) => candidate.node.id === current.node.id && candidate.kind === current.kind);\n\n if (index === -1) {\n const node = this.context.node(current.node.id);\n\n if (!node || !showsMedia(node, current.kind)) {\n this.close();\n return;\n }\n\n items = [{ node, kind: current.kind }];\n index = 0;\n }\n\n const next = items[index];\n const source = (item: MediaItem) => (item.kind === 'image' ? item.node.image?.src : item.node.video?.src);\n this.items = items;\n\n if (source(next) !== source(current)) {\n this.show(index, { autoplay: false });\n this.layout();\n return;\n }\n\n this.index = index;\n this.player?.setControls(this.context.interactive());\n this.describe();\n this.layout();\n }\n\n play(): boolean {\n const video = this.video;\n video?.play();\n return video !== null;\n }\n\n pause(): boolean {\n const video = this.video;\n video?.pause();\n return video !== null;\n }\n\n seek(seconds: number): boolean {\n const video = this.video;\n\n if (!video || !Number.isFinite(seconds)) {\n return false;\n }\n\n video.seek(seconds);\n return true;\n }\n\n unmute(): boolean {\n const video = this.video;\n video?.unmute();\n return video !== null;\n }\n\n destroy(): void {\n this.close();\n this.dialog?.remove();\n this.dialog = null;\n this.parts = null;\n }\n\n /** Writes the viewer's buttons in the map's language, and what it shows, if it's open. */\n relabel(): void {\n const parts = this.parts;\n\n if (!parts) {\n return;\n }\n\n const words = this.context.words();\n parts.zoomGroup.setAttribute('aria-label', words.text('zoom'));\n setLabel(parts.zoomOut, words.text('zoomOut'));\n setLabel(parts.zoomIn, words.text('zoomIn'));\n setLabel(parts.fit, words.text('fitPicture'));\n setLabel(parts.close, words.text('close'));\n setLabel(parts.previous, words.text('previous'));\n setLabel(parts.next, words.text('next'));\n\n if (this.shown) {\n this.describe();\n }\n }\n\n // Showing an item\n\n private go(index: number): boolean {\n if (!this.shown || index < 0 || index >= this.items.length || index === this.index) {\n return false;\n }\n\n const parts = this.parts as ViewerParts;\n // Focus on media that's going away (a video's controls) moves to the viewer.\n const focusLeaves = parts.layer.contains(focusedElement(this.host));\n this.show(index, { autoplay: true });\n this.layout();\n\n if (focusLeaves) {\n this.dialog?.focus({ preventScroll: true });\n }\n\n this.context.onShow(this.items[this.index], this.index, this.items.length);\n return true;\n }\n\n private show(index: number, options: MediaShowOptions): void {\n const parts = this.parts as ViewerParts;\n this.clearMedia();\n this.index = index;\n const item = this.items[index];\n this.setStatus(null);\n\n if (item.kind === 'image') {\n this.showPicture(item.node);\n } else {\n this.showVideo(item.node, options);\n }\n\n // The newcomer fades in.\n parts.layer.classList.remove('orbit-viewer__media--entering');\n void parts.layer.offsetWidth;\n parts.layer.classList.add('orbit-viewer__media--entering');\n this.describe();\n }\n\n private showPicture(node: OrbitNode): void {\n const parts = this.parts as ViewerParts;\n const image = node.image as NonNullable<OrbitNode['image']>;\n const url = resolveUrl(guardUrl(image.src, 'image') as string, this.context.baseUrl());\n const element = document.createElement('img');\n element.className = 'orbit-viewer__picture';\n // The picture's description is its name; without one, its caption or the node's title.\n element.alt = image.alt?.trim() || image.caption?.trim() || node.text || this.context.words().text('picture');\n element.draggable = false;\n element.decoding = 'async';\n const picture: Picture = { element, natural: null, scalable: /\\.svgz?(?:[?#]|$)/i.test(url), fitted: { width: 0, height: 0 }, view: FITTED, maximum: 1 };\n this.picture = picture;\n element.addEventListener('load', () => this.pictureLoaded(picture));\n\n element.addEventListener('error', () => {\n if (this.picture === picture) {\n this.setStatus(this.context.words().text('pictureUnavailable'));\n }\n });\n\n this.setStatus('', true);\n element.src = url;\n parts.layer.appendChild(element);\n\n if (element.complete && element.naturalWidth > 0) {\n this.pictureLoaded(picture);\n }\n }\n\n private pictureLoaded(picture: Picture): void {\n if (this.picture !== picture || picture.natural) {\n return;\n }\n\n const { naturalWidth, naturalHeight } = picture.element;\n // A vector picture without a size of its own fills the window.\n picture.natural = naturalWidth > 0 && naturalHeight > 0 ? { width: naturalWidth, height: naturalHeight } : { width: 1, height: 1 };\n picture.scalable ||= !(naturalWidth > 0 && naturalHeight > 0);\n this.setStatus(null);\n this.layout();\n }\n\n private showVideo(node: OrbitNode, options: MediaShowOptions): void {\n const parts = this.parts as ViewerParts;\n const video = node.video as NonNullable<OrbitNode['video']>;\n const baseUrl = this.context.baseUrl();\n const thumbnail = video.thumbnail ? guardUrl(video.thumbnail, 'image') : null;\n // Declared first: a player can report before it's returned.\n let player: MediaPlayer | null = null;\n player = createPlayer(video, {\n autoplay: options.autoplay !== false,\n controls: this.context.interactive(),\n startAt: options.startAt,\n title: node.text || video.caption || this.context.words().text('video'),\n poster: thumbnail ? resolveUrl(thumbnail, baseUrl) : undefined,\n baseUrl,\n onState: (state) => {\n if (player !== null && this.player === player) {\n this.context.onState(this.items[this.index].node, state);\n }\n },\n onRatio: () => {\n if (player !== null && this.player === player) {\n this.layout();\n }\n },\n onError: () => {\n if (player !== null && this.player === player) {\n this.setStatus(this.context.words().text('videoUnavailable'));\n }\n },\n });\n\n if (!player) {\n this.setStatus(this.context.words().text('videoUnavailableHere'));\n return;\n }\n\n this.player = player;\n const box = document.createElement('div');\n box.className = 'orbit-viewer__player';\n box.appendChild(player.element);\n this.playerBox = box;\n parts.layer.appendChild(box);\n }\n\n /** Lets go of the media shown: a video stops. */\n private clearMedia(): void {\n this.resetGestures();\n this.player?.destroy();\n this.player = null;\n this.picture = null;\n this.playerBox = null;\n this.parts?.layer.replaceChildren();\n this.dialog?.classList.remove('orbit-viewer--zoomed');\n }\n\n /** The title, caption, description, counter, link and buttons, for what's shown. */\n private describe(): void {\n const parts = this.parts as ViewerParts;\n const dialog = this.dialog as HTMLDialogElement;\n const item = this.items[this.index];\n const { node } = item;\n const media = item.kind === 'image' ? node.image : node.video;\n const interactive = this.context.interactive();\n dialog.classList.toggle('orbit-viewer--still', !interactive);\n dialog.dataset.orbitMedia = item.kind;\n\n const title = [this.context.icon(node), node.text].filter(Boolean).join(' ');\n parts.title.textContent = title;\n const caption = media?.caption?.trim() ?? '';\n parts.text.textContent = caption;\n parts.text.hidden = caption === '';\n const description = item.kind === 'image' ? node.image?.alt?.trim() ?? '' : '';\n parts.description.textContent = description;\n parts.description.hidden = description === '' || description === caption;\n\n // The counter is a live region: it changes, and is read out, only when the viewer moves.\n const total = this.items.length;\n const counted = total > 1 ? this.context.words().text('position', { index: this.index + 1, total }) : '';\n const named = counted && title ? `: ${title}` : '';\n\n if (parts.counter.textContent !== counted + named) {\n const position = document.createElement('span');\n position.textContent = counted;\n const name = document.createElement('span');\n name.className = 'orbit-visually-hidden';\n name.textContent = named;\n parts.counter.replaceChildren(...(counted ? [position, name] : []));\n }\n\n parts.previous.hidden = total < 2;\n parts.next.hidden = total < 2;\n parts.previous.disabled = this.index === 0;\n parts.next.disabled = this.index === total - 1;\n\n const link = this.mediaLink(item);\n parts.link.hidden = link === null;\n\n if (link) {\n parts.link.href = link.href;\n parts.link.setAttribute('aria-label', link.label);\n parts.link.title = link.label;\n } else {\n parts.link.removeAttribute('href');\n }\n\n parts.zoomGroup.hidden = item.kind !== 'image';\n this.updateZoomButtons();\n this.keepFocus();\n }\n\n /** Where to see the picture on its own, or the video on its site; none for pictures in the map itself (`data:` and `blob:` URLs). */\n private mediaLink(item: MediaItem): { href: string; label: string } | null {\n const { node } = item;\n const baseUrl = this.context.baseUrl();\n\n if (item.kind === 'image') {\n const source = node.image?.src ?? '';\n const link = /^\\s*(?:data|blob):/i.test(source) ? null : guardUrl(source, 'link');\n return link ? { href: resolveUrl(link, baseUrl), label: this.context.words().text('openPictureInNewTab') } : null;\n }\n\n const video = node.video;\n\n if (!video || /^\\s*(?:data|blob):/i.test(video.src)) {\n return null;\n }\n\n const guarded = guardUrl(video.src, 'link');\n\n if (!guarded) {\n return null;\n }\n\n const resolved = resolveUrl(guarded, baseUrl);\n const provider = video.provider === 'youtube' || video.provider === 'vimeo' ? video.provider : detectVideoProvider(resolved);\n const words = this.context.words();\n const label = provider === 'youtube'\n ? words.text('watchOn', { provider: 'YouTube' })\n : provider === 'vimeo' ? words.text('watchOn', { provider: 'Vimeo' }) : words.text('openVideoInNewTab');\n return { href: videoPageUrl(resolved, video.provider), label };\n }\n\n /** Shows `text` over the stage, with a spinner while it's `loading`; null shows nothing. */\n private setStatus(text: string | null, loading = false): void {\n const parts = this.parts as ViewerParts;\n parts.status.textContent = text ?? '';\n parts.status.hidden = text === null;\n parts.status.classList.toggle('orbit-viewer__status--loading', loading);\n parts.stage.setAttribute('aria-busy', String(loading));\n }\n\n // Layout and zoom\n\n /** Fits the picture or the player to the stage. */\n private layout(): void {\n const parts = this.parts;\n\n if (!this.shown || !parts) {\n return;\n }\n\n const stage = this.readStageBox();\n const steps = this.items.length > 1 && this.context.interactive();\n const stepsUnder = steps && this.playerBox !== null && stage.width < WIDE_STAGE;\n const room = this.mediaRoom(stage, steps, stepsUnder);\n const picture = this.picture;\n\n if (picture?.natural) {\n const fitted = fittedSize(picture.natural, room, picture.scalable);\n picture.fitted = fitted;\n picture.maximum = maximumZoom(picture.natural, fitted);\n const style = picture.element.style;\n style.width = `${round(fitted.width)}px`;\n style.height = `${round(fitted.height)}px`;\n style.left = `${round((stage.width - fitted.width) / 2)}px`;\n style.top = `${round((stage.height - fitted.height) / 2)}px`;\n this.setView(clampView(picture.view, fitted, stage, picture.maximum), false);\n }\n\n const box = this.playerBox;\n let stepTop = '';\n\n if (box && this.player) {\n const ratio = this.player.ratio;\n const width = Math.max(0, Math.min(room.width, room.height * ratio));\n const height = width / ratio;\n const top = (stage.height - height - (stepsUnder ? STEP_ROW : 0)) / 2;\n box.style.width = `${round(width)}px`;\n box.style.height = `${round(height)}px`;\n box.style.left = `${round((stage.width - width) / 2)}px`;\n box.style.top = `${round(top)}px`;\n\n if (stepsUnder) {\n stepTop = `${round(top + height + (STEP_ROW - STEP_SIZE) / 2)}px`;\n }\n }\n\n parts.previous.style.top = stepTop;\n parts.next.style.top = stepTop;\n }\n\n /**\n * Where the media fits: the stage, less a margin, and the room the\n * previous and next buttons take beside it on wide stages, or under a\n * video on narrow ones.\n */\n private mediaRoom(stage: Size, steps: boolean, stepsUnder: boolean): Size {\n const side = steps && stage.width >= WIDE_STAGE ? STEP_ROOM : MEDIA_MARGIN;\n const under = stepsUnder ? STEP_ROW : 0;\n return { width: Math.max(0, stage.width - 2 * side), height: Math.max(0, stage.height - 2 * MEDIA_MARGIN - under) };\n }\n\n /** The stage's place in the window: happy-dom has no layout, so tests replace this. */\n private readStageBox(): StageBox {\n const box = (this.parts as ViewerParts).stage.getBoundingClientRect();\n return { left: box.left, top: box.top, width: box.width, height: box.height };\n }\n\n /** A point in the window, from the stage's center. */\n private stagePoint(point: Point): Point {\n const stage = this.readStageBox();\n return { x: point.x - stage.left - stage.width / 2, y: point.y - stage.top - stage.height / 2 };\n }\n\n private setView(view: PictureView, glide: boolean): void {\n const picture = this.picture;\n\n if (!picture) {\n return;\n }\n\n picture.view = view;\n const element = picture.element;\n element.classList.toggle('orbit-viewer__picture--gliding', glide);\n element.style.transform = `translate(${round(view.x)}px, ${round(view.y)}px) scale(${Math.round(view.scale * 10000) / 10000})`;\n this.dialog?.classList.toggle('orbit-viewer--zoomed', isZoomed(view));\n this.updateZoomButtons();\n }\n\n /** Zooms the picture by `factor` around `anchor` (from the stage's center). */\n private zoomAt(factor: number, anchor: Point, glide: boolean): boolean {\n const picture = this.picture;\n\n if (!picture?.natural) {\n return false;\n }\n\n const stage = this.readStageBox();\n this.setView(zoomAround(picture.view, factor, anchor, picture.fitted, stage, picture.maximum), glide);\n return true;\n }\n\n private fitPicture(): boolean {\n if (!this.picture?.natural) {\n return false;\n }\n\n this.setView(FITTED, true);\n return true;\n }\n\n private panBy(deltaX: number, deltaY: number, glide: boolean): void {\n const picture = this.picture;\n\n if (picture?.natural) {\n this.setView(panView(picture.view, deltaX, deltaY, picture.fitted, this.readStageBox(), picture.maximum), glide);\n }\n }\n\n private get zoomed(): boolean {\n return this.picture !== null && isZoomed(this.picture.view);\n }\n\n private updateZoomButtons(): void {\n const parts = this.parts;\n const picture = this.picture;\n\n if (!parts) {\n return;\n }\n\n const ready = Boolean(picture?.natural);\n const scale = picture?.view.scale ?? 1;\n parts.zoomOut.disabled = !ready || scale <= 1.001;\n parts.fit.disabled = !ready || scale <= 1.001;\n parts.zoomIn.disabled = !ready || scale >= (picture?.maximum ?? 1) - 0.001;\n this.keepFocus();\n }\n\n /** A button that had focus and can't be pressed any more (the last step, the furthest zoom) hands focus to the viewer, which keeps its keys. */\n private keepFocus(): void {\n const focused = focusedElement(this.host);\n\n if (this.shown && focused instanceof HTMLButtonElement && focused.disabled && this.dialog?.contains(focused)) {\n this.dialog.focus({ preventScroll: true });\n }\n }\n\n // The dialog\n\n private ensureDialog(): HTMLDialogElement {\n if (this.dialog) {\n return this.dialog;\n }\n\n const dialog = document.createElement('dialog');\n dialog.className = 'orbit-viewer';\n dialog.tabIndex = -1;\n dialog.setAttribute('aria-labelledby', `${this.id}-title`);\n\n const bar = element('div', 'orbit-viewer__bar');\n const counter = element('p', 'orbit-viewer__counter');\n counter.setAttribute('role', 'status');\n const tools = element('div', 'orbit-viewer__tools');\n const zoomGroup = element('div', 'orbit-panel orbit-viewer__zoom');\n zoomGroup.setAttribute('role', 'group');\n const zoomOut = iconButton('zoom-out', () => this.zoomAt(1 / STEP_ZOOM, { x: 0, y: 0 }, true));\n const zoomIn = iconButton('zoom-in', () => this.zoomAt(STEP_ZOOM, { x: 0, y: 0 }, true));\n const fit = iconButton('fit', () => this.fitPicture());\n zoomGroup.append(zoomOut, zoomIn, fit);\n const actions = element('div', 'orbit-panel');\n const link = element('a', 'orbit-button orbit-button--icon orbit-viewer__link');\n link.target = '_blank';\n link.rel = 'noopener noreferrer';\n link.appendChild(createIcon('link'));\n const close = iconButton('close', () => this.close());\n close.classList.add('orbit-viewer__close');\n actions.append(link, close);\n tools.append(zoomGroup, actions);\n bar.append(counter, tools);\n\n const stage = element('div', 'orbit-viewer__stage');\n const layer = element('div', 'orbit-viewer__media');\n const status = element('p', 'orbit-viewer__status');\n status.hidden = true;\n const previous = iconButton('previous', () => this.step(-1));\n previous.classList.add('orbit-viewer__step', 'orbit-viewer__step--previous');\n const next = iconButton('next', () => this.step(1));\n next.classList.add('orbit-viewer__step', 'orbit-viewer__step--next');\n stage.append(layer, status, previous, next);\n\n const caption = element('div', 'orbit-viewer__caption');\n const title = element('h2', 'orbit-viewer__title');\n title.id = `${this.id}-title`;\n const text = element('p', 'orbit-viewer__text');\n const description = element('p', 'orbit-viewer__description');\n caption.append(title, text, description);\n\n dialog.append(bar, stage, caption);\n this.parts = { bar, counter, zoomOut, zoomIn, fit, zoomGroup, link, close, stage, layer, status, previous, next, caption, title, text, description };\n this.relabel();\n\n dialog.addEventListener('keydown', this.handleKeyDown);\n dialog.addEventListener('cancel', this.handleCancel);\n\n // Only the click that ends a drag is swallowed: any new press is clicked as usual.\n dialog.addEventListener('pointerdown', () => {\n this.suppressClick = false;\n }, true);\n\n // The browser can close it too. A close event can also arrive after the viewer opened again: that one is stale.\n dialog.addEventListener('close', () => {\n if (!dialog.open) {\n this.finish();\n }\n });\n\n dialog.addEventListener('click', this.handleClick, true);\n dialog.addEventListener('wheel', this.handleWheel, { passive: false });\n dialog.addEventListener('touchmove', this.handleTouchMove, { passive: false });\n stage.addEventListener('pointerdown', this.handlePointerDown);\n stage.addEventListener('pointermove', this.handlePointerMove);\n stage.addEventListener('pointerup', this.handlePointerUp);\n stage.addEventListener('pointercancel', this.handlePointerUp);\n stage.addEventListener('dblclick', this.handleDoubleClick);\n this.host.appendChild(dialog);\n this.dialog = dialog;\n return dialog;\n }\n\n /** After the dialog closed, by `close()` or by the browser. */\n private finish(): void {\n if (!this.shown) {\n return;\n }\n\n this.shown = false;\n const item = this.items[this.index];\n const index = this.index;\n const total = this.items.length;\n this.clearMedia();\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n\n if (this.settleTimer !== null) {\n clearTimeout(this.settleTimer);\n this.settleTimer = null;\n }\n\n this.items = [];\n const target = this.returnFocus;\n this.returnFocus = null;\n\n if (target && target.isConnected) {\n target.focus({ preventScroll: true });\n }\n\n if (item) {\n this.context.onClose(item, index, total);\n }\n }\n\n private observeStage(): void {\n if (this.resizeObserver || typeof ResizeObserver === 'undefined' || !this.parts) {\n return;\n }\n\n this.resizeObserver = new ResizeObserver(() => this.layout());\n this.resizeObserver.observe(this.parts.stage);\n }\n\n // Keys\n\n private readonly handleKeyDown = (event: KeyboardEvent): void => {\n if (!this.shown || !this.context.interactive() || event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey) {\n return;\n }\n\n const target = event.target instanceof Element ? event.target : null;\n // A video's own controls take the arrows and the space bar.\n const onVideo = target?.closest('video, iframe') != null;\n const stage = this.readStageBox();\n let handled = true;\n\n switch (event.key) {\n case 'Escape':\n this.close();\n break;\n case 'ArrowLeft':\n case 'ArrowRight': {\n const direction = event.key === 'ArrowRight' ? 1 : -1;\n\n if (onVideo) {\n handled = false;\n } else if (this.zoomed) {\n this.panBy(-direction * stage.width * KEY_PAN, 0, true);\n } else {\n this.step(direction);\n }\n\n break;\n }\n case 'ArrowUp':\n case 'ArrowDown':\n if (this.zoomed && !onVideo) {\n this.panBy(0, (event.key === 'ArrowDown' ? -1 : 1) * stage.height * KEY_PAN, true);\n } else {\n handled = false;\n }\n\n break;\n case 'Home':\n case 'End':\n handled = !onVideo && this.go(event.key === 'Home' ? 0 : this.items.length - 1);\n break;\n case '+':\n case '=':\n handled = this.zoomAt(STEP_ZOOM, { x: 0, y: 0 }, true);\n break;\n case '-':\n case '_':\n handled = this.zoomAt(1 / STEP_ZOOM, { x: 0, y: 0 }, true);\n break;\n case '0':\n handled = this.fitPicture();\n break;\n case ' ':\n handled = !onVideo && !target?.closest('button, a') && this.togglePlayback();\n break;\n default:\n handled = false;\n }\n\n if (handled) {\n event.preventDefault();\n }\n };\n\n /** Plays the video if it's paused, and pauses it if it plays. */\n private togglePlayback(): boolean {\n const video = this.video;\n\n if (!video) {\n return false;\n }\n\n if (video.state.playing) {\n video.pause();\n } else {\n video.play();\n }\n\n return true;\n }\n\n /** Esc, as the browser reports it: the viewer closes itself, so focus goes back and the map hears of it. */\n private readonly handleCancel = (event: Event): void => {\n event.preventDefault();\n\n if (this.context.interactive()) {\n this.close();\n }\n };\n\n // Pointer gestures\n\n private readonly handleClick = (event: MouseEvent): void => {\n if (this.suppressClick) {\n this.suppressClick = false;\n event.stopPropagation();\n event.preventDefault();\n return;\n }\n\n const parts = this.parts;\n\n if (!parts || !this.context.interactive()) {\n return;\n }\n\n // A click around the media, not on it, is a click on the backdrop.\n if (event.target === parts.stage || event.target === parts.layer) {\n this.close();\n }\n };\n\n private readonly handleWheel = (event: WheelEvent): void => {\n const parts = this.parts;\n\n if (!parts) {\n return;\n }\n\n // The page behind never scrolls; a long caption does.\n const inCaption = event.target instanceof Node && parts.caption.contains(event.target) && parts.caption.scrollHeight > parts.caption.clientHeight;\n\n if (!inCaption && event.cancelable) {\n event.preventDefault();\n }\n\n if (!this.context.interactive() || !(event.target instanceof Node) || !parts.stage.contains(event.target) || !this.picture?.natural) {\n return;\n }\n\n const factor = wheelZoomFactor(event, this.readStageBox().height);\n this.zoomAt(factor, this.stagePoint({ x: event.clientX, y: event.clientY }), false);\n };\n\n /** A drag on the viewer never scrolls the page behind it. */\n private readonly handleTouchMove = (event: TouchEvent): void => {\n const parts = this.parts;\n const inCaption = parts !== null && event.target instanceof Node && parts.caption.contains(event.target);\n\n if (!inCaption && event.cancelable) {\n event.preventDefault();\n }\n };\n\n private readonly handleDoubleClick = (event: MouseEvent): void => {\n if (!this.context.interactive() || event.target !== this.picture?.element) {\n return;\n }\n\n this.toggleZoomAt({ x: event.clientX, y: event.clientY });\n };\n\n private toggleZoomAt(point: Point): void {\n const picture = this.picture;\n\n if (!picture?.natural) {\n return;\n }\n\n const stage = this.readStageBox();\n this.setView(toggleZoom(picture.view, this.stagePoint(point), picture.natural, picture.fitted, stage, picture.maximum), true);\n }\n\n private readonly handlePointerDown = (event: PointerEvent): void => {\n if (!this.context.interactive() || (event.pointerType === 'mouse' && event.button !== 0)) {\n return;\n }\n\n if (event.target instanceof Element && event.target.closest(CONTROLS)) {\n return;\n }\n\n const point = { x: event.clientX, y: event.clientY };\n this.pointers.set(event.pointerId, point);\n\n if (this.pointers.size === 2) {\n // Two fingers pinch the picture; a swipe one of them began goes back.\n if (this.press?.mode === 'swipe' || this.press?.mode === 'pull') {\n this.settleLayer();\n }\n\n this.press = null;\n\n if (this.picture?.natural) {\n this.pinch = { view: this.picture.view, distance: this.pinchDistance(), center: this.stagePoint(this.pinchCenter()) };\n\n // Both fingers, so a lift outside the stage still ends the pinch here instead of leaving a ghost finger behind.\n for (const id of this.pointers.keys()) {\n this.capture(id);\n }\n }\n\n return;\n }\n\n if (this.pointers.size > 2) {\n return;\n }\n\n this.press = { id: event.pointerId, type: event.pointerType, start: point, last: point, moved: false, mode: 'none' };\n };\n\n private readonly handlePointerMove = (event: PointerEvent): void => {\n if (!this.pointers.has(event.pointerId)) {\n return;\n }\n\n const point = { x: event.clientX, y: event.clientY };\n this.pointers.set(event.pointerId, point);\n const pinch = this.pinch;\n const picture = this.picture;\n\n if (pinch) {\n if (this.pointers.size < 2 || !picture?.natural) {\n return;\n }\n\n // The point of the picture that was between the fingers stays between them, zoomed by how far they spread.\n const center = this.stagePoint(this.pinchCenter());\n const factor = pinch.distance > 0 ? this.pinchDistance() / pinch.distance : 1;\n const scale = Math.min(picture.maximum, Math.max(1, pinch.view.scale * factor));\n const ratio = scale / pinch.view.scale;\n const view = { scale, x: center.x - (pinch.center.x - pinch.view.x) * ratio, y: center.y - (pinch.center.y - pinch.view.y) * ratio };\n this.setView(clampView(view, picture.fitted, this.readStageBox(), picture.maximum), false);\n return;\n }\n\n const press = this.press;\n\n if (!press || press.id !== event.pointerId) {\n return;\n }\n\n const deltaX = point.x - press.start.x;\n const deltaY = point.y - press.start.y;\n\n if (!press.moved) {\n if (Math.hypot(deltaX, deltaY) < (press.type === 'mouse' ? MOUSE_SLOP : TOUCH_SLOP)) {\n return;\n }\n\n press.moved = true;\n press.mode = this.dragMode(press.type, deltaX, deltaY);\n this.capture(event.pointerId);\n this.dialog?.classList.toggle('orbit-viewer--dragging', press.mode === 'pan');\n }\n\n const layer = (this.parts as ViewerParts).layer;\n\n if (press.mode === 'pan') {\n this.panBy(point.x - press.last.x, point.y - press.last.y, false);\n } else if (press.mode === 'swipe') {\n layer.style.transform = `translate(${round(deltaX)}px, 0)`;\n } else if (press.mode === 'pull') {\n const pull = Math.max(0, deltaY);\n layer.style.transform = `translate(0, ${round(pull)}px)`;\n this.dialog?.style.setProperty('--_orbit-viewer-pull', String(Math.min(1, pull / (SWIPE_CLOSE * 3))));\n }\n\n press.last = point;\n };\n\n private readonly handlePointerUp = (event: PointerEvent): void => {\n if (!this.pointers.delete(event.pointerId)) {\n return;\n }\n\n if (this.pinch) {\n if (this.pointers.size < 2) {\n this.pinch = null;\n this.suppressClick = true;\n // The finger left on the screen pans on from where it is.\n const remaining = Array.from(this.pointers.entries())[0];\n\n if (remaining) {\n this.press = { id: remaining[0], type: event.pointerType, start: remaining[1], last: remaining[1], moved: true, mode: this.zoomed ? 'pan' : 'none' };\n }\n }\n\n return;\n }\n\n const press = this.press;\n\n if (!press || press.id !== event.pointerId) {\n return;\n }\n\n this.press = null;\n this.dialog?.classList.remove('orbit-viewer--dragging');\n const cancelled = event.type === 'pointercancel';\n const deltaX = event.clientX - press.start.x;\n const deltaY = event.clientY - press.start.y;\n\n if (press.moved) {\n this.suppressClick = true;\n\n if (press.mode === 'swipe') {\n if (cancelled || Math.abs(deltaX) < SWIPE_STEP || !this.step(deltaX < 0 ? 1 : -1)) {\n this.settleLayer();\n }\n } else if (press.mode === 'pull') {\n if (!cancelled && deltaY >= SWIPE_CLOSE) {\n this.close();\n } else {\n this.settleLayer();\n }\n }\n\n return;\n }\n\n if (press.type !== 'mouse' && !cancelled) {\n const point = { x: event.clientX, y: event.clientY };\n const previous = this.lastTap;\n\n if (previous && event.timeStamp - previous.time < DOUBLE_TAP_TIME && Math.hypot(point.x - previous.point.x, point.y - previous.point.y) < DOUBLE_TAP_DISTANCE) {\n this.lastTap = null;\n\n if (event.target === this.picture?.element) {\n this.toggleZoomAt(point);\n }\n } else {\n this.lastTap = { time: event.timeStamp, point };\n }\n }\n };\n\n /** What a drag that starts this way does: pans a zoomed picture, or swipes across or down on a touch screen. */\n private dragMode(type: string, deltaX: number, deltaY: number): Press['mode'] {\n if (this.zoomed) {\n return 'pan';\n }\n\n if (type === 'mouse') {\n return 'none';\n }\n\n if (Math.abs(deltaX) > Math.abs(deltaY)) {\n return this.items.length > 1 ? 'swipe' : 'none';\n }\n\n return deltaY > 0 ? 'pull' : 'none';\n }\n\n /** Brings media a swipe moved back to its place. */\n private settleLayer(): void {\n const parts = this.parts;\n const dialog = this.dialog;\n\n if (!parts || !dialog) {\n return;\n }\n\n dialog.classList.add('orbit-viewer--settling');\n parts.layer.style.transform = '';\n dialog.style.removeProperty('--_orbit-viewer-pull');\n\n if (this.settleTimer !== null) {\n clearTimeout(this.settleTimer);\n }\n\n this.settleTimer = setTimeout(() => {\n this.settleTimer = null;\n dialog.classList.remove('orbit-viewer--settling');\n }, 260);\n }\n\n private resetGestures(): void {\n this.pointers.clear();\n this.press = null;\n this.pinch = null;\n this.lastTap = null;\n this.dialog?.classList.remove('orbit-viewer--dragging');\n\n if (this.parts) {\n this.parts.layer.style.transform = '';\n }\n\n this.dialog?.style.removeProperty('--_orbit-viewer-pull');\n }\n\n private capture(pointerId: number): void {\n try {\n this.parts?.stage.setPointerCapture?.(pointerId);\n } catch {\n // Pointer capture is optional (some test environments lack it).\n }\n }\n\n private pinchDistance(): number {\n const [first, second] = Array.from(this.pointers.values());\n return first && second ? Math.hypot(first.x - second.x, first.y - second.y) : 0;\n }\n\n private pinchCenter(): Point {\n const [first, second] = Array.from(this.pointers.values());\n return first && second ? { x: (first.x + second.x) / 2, y: (first.y + second.y) / 2 } : first ?? { x: 0, y: 0 };\n }\n}\n\n/** The element with focus, inside shadow roots too. */\nconst focusedElement = (host: Node): HTMLElement | SVGElement | null => {\n const root = host.getRootNode() as Document | ShadowRoot;\n let active: Element | null = root.activeElement ?? host.ownerDocument?.activeElement ?? null;\n\n while (active?.shadowRoot?.activeElement) {\n active = active.shadowRoot.activeElement;\n }\n\n return active instanceof HTMLElement || active instanceof SVGElement ? active : null;\n};\n\nconst iconButton = (icon: IconName, onClick: () => void): HTMLButtonElement => {\n const button = element('button', 'orbit-button orbit-button--icon');\n button.type = 'button';\n button.appendChild(createIcon(icon));\n button.addEventListener('click', onClick);\n return button;\n};\n\n/** A button's name and its tooltip. */\nconst setLabel = (button: HTMLButtonElement, label: string): void => {\n button.setAttribute('aria-label', label);\n button.title = label;\n};\n\nconst element = <Name extends keyof HTMLElementTagNameMap>(name: Name, className: string): HTMLElementTagNameMap[Name] => {\n const created = document.createElement(name);\n created.className = className;\n return created;\n};\n\nconst round = (value: number): number => {\n return Math.round(value * 100) / 100;\n};\n",
|
|
58
|
+
"/**\n * Buttons under the focused node: its type's details, its image, video,\n * embed, note and link, then your own actions.\n */\n\nimport type { OrbitContentAction, OrbitNode } from '../types.js';\nimport { OrbitWords } from '../languages.js';\nimport { actionLabel, type OrbitAction } from '../extensions.js';\nimport { hasMediaSource } from '../media.js';\nimport { isNodeLink } from '../node-links.js';\nimport { guardUrl } from '../url-guard.js';\nimport { overlayTransform, pointsCoarsely } from '../browser.js';\nimport { createActionIcon, createIcon, type IconName } from './icons.js';\n\nexport type ActionKind = OrbitContentAction;\n\n/**\n * Where a node's link goes: a page, another node of the map (with the\n * button's label), or a node that isn't in the map, which gets no button.\n */\nexport type LinkDescription = { kind: 'page' } | { kind: 'node'; label: string } | { kind: 'missing' };\n\n/** Orbit's buttons a node offers, in display order. A video replaces an embed. */\nexport const activeActions = (node: OrbitNode, hasDetails = false): ActionKind[] => {\n const kinds: ActionKind[] = [];\n\n if (hasDetails) {\n kinds.push('details');\n }\n\n if (hasMediaSource(node.image)) {\n kinds.push('image');\n }\n\n if (hasMediaSource(node.video)) {\n kinds.push('video');\n }\n\n if (hasMediaSource(node.embed) && !hasMediaSource(node.video)) {\n kinds.push('embed');\n }\n\n if (node.note) {\n kinds.push('note');\n }\n\n if (node.link && (isNodeLink(node.link) || guardUrl(node.link, 'link') !== null)) {\n kinds.push('link');\n }\n\n return kinds;\n};\n\nconst LABELS = {\n details: 'showDetails',\n image: 'viewImage',\n video: 'playVideo',\n embed: 'openEmbed',\n note: 'readNote',\n link: 'openLink',\n} as const satisfies Record<ActionKind, string>;\n\nconst ICONS: Record<ActionKind, IconName> = {\n details: 'info',\n image: 'image',\n video: 'video',\n embed: 'embed',\n note: 'note',\n link: 'link',\n};\n\n/** What the bar asks the map about a node besides its content. */\nexport interface ActionBarContext {\n /** Runs a button: one of Orbit's, or the `id` of one of your actions. */\n onAction(node: OrbitNode, action: string, event: MouseEvent): void;\n\n /** Where the node's link goes. */\n describeLink(node: OrbitNode): LinkDescription;\n\n /** Your actions the node offers. */\n actions(node: OrbitNode): OrbitAction[];\n\n /** Whether the node's type adds a section to the detail sheet. */\n hasDetails(node: OrbitNode): boolean;\n\n /** Puts keyboard focus back on the map's active node, the way closing the inline editor does. */\n returnFocus?(): void;\n\n /** The map's words, in its language. Default: English. */\n words?(): OrbitWords;\n}\n\nconst ENGLISH = new OrbitWords('en');\n\n/** A button's width and height (px), as `.orbit-action` draws it: bigger where the page is used with a finger. */\nconst BUTTON_SIZE = 36;\nconst COARSE_BUTTON_SIZE = 42;\n/** The room between buttons (px), as `.orbit-actions` leaves it. */\nconst BUTTON_GAP = 8;\n\n/** How a row of buttons lays out in the width it's given: the buttons on each line, and the size of the whole. */\nexport interface ActionRows {\n perLine: number;\n width: number;\n height: number;\n}\n\n/** How `count` buttons `size` px wide lay out in `width` px: on one line where they fit, else wrapped onto more. */\nexport const actionRows = (count: number, size: number, width = Infinity): ActionRows => {\n const perLine = Math.max(1, Math.min(count, Math.floor((width + BUTTON_GAP) / (size + BUTTON_GAP))));\n const lines = Math.ceil(count / perLine);\n return {\n perLine,\n width: perLine * size + (perLine - 1) * BUTTON_GAP,\n height: lines * size + (lines - 1) * BUTTON_GAP,\n };\n};\n\nexport class ActionBar {\n readonly element: HTMLDivElement;\n private readonly context: ActionBarContext;\n private node: OrbitNode | null = null;\n private visible = false;\n\n /** Where the buttons were last put, so a bar that didn't move isn't touched: the map paints every frame while it moves. */\n private transform = '';\n\n /** The width they last wrapped at (0 for one line). */\n private wrap = 0;\n\n /** The last node counted, and its count. */\n private counted: { node: OrbitNode; count: number } | null = null;\n\n constructor(context: ActionBarContext) {\n this.context = context;\n this.element = document.createElement('div');\n this.element.className = 'orbit-actions';\n this.element.setAttribute('role', 'toolbar');\n }\n\n /** How many buttons `node` gets: Orbit's, then your actions. The map asks every frame, so each node is counted once. */\n count(node: OrbitNode): number {\n if (this.counted?.node !== node) {\n this.counted = { node, count: this.kinds(node).length + this.context.actions(node).length };\n }\n\n return this.counted.count;\n }\n\n /** How wide and tall each button is (px), known without laying them out. */\n size(): number {\n return pointsCoarsely(this.element) ? COARSE_BUTTON_SIZE : BUTTON_SIZE;\n }\n\n private kinds(node: OrbitNode): ActionKind[] {\n return activeActions(node, this.context.hasDetails(node)).filter((kind) => kind !== 'link' || this.context.describeLink(node).kind !== 'missing');\n }\n\n /**\n * Shows the buttons of `node` (if it has any) with their top center at\n * (`x`, `y`), wrapped onto lines `wrap` px wide (or on one line, with 0).\n */\n show(node: OrbitNode, x: number, y: number, wrap = 0): void {\n if (node !== this.node) {\n this.node = node;\n this.element.replaceChildren(\n ...this.kinds(node).map((kind) => this.contentButton(node, kind)),\n ...this.context.actions(node).map((action) => this.actionButton(node, action)),\n );\n const words = this.words();\n this.element.setAttribute('aria-label', node.text ? words.text('ideaActions', { name: node.text }) : words.text('ideaActionsUntitled'));\n }\n\n if (!this.element.hasChildNodes()) {\n this.hide();\n return;\n }\n\n const transform = overlayTransform(Math.round(x), Math.round(y), '-50%, 0');\n\n if (transform !== this.transform) {\n this.element.style.transform = transform;\n this.transform = transform;\n }\n\n if (wrap !== this.wrap) {\n this.element.style.maxWidth = wrap > 0 ? `${wrap}px` : '';\n this.wrap = wrap;\n }\n\n if (!this.visible) {\n this.element.classList.add('orbit-actions--visible');\n this.visible = true;\n }\n }\n\n hide(): void {\n if (!this.visible) {\n return;\n }\n\n // Keep focus on the map if it was on one of the buttons: blurring would drop it to <body>, off the map's keys.\n if (this.element.contains(this.element.ownerDocument.activeElement)) {\n if (this.context.returnFocus) {\n this.context.returnFocus();\n } else {\n (this.element.ownerDocument.activeElement as HTMLElement).blur();\n }\n }\n\n this.element.classList.remove('orbit-actions--visible');\n this.visible = false;\n }\n\n private words(): OrbitWords {\n return this.context.words?.() ?? ENGLISH;\n }\n\n /** Forgets the buttons, so the next `show` rebuilds them. */\n reset(): void {\n this.node = null;\n this.counted = null;\n this.element.replaceChildren();\n this.hide();\n }\n\n private contentButton(node: OrbitNode, kind: ActionKind): HTMLButtonElement {\n const link = kind === 'link' ? this.context.describeLink(node) : null;\n const label = link?.kind === 'node' ? link.label : this.words().text(LABELS[kind]);\n const button = this.button(node, kind, label);\n button.classList.add(`orbit-action--${kind}`);\n button.appendChild(createIcon(link?.kind === 'node' ? 'goto' : ICONS[kind]));\n return button;\n }\n\n private actionButton(node: OrbitNode, action: OrbitAction): HTMLButtonElement {\n const label = actionLabel(action, node);\n const button = this.button(node, action.id, label);\n button.classList.add('orbit-action--custom');\n button.dataset.action = action.id;\n button.appendChild(createActionIcon(action.icon, label));\n return button;\n }\n\n private button(node: OrbitNode, action: string, label: string): HTMLButtonElement {\n const button = document.createElement('button');\n button.type = 'button';\n button.className = 'orbit-action';\n button.setAttribute('aria-label', label);\n button.title = label;\n\n button.addEventListener('click', (event) => {\n event.stopPropagation();\n this.context.onAction(node, action, event);\n });\n\n return button;\n }\n}\n",
|
|
59
|
+
"/**\n * The field for typing a node's text on the map: a textarea laid over the\n * node each frame, in the label's font, size and color. Enter saves, Escape\n * cancels, and leaving the field saves.\n */\n\nimport type { NodeRole } from '../engine/scene.js';\n\nexport interface InlineEditorCallbacks {\n /** Enter, or the field losing focus: keep `text`. */\n onSave(text: string, how: 'enter' | 'blur'): void;\n\n /** Escape. */\n onCancel(): void;\n\n /** Tab (`back` for Shift+Tab), with `text` typed. Returns whether it was used; if not, Tab moves keyboard focus as usual. */\n onTab(text: string, back: boolean): boolean;\n}\n\n/** Where the field goes this frame: centered on a node, in screen pixels. */\nexport interface EditorPlacement {\n x: number;\n y: number;\n\n /** The width text gets inside the node. */\n width: number;\n\n /** The label's font size, which the text takes on. */\n fontSize: number;\n\n /** The tallest the field grows before it scrolls. */\n maxHeight: number;\n\n role: NodeRole;\n\n /** Light text, on a dark node. */\n light: boolean;\n\n /** A new idea, in the + rather than a node. */\n slot: boolean;\n\n /** Over a node too small to hold it, on a card of its own. */\n floating: boolean;\n\n /** How far below its center (px) the field may reach: the top of the node's \"+N\", which the field rises to keep clear of as it grows. */\n lowest?: number;\n}\n\nexport interface EditorText {\n /** What the field is for, for assistive technology. */\n label: string;\n\n placeholder: string;\n\n /** The label of a phone keyboard's Enter key: `next` while ideas keep coming, `done` otherwise. */\n enterKey: 'next' | 'done';\n}\n\n/** The field's font size: 16 px or more, so phones don't zoom into it. It is scaled down to the label's size. */\nconst FIELD_FONT_SIZE = 16;\n\nexport class InlineEditor {\n readonly element: HTMLTextAreaElement;\n private readonly callbacks: InlineEditorCallbacks;\n private open = false;\n\n /** Closing blurs the field: that blur is no save. */\n private closing = false;\n\n /** One Enter can arrive as a key and as a line break: a second one straight after, with nothing typed between, is ignored. */\n private savedAt = -Infinity;\n\n private typedSinceSave = true;\n\n /** The size and style last applied, and the position, so frames that change nothing touch no styles. */\n private look = '';\n\n private position = '';\n\n /** Where the field was last placed (null while it's out of sight), to move it again when it grows. */\n private placement: EditorPlacement | null = null;\n\n /** The field's height (px, unscaled) as it last grew to fit its text. */\n private height = 0;\n\n constructor(callbacks: InlineEditorCallbacks) {\n this.callbacks = callbacks;\n const field = document.createElement('textarea');\n field.className = 'orbit-editor';\n field.rows = 1;\n field.hidden = true;\n field.setAttribute('autocapitalize', 'sentences');\n field.addEventListener('keydown', this.handleKeyDown);\n field.addEventListener('beforeinput', this.handleBeforeInput);\n field.addEventListener('input', this.handleInput);\n field.addEventListener('blur', this.handleBlur);\n this.element = field;\n }\n\n get isOpen(): boolean {\n return this.open;\n }\n\n get value(): string {\n return this.element.value;\n }\n\n get hasFocus(): boolean {\n return this.element.ownerDocument.activeElement === this.element;\n }\n\n /** Shows the field holding `value`, all selected, with the cursor in it. */\n show(value: string, text: EditorText): void {\n const field = this.element;\n this.describe(text);\n field.value = value;\n field.hidden = false;\n this.open = true;\n this.look = '';\n this.position = '';\n this.placement = null;\n // Out of sight until `place` puts it over its node: a node flying into view is placed only once it shows.\n field.style.opacity = '0';\n this.fit();\n field.focus({ preventScroll: true });\n field.select();\n }\n\n /** Empties the field for the next idea. The cursor stays, and with it a phone's keyboard. */\n clear(text: EditorText): void {\n this.describe(text);\n this.element.value = '';\n this.fit();\n this.move();\n }\n\n hide(): void {\n if (!this.open) {\n return;\n }\n\n this.open = false;\n this.closing = true;\n\n if (this.hasFocus) {\n this.element.blur();\n }\n\n this.closing = false;\n this.element.hidden = true;\n }\n\n /** Lays the field over its node, or keeps it out of sight (and focused) while the node isn't shown. */\n place(placement: EditorPlacement | null): void {\n const field = this.element;\n this.placement = placement;\n\n if (!placement) {\n if (this.position !== '') {\n field.style.opacity = '0';\n this.position = '';\n }\n\n return;\n }\n\n const scale = placement.fontSize / FIELD_FONT_SIZE;\n const look = [placement.width, placement.fontSize, placement.maxHeight, placement.role, placement.light, placement.slot, placement.floating].join('|');\n\n if (look !== this.look) {\n this.look = look;\n field.style.width = `${round(placement.width / scale)}px`;\n field.style.maxHeight = `${round(placement.maxHeight / scale)}px`;\n field.classList.toggle('orbit-editor--sun', placement.role === 'sun');\n field.classList.toggle('orbit-editor--light', placement.light);\n field.classList.toggle('orbit-editor--slot', placement.slot);\n field.classList.toggle('orbit-editor--floating', placement.floating);\n this.fit();\n }\n\n this.move();\n }\n\n private describe(text: EditorText): void {\n this.element.setAttribute('aria-label', text.label);\n this.element.placeholder = text.placeholder;\n this.element.setAttribute('enterkeyhint', text.enterKey);\n }\n\n /** Centers the field over its node, risen as far as it must to keep clear of the node's \"+N\". */\n private move(): void {\n const placement = this.placement;\n\n if (!placement) {\n return;\n }\n\n const scale = placement.fontSize / FIELD_FONT_SIZE;\n const height = Math.min(this.height * scale, placement.maxHeight);\n const rise = placement.lowest === undefined ? 0 : Math.max(0, height / 2 - placement.lowest);\n const position = `translate3d(${round(placement.x)}px, ${round(placement.y - rise)}px, 0) translate(-50%, -50%) scale(${round(scale, 4)})`;\n\n if (position !== this.position) {\n if (this.position === '') {\n this.element.style.opacity = '';\n }\n\n this.element.style.transform = position;\n this.position = position;\n }\n }\n\n /** Grows the field with its text. */\n private fit(): void {\n const field = this.element;\n field.style.height = 'auto';\n this.height = field.scrollHeight;\n field.style.height = `${this.height}px`;\n }\n\n private save(): void {\n const now = typeof performance !== 'undefined' ? performance.now() : Date.now();\n\n if (!this.typedSinceSave && now - this.savedAt < 50) {\n return;\n }\n\n this.savedAt = now;\n this.typedSinceSave = false;\n this.callbacks.onSave(this.element.value, 'enter');\n }\n\n private readonly handleKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') {\n event.preventDefault();\n this.callbacks.onCancel();\n return;\n }\n\n if (event.key === 'Enter' && !event.shiftKey && !event.isComposing) {\n event.preventDefault();\n this.save();\n return;\n }\n\n if (event.key === 'Tab' && !event.isComposing && !event.altKey && !event.ctrlKey && !event.metaKey && this.callbacks.onTab(this.element.value, event.shiftKey)) {\n event.preventDefault();\n }\n };\n\n // Phone keyboards send their Enter key as a line break.\n private readonly handleBeforeInput = (event: InputEvent): void => {\n if (event.inputType === 'insertLineBreak' || event.inputType === 'insertParagraph') {\n event.preventDefault();\n this.save();\n }\n };\n\n // A title is one line: pasted line breaks become spaces.\n private readonly handleInput = (): void => {\n this.typedSinceSave = true;\n const field = this.element;\n\n if (/[\\r\\n]/.test(field.value)) {\n field.value = field.value.replace(/\\s*[\\r\\n]+\\s*/g, ' ');\n }\n\n this.fit();\n this.move();\n };\n\n private readonly handleBlur = (): void => {\n if (this.open && !this.closing) {\n this.callbacks.onSave(this.element.value, 'blur');\n }\n };\n}\n\nconst round = (value: number, decimals = 1): number => {\n const factor = 10 ** decimals;\n return Math.round(value * factor) / factor;\n};\n",
|
|
60
|
+
"/** Numbers as the renderer writes them into the DOM: rounded, so unchanged values compare equal and attributes stay short. */\n\nexport const round = (value: number, decimals = 2): number => {\n const factor = 10 ** decimals;\n return Math.round(value * factor) / factor;\n};\n",
|
|
61
|
+
"/**\n * The rings around orbits and the lines between nodes in the overview, kept\n * in step with each frame's display: one view each, written only when what it\n * shows changed.\n */\n\nimport type { Display, DisplayRing } from '../engine/display.js';\nimport { ringPath, svgElement } from '../engine/views.js';\nimport { round } from './numbers.js';\n\ninterface RingView {\n group: SVGGElement;\n line: SVGPathElement;\n band: SVGPathElement;\n shape: string;\n\n /** The gaps and radius the shape was last checked for: a spin keeps them, so the shape isn't worked out again. */\n gaps: DisplayRing['gaps'] | null;\n\n radius: number;\n transform: string;\n color: string;\n}\n\ninterface LinkView {\n element: SVGLineElement;\n geometry: string;\n opacity: string;\n}\n\n/** The layers rings and links are drawn in, below the nodes. */\nexport interface RingAndLinkLayers {\n rings: SVGGElement;\n links: SVGGElement;\n}\n\nexport class RingsAndLinks {\n private readonly layers: RingAndLinkLayers;\n private readonly rings = new Map<string, RingView>();\n private readonly links = new Map<string, LinkView>();\n\n constructor(layers: RingAndLinkLayers) {\n this.layers = layers;\n }\n\n /** Draws the display's rings (unless `showRings` is off) and links. */\n paint(display: Display, showRings: boolean): void {\n this.paintRings(display, showRings);\n this.paintLinks(display);\n }\n\n /** Takes every ring and link off the map. */\n clear(): void {\n for (const view of this.rings.values()) {\n view.group.remove();\n }\n\n this.rings.clear();\n\n for (const view of this.links.values()) {\n view.element.remove();\n }\n\n this.links.clear();\n }\n\n private paintRings(display: Display, showRings: boolean): void {\n const seen = new Set<string>();\n\n if (showRings) {\n for (const ring of display.rings) {\n if (ring.opacity <= 0.01 || ring.radius <= 0) {\n continue;\n }\n\n seen.add(ring.id);\n let view = this.rings.get(ring.id);\n\n if (!view) {\n view = createRingView(ring);\n this.rings.set(ring.id, view);\n this.layers.rings.appendChild(view.group);\n }\n\n if (ring.gaps !== view.gaps || ring.radius !== view.radius) {\n const shape = `${round(ring.radius)}|${ring.gaps.map((gap) => `${round(gap.angle)}:${round(gap.halfWidth)}`).join(',')}`;\n\n if (shape !== view.shape) {\n view.line.setAttribute('d', ringPath(ring.radius, ring.gaps));\n view.band.setAttribute('d', ringPath(ring.radius, []));\n view.shape = shape;\n }\n\n view.gaps = ring.gaps;\n view.radius = ring.radius;\n }\n\n const transform = `translate(${round(ring.cx)} ${round(ring.cy)}) rotate(${round(ring.rotation)})`;\n\n if (transform !== view.transform) {\n view.group.setAttribute('transform', transform);\n view.transform = transform;\n }\n\n const ringOpacity = ring.opacity >= 0.999 ? '' : String(round(ring.opacity));\n\n if (view.group.style.opacity !== ringOpacity) {\n view.group.style.opacity = ringOpacity;\n }\n\n if (view.color !== ring.color) {\n view.line.style.setProperty('--orbit-ring-color', ring.color);\n view.color = ring.color;\n }\n }\n }\n\n for (const [id, view] of this.rings) {\n if (!seen.has(id)) {\n view.group.remove();\n this.rings.delete(id);\n }\n }\n }\n\n private paintLinks(display: Display): void {\n const seen = new Set<string>();\n\n for (const link of display.links) {\n const from = display.nodes.get(link.fromId);\n const to = display.nodes.get(link.toId);\n const opacity = Math.min(link.opacity, from?.opacity ?? 0, to?.opacity ?? 0);\n\n if (!from || !to || opacity <= 0.01) {\n continue;\n }\n\n // Edge to edge, so lines never show through translucent nodes.\n const length = Math.hypot(to.x - from.x, to.y - from.y);\n\n if (length <= from.radius + to.radius) {\n continue;\n }\n\n seen.add(link.id);\n let view = this.links.get(link.id);\n\n if (!view) {\n view = { element: svgElement('line', { class: 'orbit-link' }), geometry: '', opacity: '' };\n this.links.set(link.id, view);\n this.layers.links.appendChild(view.element);\n }\n\n const unitX = (to.x - from.x) / length;\n const unitY = (to.y - from.y) / length;\n const x1 = String(round(from.x + unitX * from.radius));\n const y1 = String(round(from.y + unitY * from.radius));\n const x2 = String(round(to.x - unitX * to.radius));\n const y2 = String(round(to.y - unitY * to.radius));\n const geometry = `${x1} ${y1} ${x2} ${y2} ${link.color}`;\n\n if (geometry !== view.geometry) {\n view.element.setAttribute('x1', x1);\n view.element.setAttribute('y1', y1);\n view.element.setAttribute('x2', x2);\n view.element.setAttribute('y2', y2);\n view.element.style.setProperty('--orbit-link-color', link.color);\n view.geometry = geometry;\n }\n\n const lineOpacity = opacity >= 0.999 ? '' : String(round(opacity));\n\n if (lineOpacity !== view.opacity) {\n view.element.style.opacity = lineOpacity;\n view.opacity = lineOpacity;\n }\n }\n\n for (const [id, view] of this.links) {\n if (!seen.has(id)) {\n view.element.remove();\n this.links.delete(id);\n }\n }\n }\n}\n\nconst createRingView = (ring: DisplayRing): RingView => {\n const group = svgElement('g', { class: 'orbit-ring-group' });\n const band = svgElement('path', { class: 'orbit-ring-band' });\n const line = svgElement('path', { class: 'orbit-ring' });\n group.append(band, line);\n group.setAttribute('data-orbit-ring', ring.centerId);\n return { group, line, band, shape: '', gaps: null, radius: 0, transform: '', color: '' };\n};\n",
|
|
62
|
+
"/**\n * Names and \"+N\" counts, in the HTML layer over the map. Each frame's names\n * are planned for its display (see `planLabels`), shown a share at a time on\n * an animated map, and ride along as one layer while only the camera moves.\n */\n\nimport type { LabelFonts } from '../engine/text-measure.js';\nimport type { Camera, Viewport } from '../engine/camera.js';\nimport type { Display, DisplayNode } from '../engine/display.js';\nimport type { Scene } from '../engine/scene.js';\nimport type { MapExtensions } from '../extensions.js';\nimport type { OrbitNode } from '../types.js';\nimport { COUNT_POSITION, NodeLabel, showsCount, type LabelPlacement, type NodeView } from '../engine/views.js';\nimport { labelOrder, planLabels, type PlannedLabel } from '../engine/labels.js';\nimport { worldToScreen } from '../engine/camera.js';\nimport { prefersLightText, resolveColor } from '../engine/colors.js';\nimport { overlayTransform } from '../browser.js';\nimport { round } from './numbers.js';\n\n/**\n * While only the camera moves, labels ride along as one layer until they're this much bigger or\n * smaller than where they were placed, or have moved `RIDE_ALONG_PAN` of the map's shorter side.\n */\nconst RIDE_ALONG_ZOOM = 1.25;\nconst RIDE_ALONG_PAN = 0.3;\n/**\n * Names that start to show, at most, on one frame of an animated map: when a\n * zoom brings hundreds of names into view at once (a crowded orbit), the rest\n * show over the next frames instead of stalling one (see paintLabels).\n */\nconst LABELS_SHOWN_PER_FRAME = 24;\n\n/** What the names need from the map around them. */\nexport interface LabelHost {\n extensions(): MapExtensions;\n viewport(): Viewport;\n\n /** The scene on screen, or null during a flight: names keep their order for a scene. */\n restingScene(): Scene | null;\n\n inFlight(): boolean;\n\n /** Whether only the camera moves: a camera flight, a wheel zoom, a glide or a drag. */\n cameraMoving(): boolean;\n\n /** Nodes changed since the last frame. */\n changedIds(): ReadonlySet<string>;\n\n /** The node whose text is being typed, which shows the field instead of its name. */\n editedId(): string | null;\n\n animationsEnabled(): boolean;\n requestPaint(): void;\n nodeView(id: string): NodeView | undefined;\n themeTokens(): Record<string, string>;\n}\n\nexport class LabelPainter {\n private readonly layer: HTMLDivElement;\n private readonly fonts: LabelFonts;\n private readonly host: LabelHost;\n private readonly labels = new Map<string, NodeLabel>();\n private readonly counts = new Map<string, { element: HTMLSpanElement; text: string; transform: string }>();\n\n /**\n * Nodes in the order their labels are placed, for one display, and their\n * ids for a scene at rest: the order holds while the orbit spins, only the\n * entries are new each frame.\n */\n private labelOrder: { nodes: Map<string, DisplayNode>; order: DisplayNode[]; scene: Scene | null; ids: string[] } | null = null;\n\n /** The camera labels and counts were last placed for, and the nodes they were placed for. */\n private placed: { camera: Camera; nodes: Map<string, DisplayNode> } | null = null;\n\n /** 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. */\n private waiting: { plans: PlannedLabel[]; moving: boolean } | null = null;\n\n private layerTransform = '';\n\n private readonly lightText = new Map<string, { color: string; light: boolean }>();\n\n /** The theme's label colors, resolved when first needed after each theme change. */\n private textColors: { light: string; dark: string; root: string } | null = null;\n\n constructor(layer: HTMLDivElement, fonts: LabelFonts, host: LabelHost) {\n this.layer = layer;\n this.fonts = fonts;\n this.host = host;\n }\n\n /** Places the names and counts for this frame's display, or lets them ride along with the camera. */\n paint(display: Display): void {\n const ride = this.ride(display);\n this.setLayerTransform(ride ?? '');\n\n if (this.waiting && (ride !== null || this.still(display))) {\n // Names still waiting to show, where they were planned: the labels ride along, or nothing moved since.\n this.showWaiting();\n } else if (ride === null) {\n this.paintLabels(display);\n this.paintCounts(display);\n this.placed = { camera: { ...display.camera }, nodes: display.nodes };\n }\n }\n\n /** Where the node's name is drawn now. */\n placementOf(id: string): LabelPlacement | undefined {\n return this.labels.get(id)?.currentPlacement;\n }\n\n /** Forgets which nodes' names are light (their colors may have changed). */\n forgetLightText(): void {\n this.lightText.clear();\n }\n\n /** Forgets the theme's text colors and which names are light (the theme changed). */\n forgetTextColors(): void {\n this.lightText.clear();\n this.textColors = null;\n }\n\n /** Forgets a node that left the map. */\n forgetNode(id: string): void {\n this.lightText.delete(id);\n }\n\n /** Takes every name and count off the map. */\n clear(): void {\n this.placed = null;\n this.waiting = null;\n this.setLayerTransform('');\n\n for (const label of this.labels.values()) {\n label.element.remove();\n }\n\n this.labels.clear();\n\n for (const badge of this.counts.values()) {\n badge.element.remove();\n }\n\n this.counts.clear();\n }\n\n /**\n * While only the camera moves (a pan, a pinch, a zoom, a glide), labels and counts ride along\n * as one layer instead of being placed again on every frame, which for a big view means\n * restyling hundreds of them. They're placed again once the camera rests, or has gone far\n * enough that they'd be too big or too small, or missing for nodes coming into view. Returns\n * the layer's transform from where they were placed, or null to place them now.\n */\n private ride(display: Display): string | null {\n const placed = this.placed;\n const moving = this.host.cameraMoving();\n\n if (!placed || !moving || placed.nodes !== display.nodes || this.host.inFlight() || this.host.changedIds().size > 0) {\n return null;\n }\n\n const { camera } = display;\n const { width, height } = this.host.viewport();\n const ratio = camera.scale / placed.camera.scale;\n const panX = (placed.camera.x - camera.x) * camera.scale;\n const panY = (placed.camera.y - camera.y) * camera.scale;\n\n if (ratio > RIDE_ALONG_ZOOM || ratio < 1 / RIDE_ALONG_ZOOM || Math.hypot(panX, panY) > RIDE_ALONG_PAN * Math.min(width, height)) {\n return null;\n }\n\n return `translate(${round((width / 2) * (1 - ratio) + panX, 2)}px, ${round((height / 2) * (1 - ratio) + panY, 2)}px) scale(${round(ratio, 5)})`;\n }\n\n /** Fits and places every label again, where it is (the fonts changed). */\n refit(): void {\n this.placed = null;\n this.waiting = null;\n this.host.requestPaint();\n }\n\n /** Whether the labels were placed for this very view: the same nodes, the camera where it was, nothing changed. */\n private still(display: Display): boolean {\n const placed = this.placed;\n return placed !== null\n && placed.nodes === display.nodes\n && placed.camera.x === display.camera.x\n && placed.camera.y === display.camera.y\n && placed.camera.scale === display.camera.scale\n && !this.host.inFlight()\n && this.host.changedIds().size === 0;\n }\n\n private setLayerTransform(transform: string): void {\n if (transform !== this.layerTransform) {\n this.layer.style.transform = transform;\n this.layerTransform = transform;\n }\n }\n private paintLabels(display: Display): void {\n if (this.labelOrder?.nodes !== display.nodes) {\n const scene = this.host.restingScene();\n const ids = scene && this.labelOrder?.scene === scene ? this.labelOrder.ids : null;\n const order = ids ? ids.map((id) => display.nodes.get(id) as DisplayNode) : labelOrder(display.nodes.values());\n this.labelOrder = { nodes: display.nodes, order, scene, ids: ids ?? order.map((entry) => entry.id) };\n }\n\n const moving = this.host.inFlight() || this.host.cameraMoving();\n // In a flight, the planets of a crowded orbit that come or go with their siblings, growing out of\n // their parent or shrinking into it, show their names once it lands: hundreds would otherwise be\n // placed again on every frame of it.\n const order = this.host.inFlight() ? this.labelOrder.order.filter((entry) => entry.cluster === undefined || entry.crowded !== true) : this.labelOrder.order;\n const planned = planLabels(display, order, {\n viewport: this.host.viewport(),\n hasImage: (entry) => this.showsImage(entry.node),\n // A picture or a type's content fills the node: its icon goes on the pill, before its name.\n pillIcon: (entry) => (this.showsImage(entry.node) ? this.host.extensions().icon(entry.node) : undefined),\n hasIcon: (entry) => Boolean(this.host.extensions().icon(entry.node)),\n previousSide: (id) => this.labels.get(id)?.direction ?? null,\n inFlight: this.host.inFlight(),\n measures: this.fonts,\n moving,\n isShown: (id) => this.labels.get(id)?.isShown ?? false,\n counts: true,\n });\n const shown = new Set<string>();\n const editedId = this.host.editedId();\n // On an animated map, only so many names start to show on one frame; the rest wait for the next.\n let showable = this.host.animationsEnabled() ? LABELS_SHOWN_PER_FRAME : Infinity;\n const waiting: PlannedLabel[] = [];\n\n // Read every new node's text color before writing any label, so the browser works out styles once, not once per label.\n for (const plan of planned) {\n if (plan.placement === 'inside') {\n this.usesLightText(plan.entry);\n }\n }\n\n for (const plan of planned) {\n const { entry } = plan;\n\n // The field shows this node's text while it is typed.\n if (entry.id === editedId) {\n continue;\n }\n\n let label = this.labels.get(entry.id);\n\n if (label && (label.node !== entry.node || this.host.changedIds().has(entry.id) || label.typeName !== this.host.extensions().typeName(entry.node))) {\n label.element.remove();\n this.labels.delete(entry.id);\n label = undefined;\n }\n\n if (!label?.isShown) {\n if (showable <= 0) {\n waiting.push(plan);\n continue;\n }\n\n showable -= 1;\n }\n\n shown.add(entry.id);\n this.showLabel(plan, label, moving);\n }\n\n this.waiting = waiting.length > 0 ? { plans: waiting, moving } : null;\n\n if (this.waiting) {\n this.host.requestPaint();\n }\n\n // Labels that aren't shown this frame stay in the DOM, hidden, while their node is on the map.\n for (const [id, label] of this.labels) {\n if (shown.has(id)) {\n continue;\n }\n\n const entry = display.nodes.get(id);\n\n if (entry) {\n label.update({ x: 0, y: 0, screenRadius: 0, role: entry.role, placement: 'hidden', opacity: 0 });\n } else {\n label.element.remove();\n this.labels.delete(id);\n }\n }\n }\n\n /** Shows a planned label: its view (made when it has none yet) placed and fitted as planned. */\n private showLabel(plan: PlannedLabel, existing: NodeLabel | undefined, moving: boolean): void {\n const { entry } = plan;\n let label = existing;\n\n if (!label) {\n label = new NodeLabel(entry.node, this.host.extensions());\n this.labels.set(entry.id, label);\n this.layer.appendChild(label.element);\n }\n\n label.update({\n x: plan.x,\n y: plan.y,\n screenRadius: plan.screenRadius,\n role: entry.role,\n placement: plan.placement,\n opacity: plan.opacity,\n light: plan.placement === 'inside' && this.usesLightText(entry),\n measure: this.fonts.inside(entry.role, entry.node),\n narrower: !moving,\n countWidth: plan.countWidth,\n direction: plan.direction,\n distance: plan.distance,\n offset: plan.offset,\n lines: plan.lines,\n width: plan.width,\n pillText: plan.text,\n });\n }\n\n /**\n * While the labels ride along with the camera, shows the next names\n * waiting to: placed as planned, for the camera the labels were placed\n * at, so they ride along with the rest.\n */\n private showWaiting(): void {\n const waiting = this.waiting;\n\n if (!waiting) {\n return;\n }\n\n const editedId = this.host.editedId();\n const now = waiting.plans.splice(0, LABELS_SHOWN_PER_FRAME);\n\n for (const plan of now) {\n const label = this.labels.get(plan.entry.id);\n\n if (plan.entry.id !== editedId && (!label || label.node === plan.entry.node)) {\n this.showLabel(plan, label, waiting.moving);\n }\n }\n\n if (waiting.plans.length > 0) {\n this.host.requestPaint();\n } else {\n this.waiting = null;\n }\n }\n\n /** Whether the node shows a picture or its type's own content, so its label goes outside. */\n private showsImage(node: OrbitNode): boolean {\n return (this.host.nodeView(node.id)?.hasImage ?? false) || Boolean(this.host.extensions().nodeType(node)?.render);\n }\n\n /** Whether the theme's light text has more contrast on this node's color than its dark text. Measured once per node and color. */\n usesLightText(entry: DisplayNode): boolean {\n const cached = this.lightText.get(entry.id);\n\n if (cached && cached.color === entry.color) {\n return cached.light;\n }\n\n const fill = this.host.nodeView(entry.id)?.resolvedFill() ?? '';\n const text = this.textColors ??= this.resolveTextColors();\n const light = fill !== '' && prefersLightText(fill, text.light, entry.role === 'sun' ? text.root : text.dark);\n this.lightText.set(entry.id, { color: entry.color, light });\n return light;\n }\n\n /** The theme's label colors as plain values. */\n private resolveTextColors(): { light: string; dark: string; root: string } {\n const tokens = this.host.themeTokens();\n return {\n light: resolveColor(tokens['node-text-inverse'], tokens),\n dark: resolveColor(tokens['node-text'], tokens),\n root: resolveColor(tokens['root-text'], tokens),\n };\n }\n\n /** 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. */\n private paintCounts(display: Display): void {\n const { camera } = display;\n const seen = new Set<string>();\n\n if (!this.host.inFlight()) {\n for (const entry of display.nodes.values()) {\n const radius = entry.radius * camera.scale;\n\n if (!showsCount(entry.role, radius, entry.hiddenChildren) || entry.opacity < 0.5) {\n continue;\n }\n\n const point = worldToScreen(camera, this.host.viewport(), entry);\n let badge = this.counts.get(entry.id);\n\n if (!badge) {\n const element = document.createElement('span');\n element.className = 'orbit-count';\n element.setAttribute('aria-hidden', 'true');\n element.dataset.orbitFor = entry.id;\n this.layer.appendChild(element);\n badge = { element, text: '', transform: '' };\n this.counts.set(entry.id, badge);\n }\n\n // New text means laying the badge out again: only when the count changes.\n const count = `+${entry.hiddenChildren}`;\n\n if (count !== badge.text) {\n badge.element.textContent = count;\n badge.text = count;\n }\n\n const transform = overlayTransform(round(point.x + radius * COUNT_POSITION, 1), round(point.y + radius * COUNT_POSITION, 1), '-50%, -50%');\n\n if (transform !== badge.transform) {\n badge.element.style.transform = transform;\n badge.transform = transform;\n }\n\n seen.add(entry.id);\n }\n }\n\n for (const [id, badge] of this.counts) {\n if (!seen.has(id)) {\n badge.element.remove();\n this.counts.delete(id);\n }\n }\n }\n}\n",
|
|
63
|
+
"/**\n * Families: the renderer draws nodes in groups of siblings, and a group whose\n * members come or go together in a flight (one `Cluster`) moves as one, with\n * one transform per frame instead of one per node.\n */\n\nimport type { Cluster, DisplayNode } from '../engine/display.js';\nimport { NodeView } from '../engine/views.js';\nimport { round } from './numbers.js';\n\n/**\n * Children of one parent, drawn in one group in the layer of their role. In\n * a flight, the members of a family often come or go together, growing out\n * of their parent or shrinking into it, and then the group moves instead of\n * each of them: one transform per frame instead of hundreds.\n */\nexport interface Family {\n group: SVGGElement;\n layer: 'sun' | 'moon' | 'node';\n parentId: string;\n transform: string;\n opacity: string;\n hidden: boolean;\n\n /** This frame's members, and the motion they all share (null if they don't), once worked out. */\n members: FamilyMember[];\n\n motion?: Cluster | null;\n}\n\nexport interface FamilyMember {\n entry: DisplayNode;\n view: NodeView;\n family: Family;\n}\n\nexport const sameMotion = (first: Cluster, second: Cluster): boolean => {\n return first.scale === second.scale && first.opacity === second.opacity && first.pivotX === second.pivotX && first.pivotY === second.pivotY;\n};\n\n/** The motion all of a family's members share this frame, or null when they move each on their own. */\nexport const familyMotion = (family: Family): Cluster | null => {\n if (family.motion === undefined) {\n const first = family.members[0]?.entry.cluster ?? null;\n family.motion = first && family.members.every((member) => member.entry.cluster && sameMotion(member.entry.cluster, first)) ? first : null;\n }\n\n return family.motion;\n};\n\n/** A cluster too faint or too small to draw. */\nexport const clusterHidden = (cluster: Cluster): boolean => {\n return cluster.opacity <= 0.01 || cluster.scale <= 0.001;\n};\n\nexport const moveFamily = (family: Family, motion: Cluster | null): void => {\n const hidden = motion !== null && clusterHidden(motion);\n\n if (hidden !== family.hidden) {\n family.group.style.display = hidden ? 'none' : '';\n family.hidden = hidden;\n }\n\n const scale = round(motion?.scale ?? 1, 4);\n const transform = motion && scale !== 1 ? `matrix(${scale} 0 0 ${scale} ${round(motion.pivotX * (1 - scale))} ${round(motion.pivotY * (1 - scale))})` : '';\n\n if (transform !== family.transform) {\n if (transform) {\n family.group.setAttribute('transform', transform);\n } else {\n family.group.removeAttribute('transform');\n }\n\n family.transform = transform;\n }\n\n const opacity = motion && motion.opacity < 0.999 ? String(round(motion.opacity, 3)) : '';\n\n if (opacity !== family.opacity) {\n family.group.style.opacity = opacity;\n family.opacity = opacity;\n }\n};\n",
|
|
64
|
+
"/**\n * The nodes on the map: a view per node, drawn in groups of siblings (see\n * `families.ts`), kept in step with each frame's display. Small flat bodies\n * become specks, an orbit spinning turns the layers its planets and moons are\n * in, and while only the camera moves the nodes hold still.\n */\n\nimport type { Display, DisplayNode } from '../engine/display.js';\nimport type { Scene } from '../engine/scene.js';\nimport type { MapExtensions } from '../extensions.js';\nimport type { OrbitWords } from '../languages.js';\nimport { NodeView, describeNode, speckRadius, svgElement, turnShading, type NodeDrawing, type ViewIds } from '../engine/views.js';\nimport { normalizeDelta } from '../engine/spin.js';\nimport { clusterHidden, familyMotion, moveFamily, sameMotion, type Family, type FamilyMember } from './families.js';\nimport { round } from './numbers.js';\n\n/** While the orbit drifts, specks are lit again each time it has turned this far (degrees) since they last were (see `paintTurn`). */\nconst RELIGHT_STEP = 10;\n/** At most this many nodes become specks, or stop being them, in one frame (see `NodeDrawing`). */\nconst SPECK_SWITCHES_PER_FRAME = 60;\n/** A flight's hidden newcomers get their views over this many frames, at least `NEWCOMERS_PER_FRAME` a frame (see paintNodes). */\nconst NEWCOMER_FRAMES = 6;\nconst NEWCOMERS_PER_FRAME = 40;\n\n/** What the nodes need from the map around them. */\nexport interface NodeHost {\n extensions(): MapExtensions;\n words(): OrbitWords;\n baseUrl(): string | undefined;\n\n /** The scene on screen (the one a flight leaves, until it lands). */\n scene(): Scene | null;\n\n inFlight(): boolean;\n\n /** Whether the orbit is at rest: not dragged, coasting or settling. */\n spinResting(): boolean;\n\n /** Whether the slow drift is running. */\n driftRunning(): boolean;\n\n /** The node whose text is being typed, if any. */\n editedId(): string | null;\n\n /** The node lifted to be dragged, the bodies carried under the press (null when nothing is), and the node it would drop into. */\n drag(): { liftedId: string | null; carried: Set<string> | null; targetId: string | null };\n\n /** Nodes changed since the last frame. */\n changedIds(): ReadonlySet<string>;\n\n requestPaint(): void;\n\n /** A node's view came on the map: the map's tab stops need placing again. */\n tabStopsChanged(): void;\n\n /** A node's view left the map. */\n viewRemoved(id: string): void;\n}\n\n/** The layers nodes are drawn in. */\nexport interface NodeLayers {\n moons: SVGGElement;\n nodes: SVGGElement;\n suns: SVGGElement;\n carried: SVGGElement;\n}\n\nexport class NodePainter {\n private readonly root: HTMLDivElement;\n private readonly definitions: SVGDefsElement;\n private readonly ids: ViewIds;\n private readonly layers: NodeLayers;\n private readonly host: NodeHost;\n\n /** The orbit's turn as last written to the layers of its planets and moons (see `paintTurn`). */\n private turnTransform = '';\n\n /** The turn the shading of specks is turned back by (see `turnShading`). */\n private speckLighting = 0;\n\n /** The on-screen radius (px) below which bodies were last drawn as specks (see `speckRadius`). */\n private specksBelow = 0;\n\n /**\n * The nodes as last painted at rest, with what they were drawn for: while\n * only the camera or the orbit's turn changes, they hold still, all but\n * the bodies turned back upright (see `paintNodes`).\n */\n private stillNodes: { scene: Scene; scale: number; speckRadius: number; editedId: string | null; turnedBack: NodeView[] } | null = null;\n\n private readonly nodeViews = new Map<string, NodeView>();\n\n /** The family group each node's element is in (see `Family`). */\n private readonly nodeGroups = new Map<string, Family>();\n\n private readonly families = new Map<string, Family>();\n\n /** Counts flights, so each one's arrivals get groups of their own. */\n private flightCount = 0;\n\n private familyCount = 0;\n\n /** The lifted node and the drop target last drawn, so a change draws every node again. */\n private dragMarks = '\\n';\n\n constructor(root: HTMLDivElement, definitions: SVGDefsElement, ids: ViewIds, layers: NodeLayers, host: NodeHost) {\n this.root = root;\n this.definitions = definitions;\n this.ids = ids;\n this.layers = layers;\n this.host = host;\n }\n\n /** The view drawing a node, if it's on the map. */\n view(id: string): NodeView | undefined {\n return this.nodeViews.get(id);\n }\n\n /** Every node's view, by id. */\n entries(): IterableIterator<[string, NodeView]> {\n return this.nodeViews.entries();\n }\n\n /** A new flight starts: the ideas it brings in get families of their own. */\n startFlight(): void {\n this.flightCount += 1;\n }\n\n /** Takes a node's view off the map. */\n removeView(id: string): void {\n this.nodeViews.get(id)?.element.remove();\n this.nodeViews.delete(id);\n this.stillNodes = null;\n this.nodeGroups.delete(id);\n this.host.viewRemoved(id);\n }\n\n /** Takes every node off the map. */\n clear(): void {\n for (const id of Array.from(this.nodeViews.keys())) {\n this.removeView(id);\n }\n\n for (const family of this.families.values()) {\n family.group.remove();\n }\n\n this.families.clear();\n }\n\n /**\n * Turns the layers of the planets and moons with the orbit (see\n * `OrbitTurn`). Returns the turn (degrees) its bodies are drawn in, or\n * undefined when each is drawn where it is.\n */\n paintTurn(display: Display): number | undefined {\n const { turn } = display;\n const rotation = turn ? round(normalizeDelta(turn.rotation), 3) : 0;\n const transform = turn && rotation !== 0 ? `rotate(${rotation} ${round(turn.cx)} ${round(turn.cy)})` : '';\n\n if (transform !== this.turnTransform) {\n for (const layer of [this.layers.moons, this.layers.nodes]) {\n if (transform) {\n layer.setAttribute('transform', transform);\n } else {\n layer.removeAttribute('transform');\n }\n }\n\n this.turnTransform = transform;\n }\n\n // Specks turn with the orbit, shading and all, while it spins or flies;\n // lighting them all again takes a while, so they're lit from the top left once it rests.\n const lighting = transform ? rotation : 0;\n const resting = !this.host.inFlight() && this.host.spinResting();\n\n if (resting && Math.abs(normalizeDelta(lighting - this.speckLighting)) > (this.host.driftRunning() ? RELIGHT_STEP : 0)) {\n turnShading(this.definitions, this.ids, lighting);\n this.speckLighting = lighting;\n }\n\n return turn ? rotation : undefined;\n }\n\n paintNodes(display: Display, turn: number | undefined): void {\n const editedId = this.host.editedId();\n const scene = this.host.scene();\n const flying = this.host.inFlight();\n const pixelRatio = this.root.ownerDocument.defaultView?.devicePixelRatio ?? 1;\n const drawing: NodeDrawing = { turn, speckRadius: this.speckRadius(), crowdedSpeckRadius: speckRadius(pixelRatio, true), switches: SPECK_SWITCHES_PER_FRAME, waiting: false, flight: flying };\n // A node lifted to be dragged, carried under the press, and the node it would be dropped into.\n const { liftedId, carried, targetId } = this.host.drag();\n const marks = `${liftedId}\\n${targetId}`;\n\n if (carried || marks !== this.dragMarks) {\n this.stillNodes = null;\n }\n\n this.dragMarks = marks;\n // Only the camera or the orbit's turn changed since the last frame at rest: the bodies turned back upright are all that move.\n const still = this.stillNodes;\n\n if (!flying && still && still.scene === scene && still.scale === display.camera.scale && still.speckRadius === drawing.speckRadius && still.editedId === editedId && this.host.changedIds().size === 0) {\n for (const view of still.turnedBack) {\n const entry = display.nodes.get(view.id);\n\n if (entry) {\n view.update(entry, entry.radius * display.camera.scale, drawing);\n }\n }\n\n return;\n }\n\n this.stillNodes = null;\n const placed: FamilyMember[] = [];\n // Ideas a flight brings in stay hidden for its first quarter: their views are created over its\n // first frames, a share at a time, instead of all at once as it starts.\n let waiting = 0;\n\n if (this.host.inFlight()) {\n for (const entry of display.nodes.values()) {\n if (entry.cluster && clusterHidden(entry.cluster) && !this.nodeViews.has(entry.id)) {\n waiting += 1;\n }\n }\n }\n\n let creatable = Math.max(NEWCOMERS_PER_FRAME, Math.ceil(waiting / NEWCOMER_FRAMES));\n\n for (const entry of display.nodes.values()) {\n let view = this.nodeViews.get(entry.id);\n\n if (view && (view.node !== entry.node || this.host.changedIds().has(entry.id) || view.typeName !== this.host.extensions().typeName(entry.node))) {\n this.removeView(entry.id);\n view = undefined;\n }\n\n if (!view && this.host.inFlight() && entry.cluster && clusterHidden(entry.cluster)) {\n if (creatable <= 0) {\n continue;\n }\n\n creatable -= 1;\n }\n\n if (!view) {\n view = new NodeView(entry, entry.radius * display.camera.scale, this.ids, this.host.baseUrl(), this.host.extensions(), drawing, () => this.host.requestPaint());\n view.element.setAttribute('aria-label', describeNode(entry.node, 0, entry.node.children.length, this.host.extensions(), this.host.words()));\n this.nodeViews.set(entry.id, view);\n this.host.tabStopsChanged();\n }\n\n if (carried?.has(entry.id)) {\n // Carried above everything, where the press is, outside the orbit's turn.\n if (view.element.parentNode !== this.layers.carried) {\n this.nodeGroups.delete(entry.id);\n this.layers.carried.appendChild(view.element);\n }\n\n view.update(entry, entry.radius * display.camera.scale, { ...drawing, turn: undefined }, true);\n view.setLifted(entry.id === liftedId);\n view.setDropTarget(false);\n continue;\n }\n\n const family = this.placeInFamily(entry, view);\n\n if (flying) {\n const member = { entry, view, family };\n family.members.push(member);\n placed.push(member);\n } else {\n // At rest no family moves as one: each node is drawn where it is.\n view.update(entry, entry.radius * display.camera.scale, drawing);\n view.setEditing(entry.id === editedId);\n view.setLifted(entry.id === liftedId);\n view.setDropTarget(entry.id === targetId);\n }\n }\n\n for (const id of Array.from(this.nodeViews.keys())) {\n if (!display.nodes.has(id)) {\n this.removeView(id);\n }\n }\n\n if (flying) {\n for (const family of Array.from(this.families.values())) {\n this.splitIfMixed(family);\n }\n\n for (const { entry, view, family } of placed) {\n // A family moving as one holds still in its group, each member where it rests, and the group moves.\n const resting = familyMotion(family) ? entry.cluster : undefined;\n\n if (resting) {\n view.update({ ...entry, x: resting.x, y: resting.y, radius: resting.radius, opacity: resting.nodeOpacity }, entry.radius * display.camera.scale, drawing);\n } else {\n view.update(entry, entry.radius * display.camera.scale, drawing, true);\n }\n\n view.setEditing(entry.id === editedId);\n view.setLifted(entry.id === liftedId);\n view.setDropTarget(entry.id === targetId);\n }\n }\n\n for (const [key, family] of this.families) {\n if (family.group.childElementCount === 0) {\n family.group.remove();\n this.families.delete(key);\n continue;\n }\n\n moveFamily(family, familyMotion(family));\n family.members = [];\n family.motion = undefined;\n }\n\n if (drawing.waiting) {\n this.host.requestPaint();\n } else if (!flying && scene) {\n const turnedBack = Array.from(this.nodeViews.values()).filter((view) => view.isTurnedBack);\n this.stillNodes = { scene, scale: display.camera.scale, speckRadius: drawing.speckRadius, editedId, turnedBack };\n }\n }\n\n /**\n * The on-screen radius (px) below which flat bodies are specks, for this\n * screen's pixels; the stylesheet sizes specks' rims from it.\n */\n private speckRadius(): number {\n const radius = speckRadius(this.root.ownerDocument.defaultView?.devicePixelRatio ?? 1);\n\n if (radius !== this.specksBelow) {\n this.root.style.setProperty('--_orbit-speck-rim', String(round(1 / radius, 4)));\n this.specksBelow = radius;\n }\n\n return radius;\n }\n\n /**\n * A family whose members don't all move alike in this flight (some travel\n * on, the rest leave) splits in two, the fewer of them moving to a group of\n * their own, so each part moves as one.\n */\n private splitIfMixed(family: Family): void {\n const first = family.members.find((member) => member.entry.cluster)?.entry.cluster;\n\n if (!first) {\n return;\n }\n\n const alike = family.members.filter((member) => member.entry.cluster && sameMotion(member.entry.cluster, first));\n const others = family.members.filter((member) => !(member.entry.cluster && sameMotion(member.entry.cluster, first)));\n\n if (others.length === 0 || alike.length < 2) {\n return;\n }\n\n const [moving, staying] = alike.length <= others.length ? [alike, others] : [others, alike];\n this.familyCount += 1;\n const part = this.createFamily(`${family.layer}|${family.parentId}|${this.flightCount}.${this.familyCount}`, family.layer, family.parentId);\n\n for (const member of moving) {\n this.moveIntoFamily(member.view, member.entry.id, part);\n member.family = part;\n part.members.push(member);\n }\n\n family.members = staying;\n }\n\n /**\n * The group a node is drawn in: its family's, in the layer of its role. A\n * node stays in its group while its parent and role do, so nothing moves\n * between groups when a flight lands; the ideas a flight brings in get a\n * group of their own, so they can move as one while their siblings travel.\n */\n private placeInFamily(entry: DisplayNode, view: NodeView): Family {\n const layer = entry.role === 'sun' ? 'sun' : entry.role === 'moon' ? 'moon' : 'node';\n const parentId = entry.parentId ?? '';\n const current = this.nodeGroups.get(entry.id);\n\n if (current && current.layer === layer && current.parentId === parentId) {\n return current;\n }\n\n const key = `${layer}|${parentId}${entry.cluster && this.host.inFlight() ? `|${this.flightCount}` : ''}`;\n const family = this.families.get(key) ?? this.createFamily(key, layer, parentId, entry.cluster !== undefined && clusterHidden(entry.cluster));\n this.moveIntoFamily(view, entry.id, family);\n return family;\n }\n\n /** 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. */\n private createFamily(key: string, layer: Family['layer'], parentId: string, hidden = false): Family {\n const group = svgElement('g', { class: 'orbit-family' });\n\n if (hidden) {\n group.style.display = 'none';\n }\n\n this.layers[layer === 'sun' ? 'suns' : layer === 'moon' ? 'moons' : 'nodes'].appendChild(group);\n const family: Family = { group, layer, parentId, transform: '', opacity: '', hidden, members: [] };\n this.families.set(key, family);\n return family;\n }\n\n private moveIntoFamily(view: NodeView, id: string, family: Family): void {\n const hadFocus = this.root.ownerDocument.activeElement === view.element;\n family.group.appendChild(view.element);\n this.nodeGroups.set(id, family);\n\n if (hadFocus) {\n view.element.focus({ preventScroll: true });\n }\n }\n}\n",
|
|
65
|
+
"/**\n * What node types draw inside their nodes (`render`), in an HTML layer over\n * the map: a 100 × 100 px box per node, moved and scaled with it each frame,\n * created when the node comes on the map and cleaned up when it leaves.\n */\n\nimport type { Display } from '../engine/display.js';\nimport type { Viewport } from '../engine/camera.js';\nimport type { MapExtensions } from '../extensions.js';\nimport type { OrbitNode } from '../types.js';\nimport { worldToScreen } from '../engine/camera.js';\nimport { applyTypeTokens, markNode } from '../engine/views.js';\nimport { guarded } from '../extensions.js';\nimport { round } from './numbers.js';\n\n/** What a node type draws inside one node, and how it was last placed. */\ninterface NodeContent {\n element: HTMLDivElement;\n node: OrbitNode;\n cleanup?: () => void;\n transform: string;\n opacity: string;\n visible: boolean;\n}\n\n/** What node contents need from the map around them. */\nexport interface ContentHost {\n extensions(): MapExtensions;\n viewport(): Viewport;\n\n /** Nodes changed since the last frame. */\n changedIds(): ReadonlySet<string>;\n}\n\nexport class ContentPainter {\n private readonly layer: HTMLDivElement;\n private readonly host: ContentHost;\n private readonly contents = new Map<string, NodeContent>();\n\n constructor(layer: HTMLDivElement, host: ContentHost) {\n this.layer = layer;\n this.host = host;\n }\n\n /** Cleans up every node's content. */\n clear(): void {\n for (const id of Array.from(this.contents.keys())) {\n this.remove(id);\n }\n }\n\n /**\n * Draws what node types render inside their nodes: a 100 × 100 px box per\n * node, moved and scaled with it each frame, created when the node comes\n * on the map and cleaned up when it leaves.\n */\n paint(display: Display): void {\n const { camera } = display;\n const seen = new Set<string>();\n\n for (const entry of display.nodes.values()) {\n const type = this.host.extensions().nodeType(entry.node);\n\n if (!type?.render) {\n continue;\n }\n\n let content = this.contents.get(entry.id);\n\n if (content && (content.node !== entry.node || this.host.changedIds().has(entry.id))) {\n this.remove(entry.id);\n content = undefined;\n }\n\n if (!content) {\n const element = document.createElement('div');\n element.className = 'orbit-node-content';\n element.dataset.orbitFor = entry.id;\n markNode(element, entry.node, this.host.extensions().typeName(entry.node));\n applyTypeTokens(element, type);\n this.layer.appendChild(element);\n const render = type.render;\n const cleanup = guarded(`The \"${this.host.extensions().typeName(entry.node)}\" node type's render()`, undefined, () => render(entry.node, element));\n content = { element, node: entry.node, cleanup: typeof cleanup === 'function' ? cleanup : undefined, transform: '', opacity: '', visible: true };\n this.contents.set(entry.id, content);\n }\n\n seen.add(entry.id);\n const radius = entry.radius * camera.scale;\n const visible = entry.opacity > 0.01 && radius >= 6;\n\n if (visible !== content.visible) {\n content.element.style.display = visible ? '' : 'none';\n content.visible = visible;\n }\n\n if (!visible) {\n continue;\n }\n\n const point = worldToScreen(camera, this.host.viewport(), entry);\n const transform = `translate3d(${round(point.x - 50, 1)}px, ${round(point.y - 50, 1)}px, 0) scale(${round(radius / 50, 4)})`;\n\n if (transform !== content.transform) {\n content.element.style.transform = transform;\n content.transform = transform;\n }\n\n const opacity = entry.opacity >= 0.999 ? '' : String(round(entry.opacity, 3));\n\n if (opacity !== content.opacity) {\n content.element.style.opacity = opacity;\n content.opacity = opacity;\n }\n }\n\n for (const id of Array.from(this.contents.keys())) {\n if (!seen.has(id)) {\n this.remove(id);\n }\n }\n }\n\n private remove(id: string): void {\n const content = this.contents.get(id);\n\n if (!content) {\n return;\n }\n\n content.element.remove();\n this.contents.delete(id);\n\n if (content.cleanup) {\n guarded('A node type\\'s render() cleanup', undefined, content.cleanup);\n }\n }\n}\n",
|
|
66
|
+
"/**\n * The renderer's options: the caller's merged over the document's over the\n * defaults, and the values Orbit works out from them (insets, spin settings).\n */\n\nimport type { Insets } from '../engine/camera.js';\nimport { DEFAULT_SPIN_SETTINGS, type SpinSettings } from '../engine/spin.js';\nimport { mergeThemes } from '../themes.js';\nimport type { OrbitInsets, OrbitSpinOptions, RendererOptions } from '../types.js';\n\nexport type ResolvedRendererOptions = RendererOptions &\n Required<Pick<RendererOptions, 'viewMode' | 'showRings' | 'interactive' | 'orbitAnimation' | 'orbitSpeed' | 'showControls'>>;\n\nexport const spinSettings = (options: OrbitSpinOptions | undefined): SpinSettings => {\n return {\n ...DEFAULT_SPIN_SETTINGS,\n ...(options?.decay !== undefined && options.decay > 0 ? { decay: options.decay } : {}),\n ...(options?.maxSpeed !== undefined && options.maxSpeed > 0 ? { maxSpeed: options.maxSpeed } : {}),\n snap: options?.snap === 'planet',\n };\n};\n\nexport const mergeRendererOptions = (base: RendererOptions, overrides: RendererOptions): ResolvedRendererOptions => {\n const merged: Record<string, unknown> = { ...base };\n\n for (const [key, value] of Object.entries(overrides)) {\n if (value !== undefined) {\n merged[key] = value;\n }\n }\n\n merged.theme = mergeThemes(base.theme, overrides.theme);\n return merged as unknown as ResolvedRendererOptions;\n};\n\n/** The room the page's controls take at the map's edges, as numbers of px (none for anything else). */\nexport const resolveInsets = (insets: OrbitInsets | undefined): Insets => {\n const side = (value: number | undefined) => (typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : 0);\n return { top: side(insets?.top), right: side(insets?.right), bottom: side(insets?.bottom), left: side(insets?.left) };\n};\n",
|
|
67
|
+
"/** The page around a map: its elements, events, focus and scrolling, as the renderer reads them. */\n\nimport { OrbitWords } from '../languages.js';\n\nexport const reportListenerError = (error: unknown): void => {\n const report = (globalThis as { reportError?: (error: unknown) => void }).reportError;\n\n if (typeof report === 'function') {\n report(error);\n } else {\n setTimeout(() => {\n throw error;\n });\n }\n};\n\nexport const createEmptyState = (words: OrbitWords): HTMLDivElement => {\n const empty = document.createElement('div');\n empty.className = 'orbit-empty';\n empty.hidden = true;\n fillEmptyState(empty, words);\n return empty;\n};\n\n/** The empty map's message and hint, in `words`' language. */\nexport const fillEmptyState = (empty: HTMLDivElement, words: OrbitWords): void => {\n const title = document.createElement('strong');\n title.textContent = words.text('emptyMap');\n const hint = document.createElement('span');\n hint.textContent = words.text('emptyMapHint');\n empty.replaceChildren(title, hint);\n};\n\n/** The + in arrow-key order around the orbit. */\nexport const SLOT_STOP = '\\u0000slot';\n\nexport const isAddSlot = (target: EventTarget | null): boolean => {\n return Boolean(target && typeof (target as Element).closest === 'function' && (target as Element).closest('[data-orbit-add]'));\n};\n\nexport const nodeIdFrom = (target: EventTarget | null): string | null => {\n const element = target && typeof (target as Element).closest === 'function' ? (target as Element).closest('[data-orbit-node-id]') : null;\n return element?.getAttribute('data-orbit-node-id') ?? null;\n};\n\nexport const isFocusVisible = (target: EventTarget | null): boolean => {\n try {\n return (target as Element).matches(':focus-visible');\n } catch {\n return true;\n }\n};\n\nexport const isApplePlatform = (): boolean => {\n return typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent);\n};\n\n/** Whether the document, or any element around `element`, can scroll. */\nexport const scrollsAround = (element: Element): boolean => {\n const document = element.ownerDocument;\n const scroller = document.scrollingElement;\n\n if (scroller && scroller.scrollHeight > scroller.clientHeight + 1) {\n return true;\n }\n\n let current: Element | null = parentAcrossShadow(element);\n\n while (current && current !== document.documentElement && current !== document.body) {\n if (current.scrollHeight > current.clientHeight + 1 && typeof getComputedStyle === 'function') {\n const overflow = getComputedStyle(current).overflowY;\n\n if (overflow === 'auto' || overflow === 'scroll') {\n return true;\n }\n }\n\n current = parentAcrossShadow(current);\n }\n\n return false;\n};\n\nexport const parentAcrossShadow = (element: Element): Element | null => {\n if (element.parentElement) {\n return element.parentElement;\n }\n\n const root = element.getRootNode();\n return typeof ShadowRoot !== 'undefined' && root instanceof ShadowRoot ? root.host : null;\n};\n",
|
|
68
|
+
"/**\n * Views of a scene the renderer works out: where its orbit starts, its planets\n * in order, what of a display shows, where a view lands inside another, and a\n * flight's display with a new or renamed node in it.\n */\n\nimport type { Camera, Similarity, Viewport } from '../engine/camera.js';\nimport { sceneDisplay, type Display, type DisplayNode } from '../engine/display.js';\nimport type { Scene, SceneNode } from '../engine/scene.js';\n\n/** 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. */\nexport const RELAYOUT_THRESHOLD = 0.02;\n\n/** A node an edit just added, and where it was typed: its first frame is there. */\nexport interface Arrival {\n id: string;\n x: number;\n y: number;\n radius: number;\n}\n\n/** Whether `size` is within `RELAYOUT_THRESHOLD` of `laidOut` in both directions. */\nexport const closeInSize = (size: Viewport, laidOut: Viewport): boolean => {\n return Math.abs(size.width - laidOut.width) <= laidOut.width * RELAYOUT_THRESHOLD\n && Math.abs(size.height - laidOut.height) <= laidOut.height * RELAYOUT_THRESHOLD;\n};\n\n/** How far the nearest planet's edge (or the +'s) is from the sun, in world units: the room around the sun. */\nexport const innerEdges = new WeakMap<Scene, number>();\n\nexport const innerOrbitEdge = (scene: Scene): number => {\n let edge = innerEdges.get(scene);\n\n if (edge === undefined) {\n edge = Infinity;\n\n for (const node of scene.nodes.values()) {\n if (node.role === 'planet' && node.orbitRadius !== undefined) {\n edge = Math.min(edge, node.orbitRadius - node.radius);\n }\n }\n\n if (scene.addSlot) {\n edge = Math.min(edge, scene.addSlot.orbitRadius - scene.addSlot.radius);\n }\n\n innerEdges.set(scene, edge);\n }\n\n return edge;\n};\n\n/** Planets clockwise from the top. */\nexport const orderedPlanets = (scene: Scene): SceneNode[] => {\n return Array.from(scene.nodes.values())\n .filter((node) => node.role === 'planet')\n .sort((left, right) => clockwiseFromTop(left.orbitAngle ?? 0) - clockwiseFromTop(right.orbitAngle ?? 0));\n};\n\nexport const clockwiseFromTop = (angle: number): number => {\n return (((angle + 90) % 360) + 360) % 360;\n};\n\n/** Places `target` so its fitted view matches `camera`: the views cross-fade without the camera moving. */\nexport const overlayPlacement = (target: Scene, camera: Camera): Similarity => {\n const scale = target.frame.scale / camera.scale;\n return { scale, x: camera.x - target.frame.x * scale, y: camera.y - target.frame.y * scale };\n};\n\n/** Drops what has already faded out, so it isn't carried into the next flight. */\nexport const visiblePart = (display: Display): Display => {\n const nodes = new Map<string, DisplayNode>();\n\n for (const [id, node] of display.nodes) {\n if (node.opacity > 0.01 && node.radius > 0.01) {\n nodes.set(id, node);\n }\n }\n\n return {\n nodes,\n rings: display.rings.filter((ring) => ring.opacity > 0.01),\n links: display.links.filter((link) => link.opacity > 0.01),\n camera: display.camera,\n addSlot: display.addSlot && display.addSlot.opacity > 0.01 ? display.addSlot : undefined,\n };\n};\n\n/** `display` with a node an edit just added already where it was typed, so it stays there as the others make room. */\nexport const withArrival = (display: Display, arrival: Arrival | null, target: Scene): Display => {\n if (!arrival || display.nodes.has(arrival.id)) {\n return display;\n }\n\n const end = sceneDisplay(target, 0, target.frame).nodes.get(arrival.id);\n\n if (!end) {\n return display;\n }\n\n const nodes = new Map(display.nodes);\n nodes.set(arrival.id, { ...end, x: arrival.x, y: arrival.y, radius: arrival.radius });\n return { ...display, nodes };\n};\n\n/** `display` with the nodes an edit gave new ids under the new ones, so they move rather than leave and arrive. */\nexport const renameNodes = (display: Display, renamed: ReadonlyMap<string, string>): Display => {\n if (renamed.size === 0) {\n return display;\n }\n\n const rename = (id: string): string => renamed.get(id) ?? id;\n const nodes = new Map<string, DisplayNode>();\n\n for (const node of display.nodes.values()) {\n const id = rename(node.id);\n nodes.set(id, {\n ...node,\n id,\n parentId: node.parentId === undefined ? undefined : rename(node.parentId),\n hostId: node.hostId === undefined ? undefined : rename(node.hostId),\n });\n }\n\n return {\n ...display,\n nodes,\n rings: display.rings.map((ring) => ({ ...ring, centerId: rename(ring.centerId) })),\n links: display.links.map((link) => {\n const fromId = rename(link.fromId);\n const toId = rename(link.toId);\n return { ...link, id: `${fromId}->${toId}`, fromId, toId };\n }),\n };\n};\n",
|
|
69
|
+
"/** Maps as the renderer takes them: documents or trees, compared, checked and carried over between renders. */\n\nimport { documentSource, setDocumentSource, type NodeRecord } from '../document-source.js';\nimport { OrbitWords } from '../languages.js';\nimport { hasMediaSource } from '../media.js';\nimport type { OrbitDocument, OrbitNode } from '../types.js';\nimport type { EditorText } from '../ui/inline-editor.js';\n\n/** The field's text for a new idea under `parent`. */\nexport const newIdeaText = (parent: OrbitNode, words: OrbitWords): EditorText => {\n return { label: words.text('newIdeaFor', { name: parent.text || words.text('thisIdea') }), placeholder: words.text('newIdea'), enterKey: 'next' };\n};\n\nexport const sameValues = (first: unknown, second: unknown): boolean => {\n if (first === second) {\n return true;\n }\n\n if (!first || !second || typeof first !== 'object' || typeof second !== 'object') {\n return false;\n }\n\n const firstKeys = Object.keys(first);\n const secondKeys = Object.keys(second);\n return firstKeys.length === secondKeys.length\n && firstKeys.every((key) => sameValues((first as Record<string, unknown>)[key], (second as Record<string, unknown>)[key]));\n};\n\n/** Says how to call an editing method that got something other than an object. */\nexport const expectObject = (method: string, value: unknown, example: string): void => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new TypeError(`${method}() takes the node's text and attributes as an object, like ${example}, but got ${value === null ? 'null' : Array.isArray(value) ? 'an array' : typeof value}.`);\n }\n};\n\n/** Whether two trees hold the same map: the same nodes, ids and attributes, wherever their source wrote them. */\nexport const sameTree = (first: OrbitNode, second: OrbitNode): boolean => {\n const attributes = (node: OrbitNode): Record<string, unknown> =>\n Object.fromEntries(Object.entries(node).filter(([key, value]) => key !== 'source' && key !== 'children' && value !== undefined));\n return sameValues(attributes(first), attributes(second))\n && first.children.length === second.children.length\n && first.children.every((child, index) => sameTree(child, second.children[index]));\n};\n\n/**\n * Moves where a fresh parse of the same map came from onto the tree as drawn:\n * each node's own place, and the source itself (keyed by node, see\n * `documentSource`), so saving writes the new text against the nodes the map\n * already shows.\n */\nexport const transplantSource = (kept: OrbitNode, fresh: OrbitNode): void => {\n const pairs = new Map<OrbitNode, OrbitNode>();\n\n const pair = (keptNode: OrbitNode, freshNode: OrbitNode): void => {\n pairs.set(freshNode, keptNode);\n keptNode.source = freshNode.source;\n freshNode.children.forEach((child, index) => pair(keptNode.children[index], child));\n };\n\n pair(kept, fresh);\n const source = documentSource({ root: fresh });\n\n if (!source) {\n return;\n }\n\n const records = new WeakMap<OrbitNode, NodeRecord>();\n\n for (const [freshNode, keptNode] of pairs) {\n const record = source.records.get(freshNode);\n\n if (record) {\n records.set(keptNode, { ...record, children: record.children.map((child) => pairs.get(child) ?? child) });\n }\n }\n\n setDocumentSource({ root: kept }, {\n ...source,\n root: kept,\n records,\n owners: source.owners.map((owner) => (owner === null ? null : (pairs.get(owner) ?? owner))),\n });\n};\n\n/** An object's entries that have a value. */\nexport const definedEntries = (value: object): Record<string, unknown> => {\n return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));\n};\n\nexport const isOrbitDocument = (input: OrbitNode | OrbitDocument): input is OrbitDocument => {\n return typeof (input as OrbitDocument).root === 'object' && (input as OrbitDocument).root !== null && !('children' in input);\n};\n\nexport const isEmptyTree = (tree: OrbitNode): boolean => {\n return tree.text.trim() === '' && !tree.icon && tree.children.length === 0\n && !hasMediaSource(tree.image) && !hasMediaSource(tree.video) && !hasMediaSource(tree.embed);\n};\n",
|
|
70
|
+
"/**\n * OrbitSVGRenderer draws a map into a container element and makes it\n * explorable.\n *\n * Each view (a node in focus, or the overview) is a scene in world\n * coordinates (engine/scene.ts), seen through one camera. Moving between\n * views flies the camera along a smooth zoom path while the nodes both views\n * share move into place; when the flight lands, the world is re-rooted on\n * the new scene. In focus mode the orbit spins with momentum when flicked,\n * zooming far enough into a planet enters it, and zooming out leaves.\n *\n * Nodes, rings and links are SVG under one camera transform. Labels, badges,\n * controls and the detail sheet are HTML on top, so text stays sharp and\n * readable at any zoom.\n */\n\nimport type {\n OrbitActionDetail,\n OrbitDocument,\n OrbitDocumentOptions,\n OrbitEdit,\n OrbitEditorEvent,\n OrbitEventMap,\n OrbitEventName,\n OrbitMediaEvent,\n OrbitMediaOptions,\n OrbitMediaState,\n OrbitNode,\n OrbitNodeContextEvent,\n OrbitNodeDragEvent,\n OrbitNewNode,\n OrbitNodeInput,\n OrbitRendererTheme,\n OrbitThemePreset,\n RendererOptions,\n ViewMode,\n} from './types.js';\nimport { DEFAULT_OPTIONS } from './types.js';\nimport { findNodeById, getNodePath } from './utils.js';\nimport { addToTree, moveInTree, removeFromTree, updateInTree } from './editing.js';\nimport { branchPalette, type BranchColorRules } from './branch-colors.js';\nimport { serializeOrbitMarkdown } from './serializer-markdown.js';\n\nimport { documentToRendererOptions } from './document-options.js';\n\nimport { parseOrbit } from './dispatch.js';\nimport { guardUrl, resolveUrl } from './url-guard.js';\n\nimport { THEME_TOKENS, expandTheme, isThemeName, resolvePalette, resolveThemeTokens, themeName, themeNames, themeOverrides, type OrbitThemeToken } from './themes.js';\nimport { ensureStyles } from './styles.js';\nimport { InputController, wheelZoomFactor, type DragGesture, type Point } from './input-controller.js';\nimport { AnimationClock, easeInOutCubic, type FrameTask } from './engine/animation-clock.js';\nimport {\n IDENTITY,\n cameraTransform,\n panBy,\n screenToWorld,\n smoothZoomPath,\n worldToScreen,\n zoomAround,\n type Camera,\n type CameraPath,\n type Insets,\n type Similarity,\n type Viewport,\n} from './engine/camera.js';\nimport { AngularVelocityTracker, SpinPhysics, normalizeDelta } from './engine/spin.js';\nimport { Glide, PointVelocityTracker } from './engine/glide.js';\nimport { alignScene, assignNodeColors, buildFocusScene, buildOverviewScene, fitScene, toDegrees, type NodeRole, type Scene, type SceneNode, type SceneOptions } from './engine/scene.js';\nimport { fadeDisplay, placedFrame, sceneDisplay, transitionDisplay, type Display, type DisplayNode, type DisplaySlot, type Transition } from './engine/display.js';\nimport {\n AddSlotView,\n COUNT_HEIGHT,\n COUNT_POSITION,\n createDefinitions,\n describeNode,\n insideFontSize,\n insideLabelLayout,\n insideLabelReach,\n insideLabelWidth,\n measureCount,\n showsCount,\n svgElement,\n placeShading,\n readShadeCircle,\n type ViewIds,\n} from './engine/views.js';\nimport { nodeUnder, orbitPlaceAt, samePlace, unreachableIds, type DropPlace } from './engine/node-drag.js';\nimport { exportDisplay } from './engine/export.js';\nimport { LabelFonts, onMeasurementsReset } from './engine/text-measure.js';\nimport { resolveColor } from './engine/colors.js';\nimport { Controls } from './ui/controls.js';\nimport { AccessibleOutline, Tooltip } from './ui/outline.js';\nimport { DetailSheet, type DetailSection } from './ui/detail-sheet.js';\nimport { MediaViewer, galleryItems, showsMedia, type MediaItem, type MediaKind } from './ui/media-viewer.js';\nimport type { PlaybackState } from './ui/media-players.js';\nimport { ActionBar, actionRows, type ActionRows, type LinkDescription } from './ui/actions.js';\nimport { InlineEditor, type EditorPlacement } from './ui/inline-editor.js';\nimport { findLinkedNode, isNodeLink } from './node-links.js';\nimport { MapExtensions, actionLabel, guarded, upgradeTypes } from './extensions.js';\nimport { noteToPlainText } from './ui/note-markdown.js';\nimport { OrbitWords, languageOf } from './languages.js';\nimport { RingsAndLinks } from './renderer/rings-and-links.js';\nimport { LabelPainter } from './renderer/label-painter.js';\nimport { NodePainter } from './renderer/node-painter.js';\nimport { ContentPainter } from './renderer/content-painter.js';\nimport { mergeRendererOptions, resolveInsets, spinSettings, type ResolvedRendererOptions } from './renderer/options.js';\nimport { SLOT_STOP, createEmptyState, fillEmptyState, isAddSlot, isApplePlatform, isFocusVisible, nodeIdFrom, reportListenerError, scrollsAround } from './renderer/dom.js';\nimport { clockwiseFromTop, closeInSize, innerOrbitEdge, orderedPlanets, overlayPlacement, renameNodes, visiblePart, withArrival, type Arrival } from './renderer/scene-helpers.js';\nimport { definedEntries, expectObject, isEmptyTree, isOrbitDocument, newIdeaText, sameTree, sameValues, transplantSource } from './renderer/trees.js';\n\n/** Zoom (relative to the fitted view) past which zooming toward a planet or moon enters it. */\nconst ENTER_ZOOM = 1.75;\n/**\n * …and once the planet under the pointer is this big on screen (px), big\n * enough to read inside: a crowded orbit can be zoomed into and read\n * before it enters a planet.\n */\nconst ENTER_RADIUS = 42;\n/** Zoom below which focus mode goes up a level, or from the root to the overview. */\nconst EXIT_ZOOM = 0.72;\n/** Focus mode never zooms out further than this; it leaves at EXIT_ZOOM first. */\nconst FOCUS_MINIMUM_ZOOM = 0.6;\nconst DEFAULT_MINIMUM_ZOOM = 0.4;\nconst DEFAULT_MAXIMUM_ZOOM = 6;\n/** Zoom per press of a zoom button or the + and − keys. */\nconst STEP_ZOOM = 1.6;\n/** Wheel zoom eases toward where the wheel sent it with this time constant (ms). */\nconst WHEEL_SMOOTHING = 70;\n/** Haptic ticks only below this spin speed (degrees per second); faster ones would just buzz. */\nconst HAPTIC_SPEED_LIMIT = 720;\nconst ENTRY_DURATION = 650;\nconst MORPH_DURATION = 380;\n/** How long the planets take to make room as the place held for a node being dragged moves. */\nconst DRAG_MORPH_DURATION = 260;\n/** A node being dragged can be dropped into another this far (px) past its edge, so small moons can be hit. */\nconst DROP_REACH = 12;\n/**\n * A planet of the focused orbit takes a node dropped into it only nearer its\n * middle than this share of its radius (and at least `PLANET_CORE_PX`):\n * over its rim, the press is on the orbit, placing the node beside it.\n */\nconst PLANET_CORE = 0.6;\nconst PLANET_CORE_PX = 16;\n/** The target so far holds on this much further than it caught, so it doesn't flicker at its edge. */\nconst KEEP_TARGET = 1.3;\n/** A node dragged at least this close (px) to the orbit's ring goes to a place in it. */\nconst ORBIT_BAND = 32;\n/** Over a node it would go into, a dragged node shrinks to this size, as if about to go inside, and leaves the target's name in view. */\nconst INTO_SCALE = 0.55;\n/** Each frame, a dragged node's size goes this share of the way to where it's heading. */\nconst CARRIED_EASING = 0.3;\n/** With reduced motion, views cross-fade in this long instead of flying. */\nconst FADE_DURATION = 220;\n/** Clicks this soon after a flight starts are the second half of a double click. */\nconst CLICK_GUARD = 350;\n/**\n * One long press can reach the map twice, as Orbit's own and as the\n * browser's context menu: a second report for the same node this soon (ms)\n * is the same press.\n */\nconst CONTEXT_REPEAT = 700;\n/** Maps this wide (px) or narrower trade their breadcrumbs for a back chip (the `orbit--narrow` class). */\nconst NARROW_MAP = 560;\n/** The drift paints a turn once it moves the outermost body this far (px); a slow drift moves less than that most frames. */\nconst DRIFT_STEP = 0.5;\n/** The focused node's buttons keep this far from its planets and its name (px). */\nconst ACTION_CLEARANCE = 6;\n/** Buttons on the sun's lower rim sit this far in from its edge (px). */\nconst ACTION_RIM_INSET = 10;\n/** Buttons under the orbit sit this far below its edge, and keep this far from the map's edges and its zoom buttons (px). */\nconst ACTION_ORBIT_GAP = 12;\nconst ACTION_EDGE_MARGIN = 12;\n\n/** Where the focused node's buttons go: the middle of their top edge (px), and the width they wrap at (0 keeps them on one line). */\ninterface ActionsPlace {\n x: number;\n y: number;\n wrap: number;\n}\n\n/** What the field for typing on the map is for: a node's text, or a new idea at `index` among `parentId`'s children. */\ninterface EditSession {\n nodeId: string | null;\n parentId: string;\n index: number;\n}\n\n/**\n * A node held up by a press, then dragged somewhere else (see `editable`).\n * It stays where it was, only lifted, until the press moves.\n */\ninterface NodeDrag {\n id: string;\n node: OrbitNode;\n parent: OrbitNode;\n\n /** Its place among its parent's children when it was lifted. */\n index: number;\n\n /** What it can't be dropped into: itself, everything under it, and its parent. */\n unreachable: Set<string>;\n\n /** Following the press, rather than only lifted. */\n moving: boolean;\n\n /** The press, in px from the map's top left. */\n point: Point;\n\n /** Where the press took hold of it, from its center, in world units. */\n grab: Point;\n\n /** It, and the moons that go with it, as drawn when it was lifted, from its center. */\n bodies: DisplayNode[];\n\n /** In focus mode, the orbit's ring's radius with it: where places are once the orbit is empty without it. */\n ringRadius: number | null;\n\n /**\n * In focus mode, the radii of the orbit's rings when it started moving, and\n * the size they were laid out for: the rings keep them until the drop (see\n * `SceneOptions.keptRings`), unless the map changes size.\n */\n rings: { focusId: string; radii: number[]; size: Viewport } | null;\n\n /**\n * The place held for it in the focused orbit, counted among the sun's\n * children without it: at first where it came from, for one of them, then\n * wherever it was last carried along the ring. Let go over nothing, it\n * lands there.\n */\n slot: number | null;\n\n /** Where it would go if let go now. */\n place: DropPlace | null;\n\n /** Lifted by a long press no one took: let go without moving, it's typed into instead. */\n editOnRelease: boolean;\n\n /** Its size, eased: smaller while it's over a node it would go into. */\n scale: number;\n}\n\n/** Orbit's own buttons; any other action is one of yours. */\nconst CONTENT_ACTIONS = new Set<string>(['details', 'image', 'video', 'embed', 'note', 'link']);\n\ninterface CameraFlight {\n path: CameraPath;\n target: Camera;\n anchor: Point;\n startedAt: number;\n duration: number;\n}\n\nexport class OrbitSVGRenderer {\n private static registry = new WeakMap<HTMLElement, OrbitSVGRenderer>();\n private static instanceCounter = 0;\n\n /** Destroys the renderer drawing into `target`, if there is one. Returns whether there was. */\n static unmount(target: HTMLElement): boolean {\n const existing = OrbitSVGRenderer.registry.get(target);\n\n if (!existing) {\n return false;\n }\n\n existing.destroy();\n return true;\n }\n\n private readonly container: HTMLElement;\n private readonly root: HTMLDivElement;\n private readonly svg: SVGSVGElement;\n private readonly world: SVGGElement;\n private readonly definitions: SVGDefsElement;\n\n /** The camera as last written to the world: a spin repaints every frame without moving it. */\n private worldTransform = '';\n\n\n /** The theme the shading was last placed for (see `placeShading`). */\n private shadingTheme = '';\n\n\n\n\n private readonly layers: Record<'rings' | 'links' | 'moons' | 'nodes' | 'suns' | 'carried', SVGGElement>;\n private readonly labelLayer: HTMLDivElement;\n\n /** The fonts the labels are drawn with, which names are measured and fitted in. */\n private readonly labelFonts: LabelFonts;\n\n private readonly labelPainter: LabelPainter;\n\n /** Stops listening for fonts that finish loading. */\n private readonly stopWatchingFonts: () => void;\n\n /** What node types draw inside their nodes, between the nodes and the labels. */\n private readonly contentLayer: HTMLDivElement;\n\n private readonly contentPainter: ContentPainter;\n\n\n /** This map's node types, actions and status words, then the registered ones. */\n private extensions: MapExtensions;\n\n /** The words the map speaks, in its language, and the language and words they were made for. */\n private words: OrbitWords;\n\n private requestedLanguage: string | null;\n private requestedStrings: RendererOptions['strings'];\n private readonly overlayLayer: HTMLDivElement;\n private readonly emptyState: HTMLDivElement;\n private readonly actionBar: ActionBar;\n private readonly tooltip: Tooltip;\n private readonly controls: Controls;\n private readonly outline: AccessibleOutline;\n private readonly sheet: DetailSheet;\n private readonly viewer: MediaViewer;\n private readonly input: InputController;\n private readonly clock: AnimationClock;\n private readonly spinPhysics = new SpinPhysics();\n private readonly spinTracker = new AngularVelocityTracker();\n private readonly panTracker = new PointVelocityTracker();\n private readonly glide = new Glide();\n // SVG ids resolve document-wide, so they are unique per renderer.\n private readonly ids: ViewIds;\n private resizeObserver: ResizeObserver | null = null;\n private visibilityObserver: IntersectionObserver | null = null;\n\n /** Every node's color, from `getNodeColor`'s first call until the map or its options change. */\n private nodeColors: Map<string, string> | null = null;\n\n private taskTokens: Record<string, string> | null = null;\n\n /** Whether any of the map is on screen; off screen, the drift rests. */\n private onScreen = true;\n\n /** The reduced-motion query, asked once: the drift checks it every frame. */\n private reducedMotionQuery: MediaQueryList | null | undefined;\n\n private options: ResolvedRendererOptions;\n\n /** Options from the caller (constructor and setOptions); they win over the document's. */\n private userOptions: RendererOptions;\n\n /** Options from the rendered document's frontmatter or YAML keys. */\n private documentOptions: RendererOptions = {};\n\n /** Those options as the document wrote them, for `getDocument()` and `toMarkdown()`. */\n private sourceOptions: OrbitDocumentOptions = {};\n\n /** The document's keys Orbit doesn't read, written back on save. */\n private sourceExtra: Record<string, unknown> | undefined;\n\n private themeProperties: string[] = [];\n\n private tree: OrbitNode | null = null;\n private focusPath: string[] = [];\n private viewMode: ViewMode;\n private viewport: Viewport = { width: 0, height: 0 };\n\n /** The size the views were last laid out for: resizes close to it keep the layout. */\n private layoutSize: Viewport = { width: 0, height: 0 };\n\n /** The map was resized while flying: lay the view out again once it lands. */\n private relayoutOnArrival = false;\n\n /** The page's controls moved while flying (see `insets`): fit the view again once it lands. */\n private refitOnArrival = false;\n\n private scene: Scene | null = null;\n private camera: Camera = { x: 0, y: 0, scale: 1 };\n private transition: Transition | null = null;\n\n /** Where a flight between two branches goes after passing through their common ancestor. */\n private nextScene: Scene | null = null;\n\n /** The camera a flight ends on, when it isn't the scene's fitted view. */\n private landingCamera: Camera | null = null;\n\n private cameraFlight: CameraFlight | null = null;\n private wheelZoom: { remaining: number; anchor: Point } | null = null;\n private display: Display | null = null;\n private restingDisplay: { scene: Scene; rotation: number; display: Display } | null = null;\n\n\n\n\n\n\n private readonly ringsAndLinks: RingsAndLinks;\n private readonly nodePainter: NodePainter;\n\n\n\n\n\n /** The node that holds the map's single tab stop. */\n private activeId: string | null = null;\n\n private tabStopsChanged = true;\n private hoveredId: string | null = null;\n private keyboardFocusId: string | null = null;\n private topPlanetId: string | null = null;\n private userSpun = false;\n\n /** Put keyboard focus back on the map when a flight lands (its node may have left). */\n private returnFocusToMap = false;\n\n private dragging = false;\n\n /** The last node a long press, right click or context menu key reported, and whether someone took it. */\n private lastContext: { id: string; time: number; taken: boolean } | null = null;\n\n /** Nodes whose ids an edit changed, old to new, so the next redraw moves them rather than replacing them. */\n private renamedIds = new Map<string, string>();\n\n /** Nodes an edit changed in place (the node itself, or a parent's children): the next paint draws them again. */\n private readonly changedIds = new Set<string>();\n\n /** The + in the orbit, and the field for typing on the map. */\n private readonly addSlotView = new AddSlotView();\n\n /** The place held in the orbit for a planet being dragged: like the +, but nothing to press. */\n private readonly heldPlaceView = new AddSlotView(true);\n\n private readonly editor: InlineEditor;\n private editing: EditSession | null = null;\n private arrival: Arrival | null = null;\n\n /** A node held up to be dragged somewhere else. */\n private nodeDrag: NodeDrag | null = null;\n\n /** The frame a dragged node was let go in: the flight that follows starts from it. */\n private dropFrom: Display | null = null;\n\n /** A long press no one took a menu for, on a node it lifts: let go without moving, the node is typed into. */\n private editOnLift: string | null = null;\n\n\n private ambientRunning = false;\n\n /** Drift not painted yet, in degrees: less than a `DRIFT_STEP`. */\n private pendingDrift = 0;\n\n /** How far the current view's spinning bodies reach from the sun (world units). */\n private spinReach: { scene: Scene; reach: number } | null = null;\n\n private pageScrollCheck: { time: number; scrolls: boolean } | null = null;\n private readonly listeners = new Map<OrbitEventName, Set<(detail: never) => void>>();\n private destroyed = false;\n private warnedFlat = false;\n private warnedTheme: string | null = null;\n\n constructor(container: HTMLElement, options: RendererOptions = {}) {\n if (!container || typeof (container as Partial<HTMLElement>).appendChild !== 'function') {\n throw new TypeError(\n `Orbit needs an element to draw the map in, but got ${container === null ? 'null' : typeof container}. `\n + 'Check that the selector matches an element and that the code runs after the element exists.',\n );\n }\n\n OrbitSVGRenderer.unmount(container);\n this.container = container;\n this.userOptions = { ...options };\n this.options = this.resolveOptions();\n this.extensions = this.createExtensions();\n this.requestedLanguage = this.options.language ?? languageOf(container);\n this.requestedStrings = this.options.strings;\n this.words = new OrbitWords(this.requestedLanguage, this.requestedStrings);\n this.viewMode = this.options.viewMode;\n const prefix = `orbit-${(++OrbitSVGRenderer.instanceCounter).toString(36)}`;\n this.ids = { clip: `${prefix}-clip`, shade: `${prefix}-shade`, speckShade: `${prefix}-speck-shade`, shadow: `${prefix}-shadow`, sunShadow: `${prefix}-sun-shadow` };\n\n this.root = document.createElement('div');\n this.root.className = 'orbit';\n this.svg = svgElement('svg', { class: 'orbit__canvas' });\n this.svg.setAttribute('aria-roledescription', this.words.text('mindMapRole'));\n this.definitions = createDefinitions(this.ids);\n this.svg.appendChild(this.definitions);\n this.world = svgElement('g', { class: 'orbit__world' });\n this.layers = {\n rings: svgElement('g', { class: 'orbit__rings' }),\n links: svgElement('g', { class: 'orbit__links' }),\n moons: svgElement('g', { class: 'orbit__moons' }),\n nodes: svgElement('g', { class: 'orbit__nodes' }),\n suns: svgElement('g', { class: 'orbit__suns' }),\n // A node being dragged, and its moons: above everything it passes over, the sun included.\n carried: svgElement('g', { class: 'orbit__carried' }),\n };\n this.world.append(this.layers.rings, this.layers.links, this.layers.moons, this.layers.nodes, this.layers.suns, this.layers.carried);\n this.ringsAndLinks = new RingsAndLinks(this.layers);\n this.nodePainter = new NodePainter(this.root, this.definitions, this.ids, this.layers, {\n extensions: () => this.extensions,\n words: () => this.words,\n baseUrl: () => this.options.baseUrl,\n scene: () => this.scene,\n inFlight: () => this.transition !== null,\n spinResting: () => this.spinPhysics.mode === 'idle',\n driftRunning: () => this.ambientRunning,\n editedId: () => this.editedId(),\n drag: () => {\n const drag = this.nodeDrag;\n return {\n liftedId: drag?.id ?? null,\n carried: drag?.moving ? new Set(drag.bodies.map((body) => body.id)) : null,\n targetId: drag?.moving && drag.place?.into ? drag.place.parentId : null,\n };\n },\n changedIds: () => this.changedIds,\n requestPaint: () => this.clock.requestPaint(),\n tabStopsChanged: () => {\n this.tabStopsChanged = true;\n },\n viewRemoved: (id) => {\n this.labelPainter.forgetNode(id);\n this.tabStopsChanged = true;\n },\n });\n this.layers.nodes.appendChild(this.addSlotView.element);\n this.layers.nodes.appendChild(this.heldPlaceView.element);\n this.svg.appendChild(this.world);\n\n this.contentLayer = document.createElement('div');\n this.contentLayer.className = 'orbit__contents';\n this.contentLayer.setAttribute('aria-hidden', 'true');\n this.contentPainter = new ContentPainter(this.contentLayer, {\n extensions: () => this.extensions,\n viewport: () => this.viewport,\n changedIds: () => this.changedIds,\n });\n this.labelLayer = document.createElement('div');\n this.labelLayer.className = 'orbit__labels';\n this.labelLayer.setAttribute('aria-hidden', 'true');\n this.labelFonts = new LabelFonts(this.labelLayer, () => this.extensions);\n this.labelPainter = new LabelPainter(this.labelLayer, this.labelFonts, {\n extensions: () => this.extensions,\n viewport: () => this.viewport,\n restingScene: () => (this.transition ? null : this.scene),\n inFlight: () => this.transition !== null,\n cameraMoving: () => this.cameraFlight !== null || this.wheelZoom !== null || this.glide.isMoving || this.dragging,\n changedIds: () => this.changedIds,\n editedId: () => this.editedId(),\n animationsEnabled: () => this.animationsEnabled(),\n requestPaint: () => this.clock.requestPaint(),\n nodeView: (id) => this.nodePainter.view(id),\n themeTokens: () => this.exportTokens(),\n });\n this.overlayLayer = document.createElement('div');\n this.overlayLayer.className = 'orbit__overlay';\n this.actionBar = new ActionBar({\n onAction: (node, action, event) => this.runAction(node, action, event),\n describeLink: (node) => this.describeLink(node),\n actions: (node) => this.extensions.actions(node),\n hasDetails: (node) => Boolean(this.extensions.nodeType(node)?.details),\n returnFocus: () => this.focusNodeElement(this.activeId ?? this.focusId),\n words: () => this.words,\n });\n this.overlayLayer.appendChild(this.actionBar.element);\n this.editor = new InlineEditor({\n onSave: (text, how) => this.saveEdit(text, how),\n onCancel: () => this.finishEditing(true),\n onTab: (text, back) => this.tabFromEditor(text, back),\n });\n this.overlayLayer.appendChild(this.editor.element);\n this.emptyState = createEmptyState(this.words);\n this.tooltip = new Tooltip();\n this.controls = new Controls({\n onNavigate: (nodeId) => {\n this.navigate('focus', nodeId);\n },\n onViewMode: (mode) => this.setViewMode(mode),\n onZoom: (direction) => this.zoomBy(direction === 1 ? STEP_ZOOM : 1 / STEP_ZOOM),\n onFit: () => this.fit(),\n onToggleOutline: () => this.toggleOutline(),\n }, this.words);\n this.outline = new AccessibleOutline((nodeId) => this.selectFromOutline(nodeId), this.words);\n this.root.append(\n this.svg,\n this.contentLayer,\n this.labelLayer,\n this.overlayLayer,\n this.emptyState,\n this.tooltip.element,\n this.controls.element,\n this.outline.element,\n this.outline.live,\n );\n this.sheet = new DetailSheet(this.root);\n this.viewer = new MediaViewer(this.root, {\n items: () => (this.tree ? galleryItems(this.tree, this.options.maxDepth) : []),\n node: (id) => (this.tree ? findNodeById(this.tree, id) : null),\n baseUrl: () => this.options.baseUrl,\n interactive: () => this.options.interactive !== false,\n icon: (node) => this.extensions.icon(node),\n onShow: (item, index, total) => this.mediaShown('media-open', item, index, total),\n onClose: (item, index, total) => this.mediaShown('media-close', item, index, total),\n onState: (node, state) => this.mediaPlayed(node, state),\n words: () => this.words,\n });\n container.appendChild(this.root);\n ensureStyles(this.root);\n OrbitSVGRenderer.registry.set(container, this);\n\n this.clock = new AnimationClock(() => this.paint());\n\n // A font that finishes loading changes how wide names are: fit them again, where they are.\n this.stopWatchingFonts = onMeasurementsReset(() => {\n this.labelFonts.refresh();\n this.labelPainter.refit();\n });\n\n this.input = new InputController(this.root, {\n isInteractive: () => this.options.interactive !== false,\n longPressDelay: () => {\n const delay = this.options.longPressDelay;\n return typeof delay === 'number' && Number.isFinite(delay) && delay > 0 ? delay : 500;\n },\n dragGesture: (point) => this.dragGestureAt(point),\n spinCenter: () => this.sunOnScreen(),\n isCoasting: () => this.spinPhysics.isMoving || this.glide.isMoving,\n onCatch: () => {\n this.spinPhysics.stop();\n this.glide.stop();\n },\n onSpinStart: (time, angle) => {\n this.spinTracker.reset(time, angle);\n this.spinPhysics.grab();\n this.userSpun = true;\n },\n onSpinMove: (time, angle) => {\n this.spinPhysics.drag(this.spinTracker.add(time, angle));\n this.tickHaptics();\n this.clock.requestPaint();\n },\n onSpinEnd: (time, cancelled) => this.releaseSpin(cancelled ? 0 : this.spinTracker.velocityAt(time)),\n onPanStart: (time) => {\n this.glide.stop();\n this.cameraFlight = null;\n this.panTracker.reset(time);\n },\n onPan: (deltaX, deltaY, time) => {\n this.panTracker.add(time, deltaX, deltaY);\n this.panCamera(deltaX, deltaY);\n },\n onPanEnd: (time, cancelled) => {\n if (!cancelled && !this.prefersReducedMotion()) {\n this.glide.start(this.panTracker.velocityAt(time));\n\n if (this.glide.isMoving) {\n this.clock.add(this.glideTask);\n }\n }\n },\n onPinch: (factor, center, deltaX, deltaY) => {\n // A pinch takes the camera over from any flight in progress.\n this.cameraFlight = null;\n this.panCamera(deltaX, deltaY);\n this.zoomAt(factor, center);\n },\n onPinchEnd: () => this.settleZoom(),\n onWheel: (event, point) => this.handleWheel(event, point),\n onDoubleTap: (point, target) => this.handleDoubleTap(point, target),\n onLongPress: (point, target) => {\n const id = nodeIdFrom(target);\n return id !== null && this.openNodeContext(id, point, true);\n },\n onHold: (point, target) => this.liftNode(nodeIdFrom(target), point),\n onNodeDrag: (point, phase) => this.dragNode(point, phase),\n onDraggingChange: (dragging) => {\n this.dragging = dragging;\n this.root.classList.toggle('orbit--dragging', dragging);\n\n if (dragging) {\n this.hoveredId = null;\n this.updateTooltip();\n } else {\n // Labels that rode along with the drag are placed again where it ended.\n this.clock.requestPaint();\n }\n\n this.syncAmbientMotion();\n },\n });\n\n this.svg.addEventListener('click', this.handleClick);\n this.svg.addEventListener('contextmenu', this.handleContextMenu);\n this.svg.addEventListener('keydown', this.handleKeyDown);\n this.svg.addEventListener('pointerover', this.handlePointerOver);\n this.svg.addEventListener('pointerout', this.handlePointerOut);\n // On the root, not the SVG: Chromium makes an SVG element with focus\n // listeners a tab stop of its own.\n this.root.addEventListener('focusin', this.handleFocusIn);\n this.root.addEventListener('focusout', this.handleFocusOut);\n\n this.applyOptionEffects(null);\n this.setViewport(this.readContainerSize());\n this.observeResize();\n this.observeVisibility();\n }\n\n /**\n * Draws a map: markdown or YAML source (parsed forgivingly), a parsed\n * document, or a node tree. A document's frontmatter options apply, though\n * options given to the renderer win. Drawing a new version of the same map\n * keeps the reader's place: the focused node, or its closest ancestor that\n * still exists.\n */\n render(input: string | OrbitNode | OrbitDocument): void {\n if (typeof input === 'string') {\n input = parseOrbit(input, { untitled: this.words.text('untitledMap') });\n }\n\n const tree = isOrbitDocument(input) ? input.root : input;\n // Nodes written for older versions of their types are brought up to date; the next save writes them.\n upgradeTypes(tree, this.extensions);\n\n if (this.isSameMap(tree, isOrbitDocument(input) ? input.options : null)) {\n // The map as it already is, say from an editor saving an edit made on\n // the map: keep the view, and the edit's animation, going.\n if (isOrbitDocument(input)) {\n // Keys Orbit doesn't read don't change the drawing, but they're the map's, to save as given.\n this.sourceExtra = input.extra;\n }\n\n this.adoptTree(tree);\n return;\n }\n\n if (isOrbitDocument(input)) {\n this.sourceOptions = { ...input.options };\n this.sourceExtra = input.extra;\n this.documentOptions = documentToRendererOptions(input.options);\n this.options = this.resolveOptions();\n\n // The document picks the initial view; later renders keep whatever\n // view the reader switched to.\n if (this.tree === null) {\n this.viewMode = this.options.viewMode;\n }\n\n this.applyOptionEffects(null);\n } else {\n // A bare tree has no frontmatter: nothing of a document drawn before applies to it.\n this.sourceOptions = {};\n this.sourceExtra = undefined;\n this.documentOptions = {};\n this.options = this.resolveOptions();\n this.applyOptionEffects(null);\n }\n\n this.showTree(tree);\n }\n\n setOptions(options: RendererOptions): void {\n this.nodeColors = null;\n this.taskTokens = null;\n this.userOptions = { ...this.userOptions, ...options };\n const previous = this.options;\n this.options = this.resolveOptions();\n this.applyOptionEffects(previous);\n\n if (options.viewMode !== undefined && options.viewMode !== this.viewMode) {\n if (this.tree) {\n this.navigate(options.viewMode, this.focusId, false);\n } else {\n this.viewMode = options.viewMode;\n }\n }\n }\n\n /**\n * Listens for a map event; returns a function that stops listening. The\n * same events are dispatched on the container as `orbit-<name>` DOM events.\n */\n on<Name extends OrbitEventName>(name: Name, listener: (detail: OrbitEventMap[Name]) => void): () => void {\n let listeners = this.listeners.get(name);\n\n if (!listeners) {\n listeners = new Set();\n this.listeners.set(name, listeners);\n }\n\n const stored = listener as (detail: never) => void;\n listeners.add(stored);\n\n return () => {\n this.listeners.get(name)?.delete(stored);\n };\n }\n\n getSVGElement(): SVGSVGElement {\n return this.svg;\n }\n\n /**\n * The current view as a standalone SVG document: colors resolved, labels\n * as SVG text, nothing that depends on the page's stylesheet.\n */\n toSVGString(): string {\n const viewport = this.viewport.width > 0 && this.viewport.height > 0 ? this.viewport : { width: 800, height: 600 };\n // Mid-flight, export where the flight is going.\n let destination = this.transition ? this.nextScene ?? this.transition.target : this.scene;\n\n // The + is for editing, not part of the map: export the map as it reads without it.\n if (destination?.addSlot) {\n destination = this.buildScene(false);\n }\n\n const resting = destination\n ? sceneDisplay(destination, this.transition ? 0 : this.rotation, this.transition ? destination.frame : this.camera)\n : null;\n return exportDisplay(resting, {\n viewport,\n extensions: this.extensions,\n tokens: this.exportTokens(),\n showRings: this.options.showRings !== false,\n title: this.options.ariaLabel || this.tree?.text || this.words.text('mindMap'),\n words: this.words,\n fills: (node) => this.nodePainter.view(node.id)?.resolvedFill() ?? '',\n // The file will be opened away from the page: resolve relative URLs now.\n baseUrl: this.options.baseUrl ?? this.root.ownerDocument.baseURI,\n // Names break where they do on the map.\n measures: this.labelFonts,\n });\n }\n\n getViewMode(): ViewMode {\n return this.viewMode;\n }\n\n /** Switches between focus mode and the overview (fires onViewModeChange). */\n setViewMode(mode: ViewMode): void {\n if (mode === this.viewMode) {\n return;\n }\n\n if (!this.tree) {\n this.viewMode = mode;\n return;\n }\n\n this.navigate(mode, this.focusId);\n }\n\n /** Ids from the root to the focused node. */\n getFocusPath(): string[] {\n return [...this.focusPath];\n }\n\n /** The node focused in focus mode (the sun). */\n getFocusedNode(): OrbitNode | null {\n if (!this.tree) {\n return null;\n }\n\n return findNodeById(this.tree, this.focusId);\n }\n\n /**\n * Focuses a node by id and flies to it (fires onFocusChange). In the\n * overview, the camera moves to the node instead. Returns false when the\n * id isn't in the map.\n */\n focusNode(id: string): boolean {\n if (!this.tree) {\n return false;\n }\n\n const path = getNodePath(this.tree, id);\n\n if (path.length === 0) {\n return false;\n }\n\n if (this.viewMode === 'focus') {\n return this.navigate('focus', id);\n }\n\n const changed = id !== this.focusId;\n this.focusPath = path.map((node) => node.id);\n this.outline.setCurrent(this.focusId);\n const entry = this.scene?.nodes.get(id);\n\n if (entry && this.scene) {\n const [, maximum] = this.zoomRange();\n const scale = Math.min(this.scene.frame.scale * maximum, Math.max(this.camera.scale, 34 / entry.radius));\n this.flyCamera(this.clampCamera({ x: entry.x, y: entry.y, scale }), this.viewportCenter());\n }\n\n if (changed) {\n this.emitFocusChange(path);\n }\n\n return true;\n }\n\n /**\n * Flies to a node by id, switching to focus mode if needed (fires\n * onFocusChange and onViewModeChange). Returns false when there's no such node.\n */\n flyTo(id: string): boolean {\n return this.navigate('focus', id);\n }\n\n /** Flies out to the overview of the whole map (fires onViewModeChange). */\n overview(): void {\n this.setViewMode('all');\n }\n\n /** Zooms by `factor` around the middle of the map (above 1 zooms in). */\n zoomBy(factor: number): void {\n this.zoomStep(factor, this.viewportCenter());\n }\n\n /** Returns the camera to the fitted view. */\n fit(): void {\n if (this.scene) {\n this.flyCamera(this.scene.frame, this.viewportCenter());\n }\n }\n\n /**\n * Flicks the orbit at `speed` degrees per second; negative speeds turn it\n * counterclockwise. Only in focus mode.\n */\n spin(speed: number): void {\n if (this.viewMode !== 'focus' || !this.scene || this.transition) {\n return;\n }\n\n this.userSpun = true;\n this.releaseSpin(speed / 1000);\n }\n\n /**\n * Shows a node's picture or video in the media viewer, over the whole\n * window, opening it if it's closed: to show a picture big, or play a\n * video, from your own controls. A node with both shows its picture\n * unless `kind` is `video`, and a video starts playing unless `autoplay`\n * is `false`, from the start or `startAt` seconds in. It opens whatever\n * `mediaViewer`, `showDetailSheet` and `interactive` say; on a map that\n * isn't interactive, the viewer takes no input of its own and has no\n * buttons. Fires `media-open`. Returns false when the map has no such\n * node, or the node no such picture or video.\n */\n openMedia(nodeId: string, options: OrbitMediaOptions = {}): boolean {\n const node = this.tree ? findNodeById(this.tree, nodeId) : null;\n\n if (!node) {\n return false;\n }\n\n const kind: MediaKind = options.kind === 'image' || options.kind === 'video' ? options.kind : showsMedia(node, 'image') ? 'image' : 'video';\n return this.viewer.open({ node, kind }, { autoplay: options.autoplay !== false, startAt: options.startAt });\n }\n\n /** Closes the media viewer, if it's open (fires `media-close`). */\n closeMedia(): void {\n this.viewer.close();\n }\n\n /**\n * Plays the video in the media viewer. Returns false when it shows no\n * video, or one on a site Orbit has no player for. Files, YouTube and\n * Vimeo play.\n */\n playMedia(): boolean {\n return this.viewer.play();\n }\n\n /** Pauses the video in the media viewer. Returns false when it shows no video it can pause. */\n pauseMedia(): boolean {\n return this.viewer.pause();\n }\n\n /** Moves the video in the media viewer to `seconds` from its start. Returns false when it shows no video it can move. */\n seekMedia(seconds: number): boolean {\n return this.viewer.seek(seconds);\n }\n\n /**\n * Turns on the sound of the video in the media viewer: one a browser\n * started muted, say. Browsers allow sound only once the reader has\n * interacted with the page, so call it from a press, such as a \"Tap for\n * sound\" button's. Returns false when it shows no video it can drive.\n */\n unmuteMedia(): boolean {\n return this.viewer.unmute();\n }\n\n /**\n * The color a node is drawn with: its own, its type's, or its branch's\n * from the palette and theme. For lists and legends next to the map. A hex\n * color, or the CSS color as written when Orbit can't read it; `null` when\n * the id isn't in the map.\n */\n getNodeColor(id: string): string | null {\n const tree = this.tree;\n\n if (!tree) {\n return null;\n }\n\n // Every node's color at once, kept until the map or its options change: a list next to a big map asks for each.\n this.nodeColors ??= assignNodeColors(tree, resolvePalette(this.options.palette), (node) => this.extensions.color(node));\n const color = this.nodeColors.get(id);\n\n if (!color) {\n return null;\n }\n\n // Only theme references need the page's styles, and reading them is slow.\n return resolveColor(color, /var\\(/i.test(color) ? this.tokensForThisTask() : {});\n }\n\n /**\n * The theme's tokens as the page resolves them, read once per task:\n * reading them asks the browser for every token, and a list next to a big\n * map asks for hundreds of colors at once.\n */\n private tokensForThisTask(): Record<string, string> {\n if (!this.taskTokens) {\n this.taskTokens = this.exportTokens();\n\n queueMicrotask(() => {\n this.taskTokens = null;\n });\n }\n\n return this.taskTokens;\n }\n\n /**\n * The map as a document: its tree, and the options its source set in\n * frontmatter. Edits change this tree in place.\n */\n getDocument(): OrbitDocument | null {\n if (!this.tree) {\n return null;\n }\n\n const document: OrbitDocument = { root: this.tree, options: { ...this.sourceOptions }, warnings: [] };\n\n if (this.sourceExtra) {\n document.extra = { ...this.sourceExtra };\n }\n\n return document;\n }\n\n /**\n * The map as orbit-md, frontmatter included: what to save after an edit.\n * A map read from markdown comes back as it was written, with only what\n * the edits changed written again, so a file written by hand or by\n * another app keeps its formatting and everything Orbit doesn't read.\n */\n toMarkdown(): string {\n const document = this.getDocument();\n return document ? serializeOrbitMarkdown(document) : '';\n }\n\n /**\n * Adds a node under `parentId`, at `index` among its children (default:\n * last), with any `children` it lists under it; it flies out of its parent\n * into place. Ids come from the text, as when the map is read from\n * markdown. Fires `edit` once. Returns the new node, or null when there's\n * no such parent.\n */\n addNode(parentId: string, input: OrbitNewNode, index?: number): OrbitNode | null {\n expectObject('addNode', input, `addNode('${parentId}', { text: 'New idea' })`);\n return this.insertNode(parentId, input, index);\n }\n\n /**\n * Changes a node's text or attributes: `{ text: 'Budget' }`, `{ status:\n * 'done' }`, or `{ color: undefined }` to remove one. New text gives the\n * node a new id when its id came from its text and no link points at it,\n * so the saved map needs no id attribute. Fires `edit`. Returns the\n * node, or null when there's no such node.\n */\n updateNode(id: string, changes: OrbitNodeInput): OrbitNode | null {\n expectObject('updateNode', changes, `updateNode('${id}', { text: 'New title' })`);\n const updated = this.tree ? updateInTree(this.tree, id, changes, this.branchColorRules()) : null;\n\n if (!updated) {\n return null;\n }\n\n const { node, previousId } = updated;\n\n if (node.id !== previousId) {\n this.renameView(previousId, node.id);\n }\n\n this.changedIds.add(node.id);\n this.afterEdit('update', node);\n return node;\n }\n\n /**\n * Removes a node and everything under it. When the node in focus goes,\n * the nearest node left takes the focus. The root stays. Fires `edit`.\n * Returns the removed node, or null.\n */\n removeNode(id: string): OrbitNode | null {\n const removed = this.tree ? removeFromTree(this.tree, id, this.branchColorRules()) : null;\n\n if (!removed) {\n return null;\n }\n\n const { node, parent } = removed;\n this.changedIds.add(parent.id);\n this.afterEdit('remove', node, this.words.text('removed', { name: node.text || this.words.text('anIdea') }));\n return node;\n }\n\n /**\n * Moves a node, with everything under it, under `parentId` at `index`\n * among its children (default: last). Fires `edit`. Returns the node,\n * or null when either node is missing, the node is the root, or\n * `parentId` is inside the node.\n */\n moveNode(id: string, parentId: string, index?: number): OrbitNode | null {\n const moved = this.tree ? moveInTree(this.tree, id, parentId, index, this.branchColorRules()) : null;\n\n if (!moved) {\n return null;\n }\n\n const { node, from, to } = moved;\n this.changedIds.add(from.id).add(to.id);\n const name = node.text || this.words.text('anIdea');\n this.afterEdit('move', node, to.text ? this.words.text('moved', { name, parent: to.text }) : this.words.text('movedToTop', { name }));\n return node;\n }\n\n /**\n * Opens a field over a node to type its text where it is: Enter saves,\n * Escape cancels, and leaving the field saves. A moon, or a node out of\n * view, flies into view first. Fires `editor-open`, then `editor-close`.\n * Returns false when there's no such node.\n */\n editNode(id: string): boolean {\n const tree = this.tree;\n const path = tree ? getNodePath(tree, id) : [];\n\n if (path.length === 0 || this.options.interactive === false) {\n return false;\n }\n\n this.stopEditing();\n const node = path[path.length - 1];\n const parent = path[path.length - 2] ?? null;\n const role = (this.transition?.target ?? this.scene)?.nodes.get(id)?.role;\n\n if (this.viewMode === 'focus' && (role === undefined || role === 'moon')) {\n this.navigate('focus', parent?.id ?? id);\n }\n\n this.editing = { nodeId: id, parentId: parent?.id ?? id, index: parent ? parent.children.indexOf(node) : 0 };\n this.editor.show(node.text, {\n label: this.words.text('textOf', { name: node.text || this.words.text('thisIdea') }),\n placeholder: node.text || this.words.text('untitled'),\n enterKey: 'done',\n });\n this.paint();\n this.emitEditor('editor-open', node, null);\n return true;\n }\n\n /**\n * Adds an idea by typing it on the map: a field opens in the orbit of\n * `parentId` (default: the node in focus), at `index` among its children\n * (default: after the last), flying there first. Enter adds the idea\n * where it was typed and opens the next one after it; Escape, or Enter\n * with nothing typed, stops. Fires `editor-open`, `edit` for each idea,\n * then `editor-close`. Returns false when there's no such node.\n */\n editNewNode(parentId?: string, index?: number): boolean {\n const tree = this.tree;\n const path = tree ? getNodePath(tree, parentId ?? this.focusId) : [];\n const parent = path[path.length - 1];\n\n if (!parent || this.options.interactive === false || (this.options.maxDepth !== undefined && parent.level >= this.options.maxDepth)) {\n return false;\n }\n\n this.stopEditing();\n const count = parent.children.length;\n const at = index === undefined || !Number.isFinite(index) ? count : Math.min(count, Math.max(0, Math.trunc(index)));\n this.editing = { nodeId: null, parentId: parent.id, index: at };\n this.editor.show('', newIdeaText(parent, this.words));\n\n if (this.viewMode !== 'focus' || this.focusId !== parent.id) {\n this.navigate('focus', parent.id);\n } else {\n this.refreshSlot();\n }\n\n this.paint();\n this.emitEditor('editor-open', null, parent);\n return true;\n }\n\n /** Closes the field for typing on the map, keeping what was typed unless `save` is false. */\n stopEditing(save = true): void {\n if (!this.editing) {\n return;\n }\n\n if (save) {\n this.saveEdit(this.editor.value, 'blur');\n } else {\n this.finishEditing(false);\n }\n }\n\n destroy(): void {\n if (this.destroyed) {\n return;\n }\n\n this.destroyed = true;\n this.editing = null;\n this.editor.hide();\n this.clock.stop();\n this.input.detach();\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.visibilityObserver?.disconnect();\n this.visibilityObserver = null;\n this.svg.removeEventListener('click', this.handleClick);\n this.svg.removeEventListener('contextmenu', this.handleContextMenu);\n this.svg.removeEventListener('keydown', this.handleKeyDown);\n this.svg.removeEventListener('pointerover', this.handlePointerOver);\n this.svg.removeEventListener('pointerout', this.handlePointerOut);\n this.root.removeEventListener('focusin', this.handleFocusIn);\n this.root.removeEventListener('focusout', this.handleFocusOut);\n\n this.contentPainter.clear();\n\n this.viewer.destroy();\n this.sheet.destroy();\n this.controls.destroy();\n this.stopWatchingFonts();\n this.labelFonts.destroy();\n this.listeners.clear();\n this.root.remove();\n\n if (OrbitSVGRenderer.registry.get(this.container) === this) {\n OrbitSVGRenderer.registry.delete(this.container);\n }\n }\n\n // The tree and edits\n\n /** Draws `tree`, keeping the reader's place in it. */\n private showTree(tree: OrbitNode): void {\n const firstRender = this.tree === null;\n // A new map, or new text for it, ends a drag that isn't this map's own drop.\n const drag = this.nodeDrag;\n\n if (drag) {\n this.nodeDrag = null;\n\n if (drag.moving) {\n this.emitDrag('end', drag.node, null, null);\n }\n }\n\n this.tree = tree;\n this.nodeColors = null;\n\n if (firstRender && this.options.focus) {\n this.focusPath = [this.options.focus];\n }\n\n const session = this.editing;\n\n if (session && !findNodeById(tree, session.nodeId ?? session.parentId)) {\n // What was being typed into is gone.\n this.finishEditing(false, false);\n }\n\n let path: OrbitNode[] = [];\n\n for (let index = this.focusPath.length - 1; index >= 0 && path.length === 0; index -= 1) {\n path = getNodePath(tree, this.focusPath[index]);\n }\n\n this.focusPath = path.length > 0 ? path.map((node) => node.id) : [tree.id];\n this.actionBar.reset();\n this.labelPainter.forgetLightText();\n this.updateEmbedding();\n this.updateControls();\n this.updateOutline();\n this.rebuild(firstRender || !this.scene ? 'enter' : 'morph');\n }\n\n /** Whether `tree`, with the document's `options`, is the map as drawn now, in another object. */\n private isSameMap(tree: OrbitNode, options: OrbitDocumentOptions | null): boolean {\n return this.tree !== null && this.scene !== null && tree !== this.tree\n && (options === null || sameValues(definedEntries(options), definedEntries(this.sourceOptions)))\n && sameTree(tree, this.tree);\n }\n\n /**\n * Takes a copy of the map as drawn without drawing it again, so a flight or\n * an edit's animation carries on. The copy proved equal to the drawn tree\n * (see `isSameMap`): the drawn nodes stay, so their views, labels and\n * outline entries carry on too; the copy lends only its places in the source.\n */\n private adoptTree(tree: OrbitNode): void {\n transplantSource(this.tree as OrbitNode, tree);\n this.nodeColors = null;\n const scene = this.buildScene();\n\n if (!scene) {\n return;\n }\n\n if (this.nextScene) {\n this.nextScene = scene;\n } else if (this.transition) {\n this.transition = { ...this.transition, target: scene };\n } else {\n this.scene = scene;\n }\n\n this.actionBar.reset();\n this.clock.requestPaint();\n }\n\n /** How edits keep top-level nodes' colors: the palette's colors after the root's, and each node's own color or its type's. */\n private branchColorRules(): BranchColorRules {\n return { count: branchPalette(resolvePalette(this.options.palette)).length, ownColor: (node) => this.extensions.color(node) };\n }\n\n /** Shows an edit, keeping the reader's place, and reports it. */\n private afterEdit(kind: OrbitEdit['kind'], node: OrbitNode, announcement?: string): void {\n const tree = this.tree as OrbitNode;\n const focus = this.focusPath.join('\\n');\n this.showTree(tree);\n\n if (this.focusPath.join('\\n') !== focus) {\n this.emitFocusChange(getNodePath(tree, this.focusId));\n }\n\n if (announcement) {\n this.outline.announce(announcement);\n }\n\n const edit: OrbitEdit = { kind, node, tree };\n this.options.onEdit?.(edit);\n this.emit('edit', edit);\n }\n\n /** Adds a node; `arrival`, where a new idea was typed, is where it first shows. */\n private insertNode(parentId: string, input: OrbitNewNode, index?: number, arrival?: Omit<Arrival, 'id'>): OrbitNode | null {\n const added = this.tree ? addToTree(this.tree, parentId, input, index, this.branchColorRules()) : null;\n\n if (!added) {\n return null;\n }\n\n const { node, parent } = added;\n this.changedIds.add(parent.id);\n this.arrival = arrival ? { id: node.id, ...arrival } : null;\n this.afterEdit('add', node, this.words.text('added', { name: node.text || this.words.text('anIdea') }));\n return node;\n }\n\n /** Whether Tab, Shift+Enter and Delete edit the map (see `editingKeys`). */\n private get editingKeys(): boolean {\n return this.options.editable === true && this.options.editingKeys === true && this.options.interactive !== false;\n }\n\n /** Shift+Enter: a new idea beside `id`, right after it. Beside the root, which has no orbit around it, is under it. */\n private addBeside(id: string): boolean {\n const path = this.tree ? getNodePath(this.tree, id) : [];\n const node = path[path.length - 1];\n const parent = path[path.length - 2];\n\n if (!node) {\n return false;\n }\n\n return parent ? this.editNewNode(parent.id, parent.children.indexOf(node) + 1) : this.editNewNode(node.id);\n }\n\n /** Delete: removes `id`, and keyboard focus moves on to the node after it, or before it, or up to its parent. */\n private removeWithKey(id: string): boolean {\n const path = this.tree ? getNodePath(this.tree, id) : [];\n const node = path[path.length - 1];\n const parent = path[path.length - 2];\n\n if (!node || !parent) {\n return false;\n }\n\n const position = parent.children.indexOf(node);\n const next = parent.children[position + 1] ?? parent.children[position - 1] ?? parent;\n\n if (!this.removeNode(id)) {\n return true;\n }\n\n const scene = this.transition?.target ?? this.scene;\n this.focusNodeElement(scene?.nodes.has(next.id) ? next.id : this.focusId);\n return true;\n }\n\n /**\n * Tab and Shift+Tab in the field (see `editingKeys`). Tab goes on a level\n * down: under the idea just typed, or with nothing typed, under the idea\n * before. Shift+Tab goes on a level up, beside the parent. What was typed\n * is kept first. Returns whether the key was used.\n */\n private tabFromEditor(text: string, back: boolean): boolean {\n const session = this.editing;\n const tree = this.tree;\n\n if (!session || !tree || !this.editingKeys) {\n return false;\n }\n\n const parentPath = getNodePath(tree, session.parentId);\n const parent = parentPath[parentPath.length - 1];\n\n if (!parent) {\n return false;\n }\n\n const grandparent = parentPath[parentPath.length - 2] ?? null;\n const value = text.replace(/\\s+/g, ' ').trim();\n // The node the text went into: the one being renamed, or the idea typed.\n let typed: OrbitNode | null = null;\n\n if (session.nodeId !== null) {\n const node = findNodeById(tree, session.nodeId);\n this.finishEditing(false, false);\n typed = node && value && value !== node.text ? this.updateNode(node.id, { text: value }) : node;\n } else if (value) {\n const slot = this.display?.addSlot;\n const typedAt = slot && slot.parentId === session.parentId ? { x: slot.x, y: slot.y, radius: slot.radius } : undefined;\n this.finishEditing(false, false);\n typed = this.insertNode(session.parentId, { text: value }, session.index, typedAt);\n }\n\n if (back) {\n if (grandparent) {\n return this.editNewNode(grandparent.id, grandparent.children.indexOf(parent) + 1);\n }\n\n // There's no level above the root's orbit: an idea typed there goes on beside, as with Enter.\n return typed === null || session.nodeId !== null || this.editNewNode(parent.id, session.index + 1);\n }\n\n const under = typed ?? parent.children[session.index - 1] ?? null;\n // With nothing typed and nothing before it, the field stays where it is.\n return under === null || this.editNewNode(under.id);\n }\n\n /** Keeps what was typed: new text for a node, or a new idea (and, after Enter, the field moves on to the next). */\n private saveEdit(text: string, how: 'enter' | 'blur'): void {\n const session = this.editing;\n const tree = this.tree;\n\n if (!session || !tree) {\n return;\n }\n\n const value = text.replace(/\\s+/g, ' ').trim();\n\n if (session.nodeId !== null) {\n const node = findNodeById(tree, session.nodeId);\n this.finishEditing(how === 'enter');\n\n if (node && value && value !== node.text) {\n this.updateNode(node.id, { text: value });\n }\n\n return;\n }\n\n const parent = findNodeById(tree, session.parentId);\n\n if (!value || !parent) {\n this.finishEditing(how === 'enter');\n return;\n }\n\n const slot = this.display?.addSlot;\n const typedAt = slot && slot.parentId === session.parentId ? { x: slot.x, y: slot.y, radius: slot.radius } : undefined;\n\n if (how === 'enter') {\n // On to the next idea, right after this one.\n this.editing = { ...session, index: session.index + 1 };\n this.editor.clear(newIdeaText(parent, this.words));\n } else {\n this.finishEditing(false, false);\n }\n\n this.insertNode(session.parentId, { text: value }, session.index, typedAt);\n }\n\n /**\n * Closes the field. `returnFocus` puts keyboard focus back on the node\n * (or the +) when it was in the field; `refresh` moves the + back to its\n * place, unless an edit is about to redraw the map anyway.\n */\n private finishEditing(returnFocus: boolean, refresh = true): void {\n const session = this.editing;\n\n if (!session) {\n return;\n }\n\n const hadFocus = this.editor.hasFocus;\n this.editing = null;\n this.editor.hide();\n const tree = this.tree;\n const node = tree && session.nodeId !== null ? findNodeById(tree, session.nodeId) : null;\n const parent = tree && session.nodeId === null ? findNodeById(tree, session.parentId) : null;\n\n if (refresh) {\n this.refreshSlot();\n }\n\n if (returnFocus && hadFocus) {\n if (node) {\n this.focusNodeElement(node.id);\n } else if (this.addSlotView.isShown) {\n this.addSlotView.element.focus({ preventScroll: true });\n }\n }\n\n this.paint();\n this.emitEditor('editor-close', node, parent);\n }\n\n /** Redraws the view when the + should show, move or go. */\n private refreshSlot(): void {\n const tree = this.tree;\n const scene = this.nextScene ?? this.transition?.target ?? this.scene;\n\n if (!tree || !scene || this.viewMode !== 'focus') {\n return;\n }\n\n const wanted = this.slotPlace();\n const focused = findNodeById(tree, this.focusId);\n const wantedIndex = wanted && focused ? wanted.index ?? focused.children.length : null;\n\n if ((scene.addSlot?.index ?? null) !== wantedIndex) {\n this.rebuild('morph');\n }\n }\n\n /** Where the + goes in the focused node's orbit: where a new idea is being typed, else after its children on editable maps. */\n private slotPlace(): { index?: number } | undefined {\n const session = this.editing;\n\n if (session && session.nodeId === null) {\n return session.parentId === this.focusId ? { index: session.index } : undefined;\n }\n\n return this.options.editable && this.options.interactive !== false ? {} : undefined;\n }\n\n private emitEditor(name: 'editor-open' | 'editor-close', node: OrbitNode | null, parent: OrbitNode | null): void {\n const event: OrbitEditorEvent = { node, parent };\n\n if (name === 'editor-open') {\n this.options.onEditorOpen?.(event);\n } else {\n this.options.onEditorClose?.(event);\n }\n\n this.emit(name, event);\n }\n\n /** Keeps the view's place on a node whose id an edit changed. */\n private renameView(from: string, to: string): void {\n this.focusPath = this.focusPath.map((id) => (id === from ? to : id));\n\n for (const key of ['activeId', 'hoveredId', 'keyboardFocusId', 'topPlanetId'] as const) {\n if (this[key] === from) {\n this[key] = to;\n }\n }\n\n this.renamedIds.set(from, to);\n }\n\n // Options\n\n /** Defaults, then the document's options, then the caller's. `undefined` means \"not set\". */\n private resolveOptions(): ResolvedRendererOptions {\n return mergeRendererOptions(mergeRendererOptions(DEFAULT_OPTIONS, this.documentOptions), this.userOptions);\n }\n\n private createExtensions(): MapExtensions {\n return new MapExtensions({ nodeTypes: this.options.nodeTypes, actions: this.options.actions, statuses: this.options.statuses, nodeTypeFor: this.options.nodeTypeFor });\n }\n\n /**\n * Speaks the language the options ask for, or else the one the map's\n * element is in now, and writes the map's words again if that changed.\n */\n private syncLanguage(): void {\n const requested = this.options.language ?? languageOf(this.container);\n\n if (requested === this.requestedLanguage && sameValues(this.options.strings, this.requestedStrings)) {\n return;\n }\n\n this.requestedLanguage = requested;\n this.requestedStrings = this.options.strings;\n this.words = new OrbitWords(requested, this.options.strings);\n this.svg.setAttribute('aria-roledescription', this.words.text('mindMapRole'));\n this.controls.relabel(this.words);\n this.outline.relabel(this.words);\n this.viewer.relabel();\n this.actionBar.reset();\n fillEmptyState(this.emptyState, this.words);\n\n for (const [, view] of this.nodePainter.entries()) {\n view.element.setAttribute('aria-label', describeNode(view.node, 0, view.node.children.length, this.extensions, this.words));\n }\n\n if (this.tree) {\n this.updateOutline();\n this.updateControls();\n }\n }\n\n /** Applies the current options. With `previous`, also updates the map for what changed. */\n private applyOptionEffects(previous: ResolvedRendererOptions | null): void {\n const next = this.options;\n const extended = previous !== null\n && (!sameValues(previous.nodeTypes, next.nodeTypes) || !sameValues(previous.actions, next.actions) || !sameValues(previous.statuses, next.statuses)\n || previous.nodeTypeFor !== next.nodeTypeFor);\n\n if (extended) {\n this.extensions = this.createExtensions();\n }\n\n this.applyTheme();\n this.syncLanguage();\n this.spinPhysics.settings = spinSettings(next.spin);\n this.svg.setAttribute('aria-label', next.ariaLabel || this.words.text('mindMap'));\n this.syncInteractivity();\n this.syncAmbientMotion();\n\n if (!previous || !this.tree) {\n return;\n }\n\n if (previous.baseUrl !== next.baseUrl || extended) {\n this.clearViews();\n }\n\n if (extended) {\n this.updateOutline();\n this.refreshScene();\n return;\n }\n\n if ((!next.editable || next.interactive === false) && this.editing) {\n this.stopEditing();\n }\n\n if (previous.maxDepth !== next.maxDepth || Boolean(previous.editable) !== Boolean(next.editable)) {\n this.updateOutline();\n this.rebuild('morph');\n return;\n }\n\n const recolor = !sameValues(previous.palette, next.palette) || !sameValues(previous.theme, next.theme);\n // The focused node's buttons, and the zoom buttons they keep clear of, take room from fitted views.\n const refit = !sameValues(resolveInsets(previous.insets), resolveInsets(next.insets))\n || (previous.showActionButtons !== false) !== (next.showActionButtons !== false)\n || (previous.interactive !== false) !== (next.interactive !== false)\n || (previous.showControls !== false) !== (next.showControls !== false);\n\n if (refit && this.transition) {\n // The flight lands where it was going; the view moves over once it's there.\n this.refitOnArrival = true;\n } else if (refit) {\n const fitted = this.isFitted();\n this.refreshScene();\n\n if (fitted) {\n this.fit();\n }\n\n return;\n }\n\n if (recolor) {\n this.refreshScene();\n return;\n }\n\n this.clock.requestPaint();\n }\n\n /** Whether the camera shows the view as it's fitted, not zoomed or panned away from it. */\n private isFitted(): boolean {\n const frame = this.scene?.frame;\n\n if (!frame) {\n return false;\n }\n\n const { camera } = this;\n return Math.abs(camera.scale / frame.scale - 1) < 0.01\n && Math.abs(camera.x - frame.x) * camera.scale < 2\n && Math.abs(camera.y - frame.y) * camera.scale < 2;\n }\n\n /** The theme object to apply, with a registered theme's name replaced by its tokens. */\n private themeOption(): OrbitRendererTheme | undefined {\n const theme = expandTheme(this.options.theme);\n return typeof theme === 'object' ? theme : undefined;\n }\n\n private themePreset(): OrbitThemePreset {\n return themeName(this.options.theme);\n }\n\n private applyTheme(): void {\n const theme = this.options.theme;\n const requested = typeof theme === 'string' ? theme : theme?.preset;\n\n if (requested !== undefined && !isThemeName(requested) && requested !== this.warnedTheme) {\n this.warnedTheme = requested;\n console.warn(`[orbit] Unknown theme \"${String(requested)}\", so the map uses paper. Themes: ${themeNames().join(', ')}.`);\n }\n\n this.root.dataset.orbitTheme = this.themePreset();\n const overrides = themeOverrides(this.themeOption());\n\n for (const property of this.themeProperties) {\n if (!(property in overrides)) {\n this.root.style.removeProperty(property);\n }\n }\n\n for (const [property, value] of Object.entries(overrides)) {\n this.root.style.setProperty(property, value);\n }\n\n this.themeProperties = Object.keys(overrides);\n this.labelPainter.forgetTextColors();\n const shading = JSON.stringify([this.themePreset(), this.themeOption()]);\n\n if (shading !== this.shadingTheme) {\n this.shadingTheme = shading;\n placeShading(this.definitions, this.ids, readShadeCircle(this.themeValue('node-shade-circle')));\n }\n\n this.labelFonts.refresh();\n }\n\n /** A token as the page resolves it (its CSS can set any), or as the theme sets it while the map isn't on a page. */\n private themeValue(token: OrbitThemeToken): string {\n if (typeof getComputedStyle === 'function' && this.root.isConnected) {\n const value = getComputedStyle(this.root).getPropertyValue(`--_orbit-${token}`).trim();\n\n if (value && !value.startsWith('var(')) {\n return value;\n }\n }\n\n return resolveThemeTokens(this.themePreset(), this.themeOption())[token];\n }\n\n /** Concrete theme values for exports: the preset, then the theme object, then the page's CSS. */\n private exportTokens(): Record<string, string> {\n const page: Partial<Record<OrbitThemeToken, string>> = {};\n\n if (typeof getComputedStyle === 'function' && this.root.isConnected) {\n const style = getComputedStyle(this.root);\n\n for (const token of THEME_TOKENS) {\n const value = style.getPropertyValue(`--_orbit-${token}`).trim();\n\n if (value && !value.startsWith('var(')) {\n page[token] = value;\n }\n }\n }\n\n return resolveThemeTokens(this.themePreset(), this.themeOption(), page);\n }\n\n private syncInteractivity(): void {\n const interactive = this.options.interactive !== false;\n this.root.classList.toggle('orbit--static', !interactive);\n this.svg.setAttribute('role', interactive ? 'group' : 'img');\n\n if (interactive) {\n this.input.attach(this.svg);\n } else {\n this.input.detach();\n this.sheet.close();\n this.tooltip.hide();\n }\n\n // The viewer stays open, but takes input only on an interactive map.\n this.viewer.refresh();\n this.controls.element.hidden = !interactive || this.options.showControls === false;\n this.tabStopsChanged = true;\n }\n\n // Scenes and navigation\n\n private get focusId(): string {\n return this.focusPath[this.focusPath.length - 1] ?? this.tree?.id ?? '';\n }\n\n private get rotation(): number {\n return this.spinPhysics.angle;\n }\n\n private sceneOptions(withSlot = true): SceneOptions {\n const tree = this.tree as OrbitNode;\n // A planet being dragged is laid out at the place held for it, and the others make room; anything\n // else carried to the orbit is given the + in the orbit as its place. Either way the orbit keeps\n // its count, so nothing moves until the place does.\n const drag = this.nodeDrag?.moving ? this.nodeDrag : null;\n const planet = drag !== null && this.carriesPlanet(drag);\n const held = drag !== null && !planet && drag.slot !== null ? { index: drag.slot } : null;\n // The orbit's rings stay as they were when the drag began: moons need more room next to some neighbors than others.\n const rings = drag?.rings && closeInSize(this.viewport, drag.rings.size) ? drag.rings : null;\n return {\n viewport: this.viewport,\n insets: resolveInsets(this.options.insets),\n colors: assignNodeColors(tree, resolvePalette(this.options.palette), (node) => this.extensions.color(node)),\n maxDepth: this.options.maxDepth,\n addSlot: withSlot ? (held ?? this.slotPlace()) : undefined,\n reorder: planet && drag.slot !== null ? { id: drag.id, index: drag.slot } : undefined,\n keptRings: rings ? { focusId: rings.focusId, radii: rings.radii } : undefined,\n };\n }\n\n /**\n * The scene for the current view, or null while there is nothing to draw\n * or no room to draw it. `withSlot: false` leaves out the + (for exports).\n */\n private buildScene(withSlot = true): Scene | null {\n const tree = this.tree;\n\n if (!tree || isEmptyTree(tree) || this.viewport.width <= 0 || this.viewport.height <= 0) {\n return null;\n }\n\n this.layoutSize = { ...this.viewport };\n return this.viewMode === 'all'\n ? buildOverviewScene(tree, this.sceneOptions(withSlot))\n : this.focusScene(tree, this.focusId, this.sceneOptions(withSlot));\n }\n\n /**\n * The focus view of `focusId`. Where the focused node's buttons have no\n * place around the sun, it's fitted to leave room for them under the orbit.\n */\n private focusScene(tree: OrbitNode, focusId: string, options: SceneOptions): Scene {\n const scene = buildFocusScene(tree, focusId, options);\n const room = this.roomForActions(scene);\n return room > 0 ? { ...scene, frame: fitScene(scene, this.viewport, options.insets, room) } : scene;\n }\n\n /**\n * The room (px) a focus view needs under its orbit for the focused node's\n * buttons: none where they have a place in the view as it's fitted.\n */\n private roomForActions(scene: Scene): number {\n const sun = scene.nodes.get(scene.focusId);\n const count = sun ? this.actionBar.count(sun.node) : 0;\n\n if (!sun || count === 0 || !this.showsActions() || this.actionsPlace(scene, sun, scene.frame) !== null) {\n return 0;\n }\n\n // In that room the buttons sit at the bottom of the map, beside the zoom buttons.\n return ACTION_ORBIT_GAP + this.rowsUnderOrbit(count, resolveInsets(this.options.insets)).rows.height + ACTION_EDGE_MARGIN;\n }\n\n private showsActions(): boolean {\n return this.options.showActionButtons !== false && this.options.interactive !== false;\n }\n\n /**\n * Where the focused node's buttons go, or null where every place would\n * cover something: under the sun where its planets leave room at every\n * turn of the orbit, else on its lower rim under its name, else under the\n * orbit (`focusScene` fits views to leave room there).\n */\n private actionsPlace(scene: Scene, sun: { id: string; node: OrbitNode; x: number; y: number; radius: number; hiddenChildren: number }, camera: Camera): ActionsPlace | null {\n // A node without buttons is still given a place: showing it there clears the last node's.\n const count = Math.max(1, this.actionBar.count(sun.node));\n const size = this.actionBar.size();\n const point = worldToScreen(camera, this.viewport, sun);\n const radius = sun.radius * camera.scale;\n const clear = innerOrbitEdge(scene) * camera.scale - ACTION_CLEARANCE;\n // The planets come round to every angle as the orbit turns: the row's farthest point from the sun stays inside them.\n const offset = (actionRows(count, size).width - size) / 2;\n const reach = (top: number): number => Math.hypot(offset, top + size / 2) + size / 2;\n const labelBelow = this.labelPainter.placementOf(sun.id) === 'outside';\n const under = radius + (labelBelow ? 36 : 12);\n\n if (reach(under) <= clear) {\n return { x: point.x, y: point.y + under, wrap: 0 };\n }\n\n if (!labelBelow) {\n const countWidth = showsCount('sun', radius, sun.hiddenChildren) ? measureCount(sun.hiddenChildren, this.labelFonts.count()) : 0;\n const name = insideLabelLayout('sun', radius, sun.node.text, Boolean(this.extensions.icon(sun.node)), this.labelFonts.inside('sun', sun.node), true, countWidth);\n const onRim = radius - size - ACTION_RIM_INSET;\n\n if (onRim >= (name ? insideLabelReach(name) : 0) + ACTION_CLEARANCE && reach(onRim) <= clear) {\n return { x: point.x, y: point.y + onRim, wrap: 0 };\n }\n }\n\n // Under the orbit, its edge at every turn.\n const insets = resolveInsets(this.options.insets);\n const top = point.y + Math.max(scene.extent.x, scene.extent.y) * camera.scale + ACTION_ORBIT_GAP;\n const { rows, left, right } = this.rowsUnderOrbit(count, insets, top);\n\n if (top + rows.height > this.viewport.height - insets.bottom - ACTION_EDGE_MARGIN) {\n return null;\n }\n\n // Under the sun, unless that takes them past the zoom buttons or the map's side.\n const x = Math.min(Math.max(point.x, left + rows.width / 2), right - rows.width / 2);\n return { x, y: top, wrap: rows.perLine < count ? rows.width : 0 };\n }\n\n /**\n * How `count` buttons lay out under the orbit with their top `top` px down\n * the map (by default, as low as they go): between the sides of the map\n * that `insets` leave, or short of the zoom buttons where they come down\n * beside them, on more lines if they must.\n */\n private rowsUnderOrbit(count: number, insets: Insets, top = this.viewport.height): { rows: ActionRows; left: number; right: number } {\n const size = this.actionBar.size();\n const left = insets.left + ACTION_EDGE_MARGIN;\n let right = this.viewport.width - insets.right - ACTION_EDGE_MARGIN;\n let rows = actionRows(count, size, right - left);\n const zoom = this.controls.zoomBox(this.viewport.width, this.viewport.height);\n\n if (zoom && top + rows.height + ACTION_EDGE_MARGIN > zoom.top) {\n right = Math.min(right, zoom.left - ACTION_EDGE_MARGIN);\n rows = actionRows(count, size, right - left);\n }\n\n return { rows, left, right };\n }\n\n /**\n * Moves to a view: `nodeId` in focus, or the overview. Fires\n * onFocusChange and onViewModeChange unless `notify` is false.\n */\n private navigate(mode: ViewMode, nodeId: string, notify = true): boolean {\n const tree = this.tree;\n\n if (!tree) {\n return false;\n }\n\n const path = getNodePath(tree, nodeId);\n\n if (path.length === 0) {\n return false;\n }\n\n const focusChanged = path[path.length - 1].id !== this.focusId;\n const modeChanged = mode !== this.viewMode;\n this.focusPath = path.map((node) => node.id);\n this.viewMode = mode;\n\n if (!focusChanged && !modeChanged) {\n this.fit();\n return true;\n }\n\n const active = this.root.ownerDocument.activeElement;\n this.returnFocusToMap ||= Boolean(active && this.svg.contains(active));\n this.hoveredId = null;\n this.updateTooltip();\n this.actionBar.hide();\n this.flyToCurrentView();\n this.updateControls();\n this.outline.setCurrent(this.focusId);\n this.announceView();\n\n if (notify && modeChanged) {\n this.options.onViewModeChange?.(mode);\n this.emit('view-mode-change', { mode });\n }\n\n if (notify && focusChanged && mode === 'focus') {\n this.emitFocusChange(path);\n }\n\n return true;\n }\n\n private flyToCurrentView(): void {\n const target = this.buildScene();\n this.stopMotion();\n\n if (!target) {\n this.transition = null;\n this.nextScene = null;\n this.scene = null;\n this.paint();\n return;\n }\n\n if (this.scene && this.prefersReducedMotion() && this.options.transitionDuration !== 0) {\n this.startFade(target);\n return;\n }\n\n if (!this.scene || !this.animationsEnabled()) {\n this.transition = null;\n this.nextScene = null;\n this.restOn(target);\n return;\n }\n\n const now = this.now();\n const from = this.currentDisplay(now);\n const placement = this.placeTarget(from, target);\n\n if (placement) {\n this.nextScene = null;\n this.startTransition(from, target, placement, now);\n return;\n }\n\n // Neither view contains the other: pass through their common ancestor.\n const via = this.commonAncestorScene(target);\n const viaPlacement = via ? this.placeTarget(from, via) : null;\n\n if (via && viaPlacement) {\n this.nextScene = target;\n this.startTransition(from, via, viaPlacement, now);\n return;\n }\n\n this.nextScene = null;\n this.startTransition(from, target, overlayPlacement(target, from.camera), now);\n }\n\n /**\n * Where to put `target` in today's world so the flight has a fixed point:\n * a node both views show stays put while the camera moves.\n */\n private placeTarget(from: Display, target: Scene): Similarity | null {\n const visible = (id: string | undefined): DisplayNode | null => {\n const node = id === undefined ? undefined : from.nodes.get(id);\n return node && node.opacity > 0.3 && node.radius > 0.5 ? node : null;\n };\n\n // The destination's focus is on screen: zoom into it.\n const focus = visible(target.focusId);\n\n if (focus) {\n return alignScene(target, target.focusId, focus);\n }\n\n // Today's focus is in the destination: zoom out around it.\n const currentFocusId = this.transition?.target.focusId ?? this.scene?.focusId;\n const current = visible(currentFocusId);\n\n if (current && currentFocusId !== undefined && target.nodes.has(currentFocusId)) {\n return alignScene(target, currentFocusId, current);\n }\n\n // Any node both views share, the biggest on screen.\n let shared: DisplayNode | null = null;\n\n for (const node of from.nodes.values()) {\n if (node.opacity > 0.3 && node.radius > 0.5 && target.nodes.has(node.id) && (!shared || node.radius > shared.radius)) {\n shared = node;\n }\n }\n\n if (shared) {\n return alignScene(target, shared.id, shared);\n }\n\n const tree = this.tree;\n\n if (!tree) {\n return null;\n }\n\n // An ancestor of today's focus is in the destination: shrink this view into it.\n if (current && currentFocusId !== undefined) {\n for (let node = findNodeById(tree, currentFocusId)?.parent; node; node = node.parent) {\n if (target.nodes.has(node.id)) {\n return alignScene(target, node.id, { x: current.x, y: current.y, radius: current.radius * 1.15 });\n }\n }\n }\n\n // An ancestor of the destination's focus is on screen: grow the destination out of it.\n for (let node = findNodeById(tree, target.focusId)?.parent; node; node = node.parent) {\n const shown = visible(node.id);\n\n if (shown) {\n return alignScene(target, target.focusId, { x: shown.x, y: shown.y, radius: shown.radius * 0.45 });\n }\n }\n\n return null;\n }\n\n private commonAncestorScene(target: Scene): Scene | null {\n const tree = this.tree;\n const currentFocusId = this.transition?.target.focusId ?? this.scene?.focusId;\n\n if (!tree || target.kind !== 'focus' || currentFocusId === undefined) {\n return null;\n }\n\n const fromPath = getNodePath(tree, currentFocusId);\n const toPath = getNodePath(tree, target.focusId);\n let ancestor: OrbitNode | null = null;\n\n for (let index = 0; index < Math.min(fromPath.length, toPath.length) && fromPath[index].id === toPath[index].id; index += 1) {\n ancestor = fromPath[index];\n }\n\n if (!ancestor || ancestor.id === currentFocusId || ancestor.id === target.focusId) {\n return null;\n }\n\n return this.focusScene(tree, ancestor.id, this.sceneOptions());\n }\n\n private startTransition(from: Display, target: Scene, placement: Similarity, now: number, duration?: number, landing?: Camera): void {\n this.nodePainter.startFlight();\n const destination = landing ?? placedFrame(target, placement);\n const cameraPath = smoothZoomPath(from.camera, destination, this.viewport);\n this.transition = {\n from: visiblePart(from),\n target,\n placement,\n cameraPath,\n startedAt: now,\n duration: duration ?? this.flightDuration(cameraPath.length),\n };\n this.landingCamera = landing ?? null;\n this.spinPhysics.stop();\n this.tabStopsChanged = true;\n this.clock.add(this.transitionTask);\n // Paint the first frame now, so the map's elements exist as soon as render() returns.\n this.paint();\n }\n\n /** Reduced motion: fade the current view out and the next one in, without moving anything. */\n private startFade(target: Scene): void {\n const now = this.now();\n const from = visiblePart(this.currentDisplay(now));\n this.nextScene = null;\n this.landingCamera = null;\n this.transition = {\n from,\n target,\n placement: IDENTITY,\n cameraPath: { length: 0, at: () => target.frame },\n startedAt: now,\n duration: FADE_DURATION,\n fade: true,\n };\n this.spinPhysics.stop();\n this.tabStopsChanged = true;\n this.clock.add(this.transitionTask);\n this.paint();\n }\n\n private flightDuration(pathLength: number): number {\n const setting = this.options.transitionDuration;\n\n if (typeof setting === 'number') {\n return Math.max(0, setting);\n }\n\n return Math.min(1300, Math.max(480, pathLength * 650));\n }\n\n private readonly transitionTask: FrameTask = (now) => {\n const transition = this.transition;\n\n if (!transition) {\n return false;\n }\n\n if (now - transition.startedAt < transition.duration) {\n return true;\n }\n\n this.finishTransition();\n return this.transition !== null;\n };\n\n private finishTransition(): void {\n const transition = this.transition;\n\n if (!transition) {\n return;\n }\n\n this.transition = null;\n this.scene = transition.target;\n this.camera = this.landingCamera ? { ...this.landingCamera } : { ...transition.target.frame };\n this.landingCamera = null;\n this.spinPhysics.stop();\n this.spinPhysics.angle = 0;\n const next = this.nextScene;\n this.nextScene = null;\n\n if (next) {\n const from = sceneDisplay(this.scene, 0, this.camera);\n this.startTransition(from, next, this.placeTarget(from, next) ?? overlayPlacement(next, this.camera), this.now());\n return;\n }\n\n this.afterArrival();\n }\n\n /** Jumps to the end of any flight in progress. */\n private completeTransition(): void {\n if (!this.transition) {\n return;\n }\n\n const landing = this.nextScene ?? this.transition.target;\n const camera = this.nextScene ? null : this.landingCamera;\n this.transition = null;\n this.nextScene = null;\n this.landingCamera = null;\n this.restOn(landing, false);\n\n if (camera) {\n this.camera = camera;\n }\n }\n\n /** Shows `scene` at rest, fitted. */\n private restOn(scene: Scene, arrive = true): void {\n this.scene = scene;\n this.camera = { ...scene.frame };\n this.spinPhysics.stop();\n this.spinPhysics.angle = 0;\n this.tabStopsChanged = true;\n this.paint();\n\n if (arrive) {\n this.afterArrival();\n }\n }\n\n private afterArrival(): void {\n if (this.relayoutOnArrival) {\n this.relayoutOnArrival = false;\n this.refitOnArrival = false;\n this.rebuild('instant');\n return;\n }\n\n if (this.refitOnArrival) {\n this.refitOnArrival = false;\n this.refreshScene();\n this.fit();\n }\n\n this.tabStopsChanged = true;\n this.topPlanetId = this.planetNearestTop()?.id ?? null;\n this.clock.requestPaint();\n this.syncAmbientMotion();\n // Keep keyboard focus on the map when the node it was on has left.\n const active = this.root.ownerDocument.activeElement;\n\n if (this.returnFocusToMap && (!active || !this.svg.contains(active))) {\n this.paint();\n this.focusNodeElement(this.activeId ?? this.focusId);\n }\n\n this.returnFocusToMap = false;\n }\n\n /**\n * Builds the view again: `enter` animates it in, `morph` moves today's\n * nodes into their new places, `instant` just shows it.\n */\n private rebuild(mode: 'enter' | 'morph' | 'instant'): void {\n // The page may have switched the map's fonts since the last draw: check once it's idle.\n this.labelFonts.recheckWhenIdle(() => this.labelPainter.refit());\n const renamed = this.renamedIds;\n this.renamedIds = new Map();\n const arrival = this.arrival;\n this.arrival = null;\n this.completeTransition();\n this.stopMotion();\n const target = this.buildScene();\n this.emptyState.hidden = !(this.tree && isEmptyTree(this.tree));\n\n if (!target) {\n this.scene = null;\n this.paint();\n return;\n }\n\n if (mode === 'instant' || !this.animationsEnabled()) {\n this.restOn(target);\n return;\n }\n\n const now = this.now();\n\n if (mode === 'enter' || !this.scene) {\n const from: Display = {\n nodes: new Map(),\n rings: [],\n links: [],\n camera: { ...target.frame, scale: target.frame.scale * 0.82 },\n };\n this.scene = target;\n this.startTransition(from, target, IDENTITY, now, ENTRY_DURATION);\n return;\n }\n\n const from = this.dropFrom ?? withArrival(renameNodes(sceneDisplay(this.scene, this.rotation, this.camera), renamed), arrival, target);\n // A live edit in the overview keeps the reader's zoom and position.\n const keepCamera = target.kind === 'overview' && this.scene.kind === 'overview';\n this.startTransition(from, target, IDENTITY, now, MORPH_DURATION, keepCamera ? { ...this.camera } : undefined);\n }\n\n /** Rebuilds the current view in place (new colors, same layout). */\n private refreshScene(): void {\n this.completeTransition();\n const target = this.buildScene();\n\n if (!target || !this.scene) {\n this.rebuild('instant');\n return;\n }\n\n this.scene = target;\n this.camera = this.clampCamera(this.camera);\n this.labelPainter.forgetLightText();\n this.paint();\n }\n\n private currentDisplay(now: number): Display {\n const transition = this.transition;\n\n if (transition) {\n const progress = transition.duration <= 0 ? 1 : Math.min(1, Math.max(0, (now - transition.startedAt) / transition.duration));\n return transition.fade ? fadeDisplay(transition, progress) : transitionDisplay(transition, easeInOutCubic(progress));\n }\n\n // At rest only the camera and the spin change: reuse the layout while the spin stands still.\n const scene = this.scene as Scene;\n const cached = this.restingDisplay;\n\n if (cached && cached.scene === scene && cached.rotation === this.rotation) {\n return { ...cached.display, camera: this.camera };\n }\n\n const display = sceneDisplay(scene, this.rotation, this.camera);\n this.restingDisplay = { scene, rotation: this.rotation, display };\n return display;\n }\n\n /** Stops every camera and orbit motion except a flight between views. */\n private stopMotion(): void {\n this.cameraFlight = null;\n this.wheelZoom = null;\n this.glide.stop();\n\n if (this.spinPhysics.mode !== 'dragging') {\n this.spinPhysics.stop();\n }\n }\n\n // Painting\n\n private paint(): void {\n if (this.destroyed) {\n return;\n }\n\n if (!this.scene) {\n this.display = null;\n this.clearViews();\n return;\n }\n\n const settled = this.currentDisplay(this.now());\n const display = this.withCarried(settled);\n this.display = display;\n const worldTransform = cameraTransform(display.camera, this.viewport);\n\n if (worldTransform !== this.worldTransform) {\n this.world.setAttribute('transform', worldTransform);\n this.worldTransform = worldTransform;\n }\n\n this.ringsAndLinks.paint(display, this.options.showRings !== false);\n const turn = this.nodePainter.paintTurn(display);\n this.nodePainter.paintNodes(display, turn);\n this.paintAddSlot(display, turn);\n this.paintHeldPlace(settled, turn);\n this.contentPainter.paint(display);\n this.labelPainter.paint(display);\n\n this.changedIds.clear();\n this.paintOverlay(display);\n this.placeEditor(display);\n\n if (this.tabStopsChanged) {\n this.updateTabStops();\n }\n\n if (this.tooltip.isVisible) {\n this.positionTooltip();\n }\n }\n\n /** The node whose text is being typed on the map, if any. */\n private editedId(): string | null {\n return this.editor.isOpen ? this.editing?.nodeId ?? null : null;\n }\n\n private paintAddSlot(display: Display, turn: number | undefined): void {\n const slot = display.addSlot;\n const parent = slot ? display.nodes.get(slot.parentId)?.node : undefined;\n // The + in the orbit is the place held for a node carried there from elsewhere.\n const drag = this.nodeDrag?.moving ? this.nodeDrag : null;\n const held = drag !== null && !this.carriesPlanet(drag) && drag.slot !== null ? drag : null;\n const label = held\n ? this.words.text('moveHere', { name: held.node.text || this.words.text('theIdea') })\n : this.words.text('addIdeaTo', { name: parent?.text || this.words.text('thisIdea') });\n const drop = held ? (held.place?.into ? 'waiting' : 'target') : false;\n this.addSlotView.update(slot, label, this.editor.isOpen && this.editing?.nodeId === null, turn, drop);\n }\n\n /** The place held for a planet being dragged: an empty ring where it's laid out, under the press's way. */\n private paintHeldPlace(settled: Display, turn: number | undefined): void {\n const drag = this.nodeDrag;\n const entry = drag && this.carriesPlanet(drag) ? settled.nodes.get(drag.id) : undefined;\n const place: DisplaySlot | undefined = drag && entry\n ? { parentId: drag.parent.id, index: drag.slot ?? 0, x: entry.x, y: entry.y, radius: entry.radius, opacity: entry.opacity, unturned: entry.unturned }\n : undefined;\n this.heldPlaceView.update(place, '', false, turn, drag?.place?.into ? 'waiting' : 'target');\n }\n\n /** Lays the field for typing over its node, or the +, wherever they are this frame. */\n private placeEditor(display: Display): void {\n const session = this.editing;\n\n if (!session || !this.editor.isOpen) {\n return;\n }\n\n const { camera } = display;\n\n if (session.nodeId === null) {\n const slot = display.addSlot;\n const shown = slot && slot.parentId === session.parentId && slot.opacity > 0.5;\n this.editor.place(shown ? this.editorPlacement(worldToScreen(camera, this.viewport, slot), slot.radius * camera.scale, 'planet', false, true) : null);\n return;\n }\n\n const entry = display.nodes.get(session.nodeId);\n const shown = entry && entry.opacity > 0.5;\n this.editor.place(shown ? this.editorPlacement(worldToScreen(camera, this.viewport, entry), entry.radius * camera.scale, entry.role, this.labelPainter.usesLightText(entry), false, entry.hiddenChildren) : null);\n }\n\n /**\n * The field's place and size: the label's, inside the node; a node too\n * small to hold it gets a field floating over it at a readable size. Over a\n * node with a \"+N\" (`hiddenChildren` it doesn't draw), the field rises as\n * it grows, as names do, to keep clear of the count.\n */\n private editorPlacement(point: Point, screenRadius: number, role: NodeRole, light: boolean, slot: boolean, hiddenChildren = 0): EditorPlacement {\n const floating = screenRadius < 32;\n const width = floating ? Math.max(140, insideLabelWidth(role, screenRadius)) : insideLabelWidth(role, screenRadius);\n return {\n x: point.x,\n y: point.y,\n width,\n fontSize: Math.max(13, insideFontSize(role, width, this.editor.value || this.words.text('newIdea'), this.labelFonts.inside(role))),\n maxHeight: Math.max(44, screenRadius * 1.5),\n role,\n light: light && !floating,\n slot,\n floating: floating && !slot,\n lowest: !floating && showsCount(role, screenRadius, hiddenChildren) ? COUNT_POSITION * screenRadius - COUNT_HEIGHT / 2 : undefined,\n };\n }\n\n private paintOverlay(display: Display): void {\n const { camera } = display;\n const scene = this.scene;\n const sun = this.viewMode === 'focus' && !this.transition && scene ? display.nodes.get(scene.focusId) : undefined;\n\n const place = sun && scene && this.showsActions() && this.zoomLevel() < 1.5 ? this.actionsPlace(scene, sun, camera) : null;\n\n if (sun && place) {\n this.actionBar.show(sun.node, place.x, place.y, place.wrap);\n } else {\n this.actionBar.hide();\n }\n }\n\n private clearViews(): void {\n this.labelPainter.clear();\n\n this.nodePainter.clear();\n this.ringsAndLinks.clear();\n\n this.contentPainter.clear();\n\n this.actionBar.reset();\n }\n\n /** One tab stop for the whole map (roving tabindex); arrow keys move between nodes. */\n private updateTabStops(): void {\n this.tabStopsChanged = false;\n const interactive = this.options.interactive !== false;\n const scene = this.transition?.target ?? this.scene;\n\n if (!this.activeId || !scene?.nodes.has(this.activeId) || !this.nodePainter.view(this.activeId)) {\n this.activeId = scene?.focusId ?? null;\n }\n\n for (const [id, view] of this.nodePainter.entries()) {\n const tabStop = interactive ? (id === this.activeId ? '0' : '-1') : null;\n\n // Only a real change is written: newcomer flights run this once per frame, over every node.\n if (view.element.getAttribute('tabindex') !== tabStop) {\n if (tabStop === null) {\n view.element.removeAttribute('tabindex');\n } else {\n view.element.setAttribute('tabindex', tabStop);\n }\n }\n }\n }\n\n private focusNodeElement(id: string): void {\n const view = this.nodePainter.view(id);\n\n if (!view) {\n return;\n }\n\n this.activeId = id;\n this.updateTabStops();\n view.element.focus({ preventScroll: true });\n }\n\n // Chrome: controls, outline, tooltip, announcements\n\n private updateControls(): void {\n this.root.dataset.orbitView = this.viewMode;\n const path = this.tree ? getNodePath(this.tree, this.focusId) : [];\n this.controls.update({ viewMode: this.viewMode, path, outlineOpen: this.outline.isVisible });\n }\n\n /** The outline, and the pictures and videos the viewer steps through, follow the map. */\n private updateOutline(): void {\n if (this.tree) {\n this.outline.update(this.tree, this.focusId, this.options.maxDepth, this.options.interactive !== false, (node) => this.extensions.icon(node));\n }\n\n this.viewer.refresh();\n }\n\n private toggleOutline(): void {\n this.outline.setVisible(!this.outline.isVisible);\n this.updateControls();\n }\n\n private selectFromOutline(nodeId: string): void {\n if (this.outline.isVisible) {\n this.outline.setVisible(false);\n }\n\n this.activeId = nodeId;\n this.returnFocusToMap = true;\n this.navigate('focus', nodeId);\n this.updateControls();\n }\n\n private announceView(): void {\n if (this.viewMode === 'all') {\n this.outline.announce(this.words.text('overviewAnnouncement'));\n return;\n }\n\n const node = this.getFocusedNode();\n\n if (node) {\n const count = node.children.length;\n const name = node.text || this.words.text('untitled');\n this.outline.announce(count > 0 ? `${name}, ${this.words.count('ideaCount', count)}` : name);\n }\n }\n\n private updateTooltip(): void {\n const id = this.dragging ? null : this.hoveredId ?? this.keyboardFocusId;\n const entry = id ? this.display?.nodes.get(id) : undefined;\n\n if (!entry || this.transition) {\n this.tooltip.hide();\n return;\n }\n\n const node = entry.node;\n const typeLabel = this.extensions.nodeType(node)?.label;\n const placement = this.labelPainter.placementOf(entry.id) ?? 'hidden';\n // The tooltip shows a little of the note: bound the text before stripping\n // its markdown, whose link markup is slow to unpack on a huge note.\n const note = node.note ? noteToPlainText(node.note.slice(0, 400)).replace(/\\s+/g, ' ').trim() : '';\n const clipped = placement === 'hidden' || node.text.length > 24;\n\n if (!clipped && !note && !node.status && !typeLabel) {\n this.tooltip.hide();\n return;\n }\n\n const details = [\n typeLabel ?? '',\n node.status ? this.words.text('statusLabel', { status: node.status }) : '',\n note.length > 140 ? `${note.slice(0, 139)}…` : note,\n ].filter(Boolean);\n const point = this.tooltipAnchor(entry);\n this.tooltip.show([this.extensions.icon(node), node.text || this.words.text('untitled')].filter(Boolean).join(' '), details.join(' · '), point.x, point.y);\n }\n\n private positionTooltip(): void {\n const id = this.hoveredId ?? this.keyboardFocusId;\n const entry = id ? this.display?.nodes.get(id) : undefined;\n\n if (!entry) {\n this.tooltip.hide();\n return;\n }\n\n const point = this.tooltipAnchor(entry);\n this.tooltip.place(point.x, point.y);\n }\n\n private tooltipAnchor(entry: DisplayNode): Point {\n const camera = this.display?.camera ?? this.camera;\n const point = worldToScreen(camera, this.viewport, entry);\n return { x: point.x, y: point.y - entry.radius * camera.scale };\n }\n\n // Interaction: nodes, keyboard, hover\n\n private readonly handleClick = (event: MouseEvent): void => {\n if (this.options.interactive === false || event.detail > 1) {\n return;\n }\n\n if (isAddSlot(event.target)) {\n this.editNewNode();\n return;\n }\n\n const id = nodeIdFrom(event.target);\n\n if (id) {\n this.activate(id);\n }\n };\n\n /** A right click, or the browser's own long press or context menu key, on a node. */\n private readonly handleContextMenu = (event: MouseEvent): void => {\n const id = nodeIdFrom(event.target);\n\n if (!id || this.options.interactive === false) {\n return;\n }\n\n if (this.openNodeContext(id, this.contextPoint(event, id))) {\n event.preventDefault();\n }\n };\n\n /**\n * Where a context menu event points on the map: the pointer when it is on\n * the node, otherwise the node's center (menus opened from the keyboard\n * report the element's corner, or nothing).\n */\n private contextPoint(event: MouseEvent, id: string): Point {\n const center = this.nodeOnScreen(id);\n const bounds = this.root.getBoundingClientRect();\n const point = { x: event.clientX - bounds.left, y: event.clientY - bounds.top };\n const entry = this.display?.nodes.get(id);\n const reach = (entry?.radius ?? 0) * (this.display?.camera.scale ?? 1) + 24;\n return Number.isFinite(point.x) && Number.isFinite(point.y) && Math.hypot(point.x - center.x, point.y - center.y) <= reach ? point : center;\n }\n\n /** A node's center on the map. */\n private nodeOnScreen(id: string): Point {\n const entry = this.display?.nodes.get(id);\n\n if (!entry) {\n return this.viewportCenter();\n }\n\n return worldToScreen(this.display?.camera ?? this.camera, this.viewport, entry);\n }\n\n /**\n * Reports a long press, right click or context menu key on a node.\n * Returns whether someone took it: an `onNodeContext` callback, a\n * `node-context` listener, or a DOM listener that called\n * `preventDefault()`. A press someone took doesn't open the node, and the\n * browser's menu stays closed.\n */\n private openNodeContext(id: string, point: Point, longPress = false): boolean {\n const scene = this.transition?.target ?? this.scene;\n const entry = scene?.nodes.get(id);\n\n if (!entry) {\n return false;\n }\n\n const now = this.now();\n const previous = this.lastContext;\n\n if (previous && previous.id === id && now - previous.time < CONTEXT_REPEAT) {\n return previous.taken;\n }\n\n const detail: OrbitNodeContextEvent = { node: entry.node, x: Math.round(point.x), y: Math.round(point.y) };\n const listening = this.options.onNodeContext !== undefined || (this.listeners.get('node-context')?.size ?? 0) > 0;\n this.options.onNodeContext?.(detail);\n let taken = !this.emit('node-context', detail, true) || listening;\n\n // Without a menu of the page's own, an editable map types the node's text where it is: after a long\n // press, once it's let go without moving, as the press may drag the node instead.\n if (!taken && this.options.editable) {\n if (longPress && this.canLift(id)) {\n this.editOnLift = id;\n taken = true;\n } else {\n taken = this.editNode(id);\n }\n }\n\n this.lastContext = { id, time: now, taken };\n\n if (taken) {\n // A menu is about to cover the node: its tooltip goes.\n this.hoveredId = null;\n this.keyboardFocusId = null;\n this.updateTooltip();\n }\n\n return taken;\n }\n\n // Interaction: dragging a node somewhere else\n\n /** Whether a press held on node `id` lifts it: on an editable map at rest, any node but the root and the sun. */\n private canLift(id: string): boolean {\n if (!this.options.editable || this.options.interactive === false || this.transition || this.editing) {\n return false;\n }\n\n const entry = this.display?.nodes.get(id);\n return entry !== undefined && entry.role !== 'sun' && entry.opacity > 0.5 && entry.parentId !== undefined\n && this.tree !== null && getNodePath(this.tree, id).length > 1;\n }\n\n /** A press held still on node `id`: it lifts, to be dragged somewhere else. Returns whether it did. */\n private liftNode(id: string | null, point: Point): boolean {\n const editOnRelease = id !== null && this.editOnLift === id;\n this.editOnLift = null;\n const display = this.display;\n const tree = this.tree;\n\n if (id === null || !display || !tree || !this.canLift(id)) {\n return false;\n }\n\n const path = getNodePath(tree, id);\n const node = path[path.length - 1];\n const parent = path[path.length - 2];\n const entry = display.nodes.get(id) as DisplayNode;\n const world = screenToWorld(display.camera, this.viewport, point);\n // The moons go with their planet, each where it is around it.\n const bodies = Array.from(display.nodes.values())\n .filter((body) => body.id === id || (body.role === 'moon' && body.hostId === id))\n .map((body) => ({ ...body, x: body.x - entry.x, y: body.y - entry.y, unturned: undefined, cluster: undefined }));\n this.nodeDrag = {\n id,\n node,\n parent,\n index: parent.children.indexOf(node),\n unreachable: unreachableIds(node, parent.id),\n moving: false,\n point,\n grab: { x: world.x - entry.x, y: world.y - entry.y },\n bodies,\n ringRadius: null,\n rings: null,\n slot: null,\n place: null,\n editOnRelease,\n scale: 1,\n };\n this.hoveredId = null;\n this.updateTooltip();\n this.clock.requestPaint();\n return true;\n }\n\n /** The press holding a lifted node moved, was let go, or was taken away. */\n private dragNode(point: Point, phase: 'move' | 'drop' | 'cancel'): void {\n const drag = this.nodeDrag;\n\n if (!drag) {\n return;\n }\n\n if (this.destroyed) {\n this.nodeDrag = null;\n return;\n }\n\n drag.point = point;\n\n if (phase === 'move') {\n if (!drag.moving) {\n this.startCarrying(drag);\n }\n\n this.updateDropPlace(drag);\n this.clock.requestPaint();\n return;\n }\n\n // Where it's let go decides, even if the last move was elsewhere.\n const place = drag.moving ? this.dropPlaceAt(drag) : null;\n\n if (phase === 'drop' && place) {\n this.dropNode(drag, place);\n return;\n }\n\n this.putBack(drag, phase === 'drop');\n }\n\n /**\n * The lifted node leaves its place to follow the press. A planet of the\n * focused orbit keeps its place held, so nothing moves and nothing slides\n * under the press; anything else leaves an empty place behind.\n */\n private startCarrying(drag: NodeDrag): void {\n drag.moving = true;\n\n if (this.viewMode === 'focus' && this.scene?.kind === 'focus') {\n drag.ringRadius = this.scene.rings[0]?.radius ?? 0;\n drag.rings = { focusId: this.scene.focusId, radii: this.scene.rings.map((ring) => ring.radius), size: { ...this.viewport } };\n drag.slot = drag.parent.id === this.focusId ? drag.index : null;\n }\n\n drag.place = drag.slot === null ? null : { parentId: this.focusId, index: drag.slot, into: false };\n this.emitDrag('start', drag.node, drag.parent, drag.index);\n // It leaves its place under the press at once.\n this.paint();\n }\n\n /** Whether the node being dragged is one of the focused orbit's planets, laid out at the place held for it. */\n private carriesPlanet(drag: NodeDrag): boolean {\n return drag.moving && drag.slot !== null && drag.parent.id === this.focusId && this.viewMode === 'focus';\n }\n\n /**\n * Where the dragged node would go if let go now: into the node under the\n * press, at the place in the orbit under it, or else at the place held for\n * it. Null when there's none of those.\n */\n private dropPlaceAt(drag: NodeDrag): DropPlace | null {\n const display = this.display;\n\n if (!display) {\n return null;\n }\n\n const { camera } = display;\n const world = screenToWorld(camera, this.viewport, drag.point);\n const current = drag.place?.into ? drag.place.parentId : null;\n const focus = this.viewMode === 'focus';\n\n const catchRadius = (entry: DisplayNode, held: boolean): number => {\n const reach = focus && entry.role === 'planet'\n ? Math.max(entry.radius * PLANET_CORE, PLANET_CORE_PX / camera.scale)\n : entry.radius + DROP_REACH / camera.scale;\n return held ? reach * KEEP_TARGET : reach;\n };\n\n const under = nodeUnder(display, world, drag.unreachable, catchRadius, current);\n\n if (under) {\n return { parentId: under.id, index: null, into: true };\n }\n\n const held = drag.slot === null ? null : { parentId: this.focusId, index: drag.slot, into: false };\n // Over a node it can't go into, such as the planet a moon is leaving, where it would go stays as it was.\n const carried = new Set(drag.bodies.map((body) => body.id));\n\n for (const entry of display.nodes.values()) {\n if (drag.unreachable.has(entry.id) && !carried.has(entry.id) && Math.hypot(world.x - entry.x, world.y - entry.y) <= entry.radius) {\n return drag.place?.into ? held : drag.place;\n }\n }\n\n // The orbit as it will rest: a flight's target is drawn unturned.\n const layout = this.transition?.target ?? this.scene;\n const sun = display.nodes.get(this.focusId);\n\n if (drag.ringRadius !== null && layout && sun) {\n const band = Math.max(ORBIT_BAND / camera.scale, (drag.bodies[0]?.radius ?? 0) * 1.2);\n const rotation = this.transition ? 0 : this.rotation;\n const index = orbitPlaceAt(layout, { x: world.x - sun.x, y: world.y - sun.y }, rotation, drag.ringRadius, band, drag.id, drag.slot);\n\n if (index !== null) {\n return { parentId: this.focusId, index, into: false };\n }\n }\n\n return held;\n }\n\n /**\n * Follows where the dragged node would go, and tells the page when that\n * changes. The orbit is laid out again only when the place held in it\n * moves: hovering a node leaves the planets where they are, so the node\n * stays under the press.\n */\n private updateDropPlace(drag: NodeDrag): void {\n const place = this.dropPlaceAt(drag);\n\n if (samePlace(place, drag.place)) {\n return;\n }\n\n drag.place = place;\n const parent = place && this.tree ? findNodeById(this.tree, place.parentId) : null;\n this.emitDrag('over', drag.node, parent, place?.index ?? null);\n\n if (place && !place.into && place.index !== drag.slot) {\n drag.slot = place.index;\n this.relayoutForDrag();\n } else {\n // The new target shows at once; the place held waits while a node is the target.\n this.paint();\n }\n }\n\n /**\n * Lays the view out again around the node being dragged, with the place\n * held for it where it would land in the orbit, the planets making room.\n * They glide from wherever they are this frame, and the camera holds still.\n */\n private relayoutForDrag(): void {\n const target = this.buildScene();\n\n if (!target || !this.scene) {\n return;\n }\n\n const now = this.now();\n const from = this.currentDisplay(now);\n this.nextScene = null;\n\n if (!this.animationsEnabled()) {\n this.transition = null;\n this.landingCamera = null;\n this.restOn(target, false);\n this.camera = { ...from.camera };\n this.paint();\n return;\n }\n\n this.startTransition(from, target, IDENTITY, now, DRAG_MORPH_DURATION, { ...from.camera });\n }\n\n /** Lets the dragged node go at `place`: it moves there (an `edit`), and flies from where it was let go. */\n private dropNode(drag: NodeDrag, place: DropPlace): void {\n // Back at the place it came from is no move at all.\n if (place.parentId === drag.parent.id && (place.index ?? drag.parent.children.length - 1) === drag.index) {\n this.putBack(drag, false);\n return;\n }\n\n this.dropFrom = this.display;\n this.nodeDrag = null;\n const moved = this.moveNode(drag.id, place.parentId, place.index ?? undefined);\n this.dropFrom = null;\n\n if (!moved) {\n this.rebuild('morph');\n this.emitDrag('end', drag.node, null, null);\n return;\n }\n\n const tree = this.tree as OrbitNode;\n const path = getNodePath(tree, moved.id);\n const parent = path[path.length - 2] ?? null;\n this.emitDrag('end', moved, parent, parent ? parent.children.indexOf(moved) : null);\n }\n\n /**\n * Puts the dragged node back where it was: it flies back from where it\n * was let go. One only lifted goes back down; `released` without moving\n * after a long press no one took, it's typed into.\n */\n private putBack(drag: NodeDrag, released: boolean): void {\n this.nodeDrag = null;\n\n if (drag.moving) {\n this.dropFrom = this.display;\n this.rebuild('morph');\n this.dropFrom = null;\n this.emitDrag('end', drag.node, null, null);\n return;\n }\n\n this.clock.requestPaint();\n\n if (released && drag.editOnRelease) {\n this.editNode(drag.id);\n }\n }\n\n private emitDrag(phase: OrbitNodeDragEvent['phase'], node: OrbitNode, parent: OrbitNode | null, index: number | null): void {\n const event: OrbitNodeDragEvent = { phase, node, parent, index };\n this.options.onNodeDrag?.(event);\n this.emit('node-drag', event);\n }\n\n /**\n * `display` with the node being dragged, and its moons, under the press:\n * over a node it would go into, smaller, nearer the press and without its\n * name, as if about to go inside.\n */\n private withCarried(display: Display): Display {\n const drag = this.nodeDrag;\n\n if (!drag?.moving) {\n return display;\n }\n\n const goal = drag.place?.into ? INTO_SCALE : 1;\n drag.scale += (goal - drag.scale) * (this.prefersReducedMotion() ? 1 : CARRIED_EASING);\n\n if (Math.abs(goal - drag.scale) < 0.01) {\n drag.scale = goal;\n } else {\n this.clock.requestPaint();\n }\n\n const { scale } = drag;\n const world = screenToWorld(display.camera, this.viewport, drag.point);\n const centerX = world.x - drag.grab.x * scale;\n const centerY = world.y - drag.grab.y * scale;\n const named = scale > (1 + INTO_SCALE) / 2 ? 1 : 0;\n const nodes = new Map(display.nodes);\n\n for (const body of drag.bodies) {\n nodes.set(body.id, { ...body, x: centerX + body.x * scale, y: centerY + body.y * scale, radius: body.radius * scale, opacity: 1, labelOpacity: named });\n }\n\n return { ...display, nodes };\n }\n\n /** A click (or Enter) on a node: the sun goes back up, anything else is entered. */\n private activate(id: string): void {\n const scene = this.transition?.target ?? this.scene;\n const entry = scene?.nodes.get(id);\n\n if (!entry) {\n return;\n }\n\n if (this.transition && this.now() - this.transition.startedAt < CLICK_GUARD) {\n return;\n }\n\n this.options.onNodeClick?.(entry.node);\n this.emit('node-click', { node: entry.node });\n\n if (this.viewMode === 'focus' && entry.role === 'sun') {\n this.goBack();\n return;\n }\n\n this.navigate('focus', id);\n }\n\n /** Up a level in focus mode; from the overview, back to focus mode. */\n private goBack(): boolean {\n if (this.viewMode === 'all') {\n return this.navigate('focus', this.focusId);\n }\n\n const parent = this.focusPath[this.focusPath.length - 2];\n return parent === undefined ? false : this.navigate('focus', parent);\n }\n\n private readonly handleKeyDown = (event: KeyboardEvent): void => {\n if (this.options.interactive === false || this.viewer.isOpen || event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey) {\n return;\n }\n\n const id = nodeIdFrom(event.target);\n const onSlot = isAddSlot(event.target);\n let handled = true;\n\n switch (event.key) {\n case 'Enter':\n case ' ':\n if (event.key === 'Enter' && event.shiftKey && this.editingKeys) {\n handled = onSlot ? this.editNewNode() : id !== null && this.addBeside(id);\n } else if (onSlot) {\n this.editNewNode();\n } else if (id) {\n this.activate(id);\n } else {\n handled = false;\n }\n\n break;\n case 'F2':\n // Like a long press or a right click, only on maps people may edit; editNode() works on any.\n handled = this.options.editable === true && id !== null && this.editNode(id);\n break;\n case 'Tab':\n case 'Insert':\n // Shift+Tab leaves the map, as without the keys.\n handled = this.editingKeys && !event.shiftKey && (onSlot ? this.editNewNode() : id !== null && this.editNewNode(id));\n break;\n case 'Delete':\n handled = this.editingKeys && id !== null && this.removeWithKey(id);\n break;\n case 'Escape':\n case 'Backspace':\n // Escape puts a node being dragged back first.\n if (event.key === 'Escape' && this.nodeDrag) {\n this.putBack(this.nodeDrag, false);\n break;\n }\n\n handled = this.goBack();\n break;\n case 'ContextMenu':\n handled = id !== null && this.openNodeContext(id, this.nodeOnScreen(id));\n break;\n case 'F10':\n handled = event.shiftKey && id !== null && this.openNodeContext(id, this.nodeOnScreen(id));\n break;\n case '+':\n case '=':\n this.zoomBy(STEP_ZOOM);\n break;\n case '-':\n case '_':\n this.zoomBy(1 / STEP_ZOOM);\n break;\n case '0':\n this.fit();\n break;\n case 'ArrowLeft':\n case 'ArrowRight':\n case 'ArrowUp':\n case 'ArrowDown':\n case 'Home':\n case 'End':\n handled = this.moveFocus(event.key, onSlot ? SLOT_STOP : id);\n break;\n default:\n handled = false;\n }\n\n if (handled) {\n event.preventDefault();\n }\n };\n\n /**\n * Arrow-key movement. Focus mode: left and right step through the planets\n * (turning the orbit so the chosen one sits on top), down enters the\n * orbit, up returns to the sun. Overview: the tree, as in a tree view.\n */\n private moveFocus(key: string, currentId: string | null): boolean {\n const scene = this.transition?.target ?? this.scene;\n const tree = this.tree;\n\n if (!scene || !tree) {\n return false;\n }\n\n if (this.viewMode === 'focus') {\n // The + takes its turn in the orbit, after the planets before it.\n const stops: (SceneNode | typeof SLOT_STOP)[] = orderedPlanets(scene);\n\n if (scene.addSlot && this.addSlotView.isShown) {\n const slotAngle = clockwiseFromTop(scene.addSlot.orbitAngle);\n const after = stops.filter((stop) => stop !== SLOT_STOP && clockwiseFromTop(stop.orbitAngle ?? 0) < slotAngle).length;\n stops.splice(after, 0, SLOT_STOP);\n }\n\n if (stops.length === 0) {\n return false;\n }\n\n const index = stops.findIndex((stop) => (stop === SLOT_STOP ? currentId === SLOT_STOP : stop.id === currentId));\n let next: SceneNode | typeof SLOT_STOP | undefined;\n\n if (key === 'ArrowUp') {\n this.focusNodeElement(scene.focusId);\n return true;\n }\n\n if (key === 'Home') {\n next = stops[0];\n } else if (key === 'End') {\n next = stops[stops.length - 1];\n } else if (index === -1) {\n next = key === 'ArrowLeft' ? stops[stops.length - 1] : stops[0];\n } else if (key === 'ArrowRight') {\n next = stops[(index + 1) % stops.length];\n } else if (key === 'ArrowLeft') {\n next = stops[(index - 1 + stops.length) % stops.length];\n } else {\n next = stops[index];\n }\n\n if (next === SLOT_STOP) {\n this.addSlotView.element.focus({ preventScroll: true });\n } else {\n this.turnToTop(next);\n this.focusNodeElement(next.id);\n }\n\n return true;\n }\n\n const current = currentId ? findNodeById(tree, currentId) : null;\n\n if (!current) {\n this.focusNodeElement(tree.id);\n return true;\n }\n\n const siblings = current.parent?.children ?? [current];\n const position = siblings.indexOf(current);\n let next: OrbitNode | undefined;\n\n if (key === 'ArrowUp') {\n next = current.parent;\n } else if (key === 'ArrowDown') {\n next = current.children.find((child) => scene.nodes.has(child.id));\n } else if (key === 'ArrowLeft') {\n next = siblings[position - 1];\n } else if (key === 'ArrowRight') {\n next = siblings[position + 1];\n } else if (key === 'Home') {\n next = tree;\n } else if (key === 'End') {\n next = siblings[siblings.length - 1];\n }\n\n if (!next || !scene.nodes.has(next.id)) {\n return true;\n }\n\n this.focusNodeElement(next.id);\n this.keepInView(next.id);\n return true;\n }\n\n /** Turns the orbit so `planet` sits at the top. */\n private turnToTop(planet: SceneNode): void {\n if (planet.orbitAngle === undefined || this.transition) {\n return;\n }\n\n const target = -90 - planet.orbitAngle;\n\n if (this.prefersReducedMotion()) {\n this.spinPhysics.angle = target;\n this.clock.requestPaint();\n return;\n }\n\n this.spinPhysics.settleTo(target);\n this.clock.add(this.spinTask);\n }\n\n /** Pans the overview so a node that has keyboard focus is on screen. */\n private keepInView(id: string): void {\n const entry = this.display?.nodes.get(id);\n\n if (!entry || !this.display) {\n return;\n }\n\n const point = worldToScreen(this.display.camera, this.viewport, entry);\n const radius = entry.radius * this.display.camera.scale;\n const margin = 48;\n\n if (point.x - radius >= margin && point.x + radius <= this.viewport.width - margin\n && point.y - radius >= margin && point.y + radius <= this.viewport.height - margin) {\n return;\n }\n\n this.flyCamera(this.clampCamera({ ...this.camera, x: entry.x, y: entry.y }), this.viewportCenter());\n }\n\n private readonly handlePointerOver = (event: PointerEvent): void => {\n if (event.pointerType !== 'mouse' || this.dragging) {\n return;\n }\n\n const id = nodeIdFrom(event.target);\n\n if (id !== this.hoveredId) {\n this.hoveredId = id;\n this.updateTooltip();\n }\n };\n\n private readonly handlePointerOut = (event: PointerEvent): void => {\n const id = nodeIdFrom(event.relatedTarget);\n\n if (id !== this.hoveredId) {\n this.hoveredId = id;\n this.updateTooltip();\n this.syncAmbientMotion();\n }\n };\n\n private readonly handleFocusIn = (event: FocusEvent): void => {\n const id = nodeIdFrom(event.target);\n\n if (!id) {\n return;\n }\n\n this.nodePainter.view(id)?.showFocusRing();\n\n if (id !== this.activeId) {\n this.activeId = id;\n this.tabStopsChanged = true;\n this.clock.requestPaint();\n }\n\n this.keyboardFocusId = isFocusVisible(event.target) ? id : null;\n this.updateTooltip();\n };\n\n private readonly handleFocusOut = (event: FocusEvent): void => {\n if (!nodeIdFrom(event.relatedTarget)) {\n this.keyboardFocusId = null;\n this.updateTooltip();\n this.syncAmbientMotion();\n }\n };\n\n // Interaction: spin\n\n private dragGestureAt(point: Point): DragGesture {\n const scene = this.scene;\n\n if (!scene || this.transition) {\n return 'none';\n }\n\n if (this.viewMode === 'all' || this.zoomLevel() > 1.04) {\n return 'pan';\n }\n\n if (!Array.from(scene.nodes.values()).some((node) => node.role === 'planet')) {\n return 'none';\n }\n\n const center = this.sunOnScreen();\n return Math.hypot(point.x - center.x, point.y - center.y) > 12 ? 'spin' : 'none';\n }\n\n private sunOnScreen(): Point {\n const scene = this.scene;\n const sun = scene ? this.display?.nodes.get(scene.focusId) : undefined;\n return sun && this.display ? worldToScreen(this.display.camera, this.viewport, sun) : this.viewportCenter();\n }\n\n private releaseSpin(velocity: number): void {\n const scene = this.scene;\n\n if (!scene) {\n return;\n }\n\n // Momentum is motion the reader didn't directly make: none with reduced motion.\n if (this.prefersReducedMotion()) {\n this.spinPhysics.stop();\n this.spinSettled();\n return;\n }\n\n const slots = orderedPlanets(scene).map((planet) => -90 - (planet.orbitAngle ?? 0));\n this.spinPhysics.release(velocity, slots);\n\n if (this.spinPhysics.isMoving) {\n this.clock.add(this.spinTask);\n } else {\n this.spinSettled();\n }\n }\n\n private readonly spinTask: FrameTask = (_now, elapsed) => {\n const moving = this.spinPhysics.step(elapsed);\n this.tickHaptics();\n\n if (!moving) {\n this.spinSettled();\n }\n\n return moving;\n };\n\n private spinSettled(): void {\n if (this.userSpun) {\n this.userSpun = false;\n const top = this.planetNearestTop();\n\n if (top) {\n this.options.onSpinSettle?.(top.node);\n this.emit('spin-settle', { planet: top.node });\n }\n }\n\n this.syncAmbientMotion();\n }\n\n private planetNearestTop(): SceneNode | null {\n const scene = this.scene;\n\n if (!scene || this.viewMode !== 'focus') {\n return null;\n }\n\n // Every frame of a spin asks: one pass, nothing sorted. Of two as near, the first clockwise from the top.\n let best: SceneNode | null = null;\n let bestDistance = Infinity;\n\n for (const node of scene.nodes.values()) {\n if (node.role !== 'planet') {\n continue;\n }\n\n const distance = Math.abs(normalizeDelta((node.orbitAngle ?? 0) + this.rotation + 90));\n\n if (distance < bestDistance || (distance === bestDistance && best && clockwiseFromTop(node.orbitAngle ?? 0) < clockwiseFromTop(best.orbitAngle ?? 0))) {\n best = node;\n bestDistance = distance;\n }\n }\n\n return best;\n }\n\n /** A short vibration each time a planet passes the top, like the detents of a dial. */\n private tickHaptics(): void {\n const top = this.planetNearestTop();\n\n if (!top || top.id === this.topPlanetId) {\n return;\n }\n\n const previous = this.topPlanetId;\n this.topPlanetId = top.id;\n const speed = Math.abs(this.spinPhysics.velocity) * 1000;\n\n if (this.options.spin?.haptics && previous !== null && speed < HAPTIC_SPEED_LIMIT && typeof navigator !== 'undefined') {\n navigator.vibrate?.(4);\n }\n }\n\n /** The slow drift of `orbitAnimation`; it pauses while the reader is pointing at, holding or tabbing through the map. */\n private syncAmbientMotion(): void {\n if (!this.ambientRunning && this.shouldDrift()) {\n this.ambientRunning = true;\n this.clock.add(this.ambientTask);\n }\n }\n\n private shouldDrift(): boolean {\n return Boolean(this.options.orbitAnimation)\n && !this.destroyed\n && this.scene !== null\n && this.viewMode === 'focus'\n && !this.transition\n && this.spinPhysics.mode === 'idle'\n && !this.dragging\n && this.cameraFlight === null\n && this.wheelZoom === null\n && !this.glide.isMoving\n && this.hoveredId === null\n && this.keyboardFocusId === null\n && this.onScreen\n && !this.viewer.isOpen\n && !this.prefersReducedMotion();\n }\n\n private readonly ambientTask: FrameTask = (_now, elapsed) => {\n if (!this.shouldDrift()) {\n this.ambientRunning = false;\n this.pendingDrift = 0;\n return false;\n }\n\n const reach = this.spinningReach(this.scene as Scene) * this.camera.scale;\n\n if (reach <= 0) {\n // Nothing in this view spins with the orbit (a leaf in focus): sleep\n // until the view changes and syncAmbientMotion arms the drift again.\n this.ambientRunning = false;\n this.pendingDrift = 0;\n return false;\n }\n\n // Seconds per turn; anything but a positive number falls back to the default.\n const speed = this.options.orbitSpeed > 0 && Number.isFinite(this.options.orbitSpeed) ? this.options.orbitSpeed : DEFAULT_OPTIONS.orbitSpeed;\n this.pendingDrift += (360 / Math.max(1, speed)) * (elapsed / 1000);\n\n // Turning the orbit repaints every body in it: wait until the turn shows.\n if (this.pendingDrift < toDegrees(DRIFT_STEP / reach)) {\n return 'hold';\n }\n\n this.spinPhysics.angle += this.pendingDrift;\n this.pendingDrift = 0;\n return true;\n };\n\n /** How far the bodies that spin with the orbit reach from the sun, in world units. */\n private spinningReach(scene: Scene): number {\n if (this.spinReach?.scene !== scene) {\n const sun = scene.nodes.get(scene.focusId);\n let reach = 0;\n\n for (const node of scene.nodes.values()) {\n if (node.spins) {\n reach = Math.max(reach, Math.hypot(node.x - (sun?.x ?? 0), node.y - (sun?.y ?? 0)) + node.radius);\n }\n }\n\n this.spinReach = { scene, reach };\n }\n\n return this.spinReach.reach;\n }\n\n // Interaction: camera\n\n private zoomLevel(): number {\n return this.scene ? this.camera.scale / this.scene.frame.scale : 1;\n }\n\n private zoomRange(): [number, number] {\n const minimum = this.options.zoom?.minimum ?? DEFAULT_MINIMUM_ZOOM;\n const maximum = this.options.zoom?.maximum ?? DEFAULT_MAXIMUM_ZOOM;\n\n if (this.viewMode === 'focus') {\n return [FOCUS_MINIMUM_ZOOM, Math.max(1, maximum)];\n }\n\n return [Math.min(1, minimum), Math.max(1, maximum)];\n }\n\n private viewportCenter(): Point {\n return { x: this.viewport.width / 2, y: this.viewport.height / 2 };\n }\n\n /**\n * Keeps the content reachable. The overview can pan until its edge meets\n * the middle of the map; focus mode stays centered on the sun when fitted\n * and gains room to pan the further it zooms in.\n */\n private clampCamera(camera: Camera): Camera {\n const scene = this.scene;\n\n if (!scene) {\n return camera;\n }\n\n const { frame } = scene;\n const relative = camera.scale / frame.scale;\n const reach = scene.kind === 'focus' ? Math.max(0, 1 - 1 / relative) : 1;\n const limitX = (this.viewport.width / 2 / frame.scale) * reach;\n const limitY = (this.viewport.height / 2 / frame.scale) * reach;\n return {\n scale: camera.scale,\n x: Math.min(frame.x + limitX, Math.max(frame.x - limitX, camera.x)),\n y: Math.min(frame.y + limitY, Math.max(frame.y - limitY, camera.y)),\n };\n }\n\n private panCamera(deltaX: number, deltaY: number): boolean {\n if (!this.scene || this.transition) {\n return false;\n }\n\n const before = this.camera;\n this.camera = this.clampCamera(panBy(this.camera, deltaX, deltaY));\n this.clock.requestPaint();\n return Math.abs(before.x - this.camera.x) > 1e-6 || Math.abs(before.y - this.camera.y) > 1e-6;\n }\n\n private readonly glideTask: FrameTask = (_now, elapsed) => {\n if (elapsed <= 0) {\n // A duplicate timestamp: nothing moved yet, but the glide isn't done.\n return 'hold';\n }\n\n if (this.glide.isMoving && !this.transition) {\n const distance = this.glide.step(elapsed);\n\n if (this.panCamera(distance.x, distance.y) && this.glide.isMoving) {\n return true;\n }\n }\n\n this.glide.stop();\n this.syncAmbientMotion();\n return false;\n };\n\n /** Zooms immediately by `factor` around `anchor`, within the zoom range. */\n private zoomAt(factor: number, anchor: Point): boolean {\n if (!this.scene || this.transition || !Number.isFinite(factor) || factor <= 0) {\n return false;\n }\n\n const [minimum, maximum] = this.zoomRange();\n const current = this.zoomLevel();\n const next = Math.min(maximum, Math.max(minimum, current * factor));\n\n if (Math.abs(next - current) < 1e-6) {\n return false;\n }\n\n this.camera = this.clampCamera(zoomAround(this.camera, this.viewport, next / current, anchor));\n this.hoveredId = null;\n this.tooltip.hide();\n this.clock.requestPaint();\n this.checkZoomNavigation(anchor);\n return true;\n }\n\n /** Zooming into a planet or moon enters it; zooming out of a view leaves it. */\n private checkZoomNavigation(anchor: Point): void {\n if (this.viewMode !== 'focus' || !this.scene || this.transition) {\n return;\n }\n\n const level = this.zoomLevel();\n\n if (level >= ENTER_ZOOM) {\n const body = this.bodyAt(anchor, ENTER_RADIUS);\n\n if (body) {\n this.navigate('focus', body.id);\n }\n\n return;\n }\n\n if (level <= EXIT_ZOOM) {\n const parent = this.focusPath[this.focusPath.length - 2];\n\n if (parent === undefined) {\n this.navigate('all', this.focusId);\n } else {\n this.navigate('focus', parent);\n }\n }\n }\n\n /** The planet or moon under `point` at least `minimumRadius` px on screen, preferring the smallest (most specific). */\n private bodyAt(point: Point, minimumRadius = 0): DisplayNode | null {\n const display = this.display;\n\n if (!display) {\n return null;\n }\n\n let best: DisplayNode | null = null;\n\n for (const entry of display.nodes.values()) {\n if (entry.role !== 'planet' && entry.role !== 'moon') {\n continue;\n }\n\n // The camera as it is now: a zoom checks this before the next frame paints.\n const center = worldToScreen(this.camera, this.viewport, entry);\n const radius = entry.radius * this.camera.scale;\n\n if (radius < minimumRadius) {\n continue;\n }\n\n if (Math.hypot(point.x - center.x, point.y - center.y) <= radius * 1.35 + 12 && (!best || entry.radius < best.radius)) {\n best = entry;\n }\n }\n\n return best;\n }\n\n /** After a pinch or wheel zoom: focus mode springs back from a partial zoom-out. */\n private settleZoom(): void {\n if (this.viewMode === 'focus' && this.scene && !this.transition && this.zoomLevel() < 0.999) {\n this.fit();\n }\n\n this.syncAmbientMotion();\n }\n\n private handleWheel(event: WheelEvent, point: Point): void {\n const setting = this.options.zoom?.wheel ?? 'auto';\n\n if (setting === false || !this.scene) {\n return;\n }\n\n const modifier = event.ctrlKey || event.metaKey;\n\n if (!modifier && (setting === 'modifier' || (setting === 'auto' && this.pageScrolls()))) {\n this.controls.showHint(this.words.text('scrollToZoom', { key: isApplePlatform() ? '⌘' : 'Ctrl' }));\n return;\n }\n\n event.preventDefault();\n\n if (this.transition) {\n return;\n }\n\n this.cameraFlight = null;\n this.glide.stop();\n const amount = Math.log(wheelZoomFactor(event, this.viewport.height));\n\n if (this.wheelZoom) {\n this.wheelZoom.remaining += amount;\n this.wheelZoom.anchor = point;\n } else {\n this.wheelZoom = { remaining: amount, anchor: point };\n this.clock.add(this.wheelTask);\n }\n }\n\n private readonly wheelTask: FrameTask = (_now, elapsed) => {\n const zoom = this.wheelZoom;\n\n if (!zoom || this.transition) {\n this.wheelZoom = null;\n return false;\n }\n\n if (elapsed <= 0) {\n // A duplicate timestamp: keep the banked zoom for the next frame.\n return 'hold';\n }\n\n const finished = Math.abs(zoom.remaining) < 0.002;\n const step = finished ? zoom.remaining : zoom.remaining * (1 - Math.exp(-elapsed / WHEEL_SMOOTHING));\n zoom.remaining -= step;\n\n if (!this.zoomAt(Math.exp(step), zoom.anchor)) {\n // At a limit: don't bank zoom the camera can't use.\n zoom.remaining = 0;\n }\n\n if (finished || zoom.remaining === 0) {\n this.wheelZoom = null;\n this.settleZoom();\n return false;\n }\n\n return true;\n };\n\n private handleDoubleTap(point: Point, target: EventTarget | null): void {\n if (!this.scene || this.transition || nodeIdFrom(target)) {\n return;\n }\n\n if (this.viewMode === 'all') {\n this.zoomStep(2, point);\n } else if (this.zoomLevel() > 1.04) {\n this.fit();\n }\n }\n\n /** An animated zoom step (buttons, keys, double taps). */\n private zoomStep(factor: number, anchor: Point): void {\n const scene = this.scene;\n\n if (!scene || this.transition || !(factor > 0)) {\n return;\n }\n\n const base = this.cameraFlight?.target ?? this.camera;\n const [minimum, maximum] = this.zoomRange();\n const current = base.scale / scene.frame.scale;\n const next = Math.min(maximum, Math.max(minimum, current * factor));\n this.flyCamera(this.clampCamera(zoomAround(base, this.viewport, next / current, anchor)), anchor);\n }\n\n private flyCamera(target: Camera, anchor: Point): void {\n if (!this.scene || this.transition) {\n return;\n }\n\n this.glide.stop();\n this.wheelZoom = null;\n\n if (!this.animationsEnabled()) {\n this.cameraFlight = null;\n this.camera = target;\n this.paint();\n this.afterCameraFlight(anchor);\n return;\n }\n\n const path = smoothZoomPath(this.camera, target, this.viewport);\n const duration = Math.min(650, Math.max(240, path.length * 520));\n this.cameraFlight = { path, target, anchor, startedAt: this.now(), duration };\n this.clock.add(this.cameraFlightTask);\n }\n\n private readonly cameraFlightTask: FrameTask = (now) => {\n const flight = this.cameraFlight;\n\n if (!flight || this.transition) {\n this.cameraFlight = null;\n return false;\n }\n\n const progress = Math.min(1, (now - flight.startedAt) / flight.duration);\n this.camera = progress >= 1 ? flight.target : flight.path.at(easeInOutCubic(progress));\n\n if (progress >= 1) {\n this.cameraFlight = null;\n this.afterCameraFlight(flight.anchor);\n return false;\n }\n\n return true;\n };\n\n private afterCameraFlight(anchor: Point): void {\n this.checkZoomNavigation(anchor);\n this.settleZoom();\n }\n\n /** Whether the page around the map scrolls; if so, a plain wheel scrolls the page instead of zooming. */\n private pageScrolls(): boolean {\n const now = this.now();\n\n if (this.pageScrollCheck && now - this.pageScrollCheck.time < 500) {\n return this.pageScrollCheck.scrolls;\n }\n\n const scrolls = scrollsAround(this.container);\n this.pageScrollCheck = { time: now, scrolls };\n return scrolls;\n }\n\n private updateEmbedding(): void {\n this.pageScrollCheck = null;\n this.root.classList.toggle('orbit--embedded', this.pageScrolls());\n }\n\n // Events\n\n private emitFocusChange(path: OrbitNode[]): void {\n const node = path[path.length - 1];\n this.options.onFocusChange?.(node);\n this.emit('focus-change', { node, path });\n }\n\n /**\n * Calls the `on()` listeners, then dispatches `orbit-<name>` on the\n * container. Returns false when a DOM listener cancelled the event.\n */\n private emit<Name extends OrbitEventName>(name: Name, detail: OrbitEventMap[Name], cancelable = false): boolean {\n for (const listener of Array.from(this.listeners.get(name) ?? [])) {\n try {\n (listener as (detail: OrbitEventMap[Name]) => void)(detail);\n } catch (error) {\n // A failing listener must not break the map; report it like a DOM listener would.\n reportListenerError(error);\n }\n }\n\n if (typeof CustomEvent !== 'function') {\n return true;\n }\n\n const event = new CustomEvent(`orbit-${name}`, { detail, bubbles: true, composed: true, cancelable });\n return this.container.dispatchEvent(event);\n }\n\n // Actions and the detail sheet\n\n /** Runs a button: one of Orbit's, or one of your actions, after `onAction` and the `action` event let it. */\n private runAction(node: OrbitNode, action: string, sourceEvent: MouseEvent | KeyboardEvent): void {\n if (!this.allowAction(node, action, sourceEvent)) {\n return;\n }\n\n if (action === 'link') {\n if (isNodeLink(node.link)) {\n const linked = this.findLinked(node.link);\n\n if (linked) {\n this.followNodeLink(linked);\n }\n\n return;\n }\n\n const url = node.link ? guardUrl(node.link, 'link') : null;\n\n if (url && typeof window !== 'undefined') {\n window.open(resolveUrl(url, this.options.baseUrl), '_blank', 'noopener');\n }\n\n return;\n }\n\n if (!CONTENT_ACTIONS.has(action)) {\n const custom = this.extensions.actions(node).find((candidate) => candidate.id === action);\n\n if (custom) {\n guarded(`The \"${custom.id}\" action's run()`, undefined, () => custom.run(node, sourceEvent));\n }\n\n return;\n }\n\n if ((action === 'image' || action === 'video') && this.options.mediaViewer !== false && this.viewer.open({ node, kind: action })) {\n return;\n }\n\n if (this.options.showDetailSheet !== false) {\n this.openDetails(node, action as DetailSection);\n }\n }\n\n /** Whether a button may do what it does: `onAction` didn't return `false` and no listener called the `action` event's `preventDefault()`. */\n private allowAction(node: OrbitNode, action: string, sourceEvent: MouseEvent | KeyboardEvent): boolean {\n if (this.options.onAction?.({ node, action, sourceEvent }) === false) {\n return false;\n }\n\n let prevented = false;\n const detail: OrbitActionDetail = {\n node,\n action,\n sourceEvent,\n preventDefault: () => {\n prevented = true;\n },\n get defaultPrevented() {\n return prevented;\n },\n };\n return this.emit('action', detail, true) && !prevented;\n }\n\n /**\n * A picture or video pressed in the detail sheet: a press of \"View image\"\n * or \"Play video\". The viewer opens over the sheet; a page that takes the\n * press gets the sheet closed, so what it opens is in front.\n */\n private viewFromSheet(node: OrbitNode, kind: MediaKind, sourceEvent: MouseEvent, startAt?: number): void {\n if (!this.allowAction(node, kind, sourceEvent)) {\n this.sheet.close();\n return;\n }\n\n this.viewer.open({ node, kind }, { startAt });\n }\n\n private openDetails(node: OrbitNode, section?: DetailSection): void {\n const path = this.tree ? getNodePath(this.tree, node.id).slice(0, -1) : [];\n this.sheet.open({\n node,\n path,\n siblings: node.parent?.children ?? [node],\n section,\n baseUrl: this.options.baseUrl,\n noteRenderer: this.options.noteRenderer,\n resolveLink: (href) => this.findLinked(href),\n onFollowLink: (linked) => this.followNodeLink(linked),\n onViewMedia: this.options.mediaViewer === false ? undefined : (shown, kind, event, startAt) => this.viewFromSheet(shown, kind, event, startAt),\n extensions: {\n icon: (shown) => this.extensions.icon(shown),\n typeLabel: (shown) => this.extensions.nodeType(shown)?.label,\n details: (shown) => {\n const details = this.extensions.nodeType(shown)?.details;\n return details ? (element) => guarded(`The \"${this.extensions.typeName(shown)}\" node type's details()`, undefined, () => details(shown, element)) : undefined;\n },\n actions: (shown) => this.extensions.actions(shown).map((action) => ({ id: action.id, label: actionLabel(action, shown), icon: action.icon })),\n runAction: (shown, action, event) => this.runAction(shown, action, event),\n status: (word) => this.extensions.status(word),\n },\n words: this.words,\n });\n }\n\n /** The media viewer opened, stepped, or closed: the drift rests behind it, and the page hears of it. */\n private mediaShown(name: 'media-open' | 'media-close', item: MediaItem, index: number, total: number): void {\n this.syncAmbientMotion();\n const event: OrbitMediaEvent = { node: item.node, kind: item.kind, index, total };\n\n if (name === 'media-open') {\n this.options.onMediaOpen?.(event);\n } else {\n this.options.onMediaClose?.(event);\n }\n\n this.emit(name, event);\n }\n\n private mediaPlayed(node: OrbitNode, playback: PlaybackState): void {\n const state: OrbitMediaState = { node, ...playback };\n this.options.onMediaState?.(state);\n this.emit('media-state', state);\n }\n\n /** The node a `#id` link points at, in this map. */\n private findLinked(href: string): OrbitNode | null {\n return this.tree ? findLinkedNode(this.tree, href) : null;\n }\n\n /** Where a node's link button goes: a page, or another node of the map (\"Go to Research\"). */\n private describeLink(node: OrbitNode): LinkDescription {\n if (!isNodeLink(node.link)) {\n return { kind: 'page' };\n }\n\n const linked = this.findLinked(node.link);\n return linked ? { kind: 'node', label: this.words.text('goTo', { name: linked.text || this.words.text('theIdea') }) } : { kind: 'missing' };\n }\n\n /** Flies to the node a `#id` link points at, from a link button, the detail sheet or a note. */\n private followNodeLink(linked: OrbitNode): void {\n if (this.sheet.isOpen) {\n this.sheet.close();\n }\n\n this.activeId = linked.id;\n this.returnFocusToMap = true;\n this.focusNode(linked.id);\n }\n\n // Environment\n\n private observeResize(): void {\n if (typeof ResizeObserver === 'undefined') {\n return;\n }\n\n this.resizeObserver = new ResizeObserver(() => {\n const size = this.readContainerSize();\n this.warnIfFlat(size);\n this.handleResize(size);\n });\n\n this.resizeObserver.observe(this.root);\n }\n\n /** Rests the drift while the map is scrolled out of sight, so a page of maps only moves the ones in view. */\n private observeVisibility(): void {\n if (typeof IntersectionObserver === 'undefined') {\n return;\n }\n\n this.visibilityObserver = new IntersectionObserver((entries) => {\n const latest = entries[entries.length - 1];\n\n if (latest) {\n this.onScreen = latest.isIntersecting;\n this.syncAmbientMotion();\n }\n });\n\n this.visibilityObserver.observe(this.root);\n }\n\n /** A map in a container without a height is invisible; say so once, in the console, where it gets noticed. */\n private warnIfFlat(size: Viewport): void {\n if (this.warnedFlat || size.width <= 0 || size.height >= 1 || !this.root.isConnected) {\n return;\n }\n\n this.warnedFlat = true;\n console.warn('[orbit] The map has no height, so nothing shows. It fills its container: give the container a height, for example style=\"height: 480px\".');\n }\n\n private handleResize(size: Viewport): void {\n if (Math.abs(size.width - this.viewport.width) < 0.5 && Math.abs(size.height - this.viewport.height) < 0.5) {\n return;\n }\n\n const hadScene = this.scene !== null;\n this.setViewport(size);\n this.updateEmbedding();\n\n if (!this.tree) {\n return;\n }\n\n if (!hadScene) {\n this.rebuild('enter');\n return;\n }\n\n // A container a little taller or shorter (a page's toolbar changing its text, say) keeps the\n // layout and whatever is moving: the view only re-centers.\n if (closeInSize(size, this.layoutSize)) {\n this.clock.requestPaint();\n return;\n }\n\n // A flight carries on; the view it lands on is laid out for the new size.\n if (this.transition) {\n this.relayoutOnArrival = true;\n this.clock.requestPaint();\n return;\n }\n\n this.rebuild('instant');\n }\n\n private setViewport(size: Viewport): void {\n this.viewport = size;\n this.root.classList.toggle('orbit--narrow', size.width <= NARROW_MAP);\n }\n\n private readContainerSize(): Viewport {\n const rectangle = this.root.getBoundingClientRect();\n return {\n width: rectangle.width || this.root.clientWidth || 0,\n height: rectangle.height || this.root.clientHeight || 0,\n };\n }\n\n /** Flights and camera moves animate unless reduced motion is on or `transitionDuration` is 0. */\n private animationsEnabled(): boolean {\n return this.options.transitionDuration !== 0 && !this.prefersReducedMotion();\n }\n\n private prefersReducedMotion(): boolean {\n if (this.reducedMotionQuery === undefined) {\n this.reducedMotionQuery = typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n ? window.matchMedia('(prefers-reduced-motion: reduce)')\n : null;\n }\n\n return this.reducedMotionQuery?.matches === true;\n }\n\n private now(): number {\n return typeof performance !== 'undefined' ? performance.now() : Date.now();\n }\n}\n"
|
|
71
|
+
],
|
|
72
|
+
"mappings": "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",
|
|
73
|
+
"debugId": "28A2939CA8E7F27664756E2164756E21",
|
|
74
|
+
"names": []
|
|
75
|
+
}
|