@kgdiff/viewer 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +52 -2
  3. package/dist/compute-loader.d.ts +13 -0
  4. package/dist/compute-loader.d.ts.map +1 -0
  5. package/dist/compute-loader.js +46 -0
  6. package/dist/compute-loader.js.map +1 -0
  7. package/dist/compute.d.ts +8 -0
  8. package/dist/compute.d.ts.map +1 -0
  9. package/dist/compute.js +8 -0
  10. package/dist/compute.js.map +1 -0
  11. package/dist/controller.d.ts +199 -0
  12. package/dist/controller.d.ts.map +1 -0
  13. package/dist/controller.js +1254 -0
  14. package/dist/controller.js.map +1 -0
  15. package/dist/dom.d.ts +32 -0
  16. package/dist/dom.d.ts.map +1 -0
  17. package/dist/dom.js +105 -0
  18. package/dist/dom.js.map +1 -0
  19. package/dist/element.d.ts +43 -0
  20. package/dist/element.d.ts.map +1 -0
  21. package/dist/element.js +656 -0
  22. package/dist/element.js.map +1 -0
  23. package/dist/framing.d.ts +45 -0
  24. package/dist/framing.d.ts.map +1 -0
  25. package/dist/framing.js +107 -0
  26. package/dist/framing.js.map +1 -0
  27. package/dist/hash-sync.d.ts +18 -0
  28. package/dist/hash-sync.d.ts.map +1 -0
  29. package/dist/hash-sync.js +45 -0
  30. package/dist/hash-sync.js.map +1 -0
  31. package/dist/i18n.d.ts +222 -0
  32. package/dist/i18n.d.ts.map +1 -0
  33. package/dist/i18n.js +434 -0
  34. package/dist/i18n.js.map +1 -0
  35. package/dist/icons.d.ts +37 -0
  36. package/dist/icons.d.ts.map +1 -0
  37. package/dist/icons.js +36 -0
  38. package/dist/icons.js.map +1 -0
  39. package/dist/index.d.ts +151 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +41 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/keyboard.d.ts +64 -0
  44. package/dist/keyboard.d.ts.map +1 -0
  45. package/dist/keyboard.js +95 -0
  46. package/dist/keyboard.js.map +1 -0
  47. package/dist/list-model.d.ts +35 -0
  48. package/dist/list-model.d.ts.map +1 -0
  49. package/dist/list-model.js +70 -0
  50. package/dist/list-model.js.map +1 -0
  51. package/dist/payload.d.ts +10 -0
  52. package/dist/payload.d.ts.map +1 -0
  53. package/dist/payload.js +138 -0
  54. package/dist/payload.js.map +1 -0
  55. package/dist/pipeline.d.ts +31 -0
  56. package/dist/pipeline.d.ts.map +1 -0
  57. package/dist/pipeline.js +122 -0
  58. package/dist/pipeline.js.map +1 -0
  59. package/dist/prefs.d.ts +18 -0
  60. package/dist/prefs.d.ts.map +1 -0
  61. package/dist/prefs.js +38 -0
  62. package/dist/prefs.js.map +1 -0
  63. package/dist/registry.d.ts +3 -0
  64. package/dist/registry.d.ts.map +1 -0
  65. package/dist/registry.js +3 -0
  66. package/dist/registry.js.map +1 -0
  67. package/dist/renderer-port.d.ts +14 -0
  68. package/dist/renderer-port.d.ts.map +1 -0
  69. package/dist/renderer-port.js +16 -0
  70. package/dist/renderer-port.js.map +1 -0
  71. package/dist/replay.d.ts +55 -0
  72. package/dist/replay.d.ts.map +1 -0
  73. package/dist/replay.js +147 -0
  74. package/dist/replay.js.map +1 -0
  75. package/dist/review-store.d.ts +30 -0
  76. package/dist/review-store.d.ts.map +1 -0
  77. package/dist/review-store.js +120 -0
  78. package/dist/review-store.js.map +1 -0
  79. package/dist/search.d.ts +25 -0
  80. package/dist/search.d.ts.map +1 -0
  81. package/dist/search.js +90 -0
  82. package/dist/search.js.map +1 -0
  83. package/dist/standalone/kgdiff-viewer-compute.js +1 -0
  84. package/dist/standalone/kgdiff-viewer.js +5 -0
  85. package/dist/standalone-compute.d.ts +2 -0
  86. package/dist/standalone-compute.d.ts.map +1 -0
  87. package/dist/standalone-compute.js +8 -0
  88. package/dist/standalone-compute.js.map +1 -0
  89. package/dist/standalone.d.ts +2 -0
  90. package/dist/standalone.d.ts.map +1 -0
  91. package/dist/standalone.js +18 -0
  92. package/dist/standalone.js.map +1 -0
  93. package/dist/styles.d.ts +11 -0
  94. package/dist/styles.d.ts.map +1 -0
  95. package/dist/styles.js +622 -0
  96. package/dist/styles.js.map +1 -0
  97. package/dist/text-diff.d.ts +44 -0
  98. package/dist/text-diff.d.ts.map +1 -0
  99. package/dist/text-diff.js +261 -0
  100. package/dist/text-diff.js.map +1 -0
  101. package/dist/ui/context.d.ts +32 -0
  102. package/dist/ui/context.d.ts.map +1 -0
  103. package/dist/ui/context.js +49 -0
  104. package/dist/ui/context.js.map +1 -0
  105. package/dist/ui/detail.d.ts +9 -0
  106. package/dist/ui/detail.d.ts.map +1 -0
  107. package/dist/ui/detail.js +609 -0
  108. package/dist/ui/detail.js.map +1 -0
  109. package/dist/ui/header.d.ts +14 -0
  110. package/dist/ui/header.d.ts.map +1 -0
  111. package/dist/ui/header.js +195 -0
  112. package/dist/ui/header.js.map +1 -0
  113. package/dist/ui/popovers.d.ts +20 -0
  114. package/dist/ui/popovers.d.ts.map +1 -0
  115. package/dist/ui/popovers.js +180 -0
  116. package/dist/ui/popovers.js.map +1 -0
  117. package/dist/ui/sidebar.d.ts +25 -0
  118. package/dist/ui/sidebar.d.ts.map +1 -0
  119. package/dist/ui/sidebar.js +609 -0
  120. package/dist/ui/sidebar.js.map +1 -0
  121. package/dist/ui/stage.d.ts +18 -0
  122. package/dist/ui/stage.d.ts.map +1 -0
  123. package/dist/ui/stage.js +664 -0
  124. package/dist/ui/stage.js.map +1 -0
  125. package/package.json +58 -3
  126. package/src/compute-loader.ts +58 -0
  127. package/src/compute.ts +7 -0
  128. package/src/controller.ts +1393 -0
  129. package/src/dom.ts +131 -0
  130. package/src/element.ts +697 -0
  131. package/src/framing.ts +150 -0
  132. package/src/hash-sync.ts +54 -0
  133. package/src/i18n.ts +467 -0
  134. package/src/icons.ts +48 -0
  135. package/src/index.ts +171 -0
  136. package/src/keyboard.ts +128 -0
  137. package/src/list-model.ts +86 -0
  138. package/src/payload.ts +165 -0
  139. package/src/pipeline.ts +179 -0
  140. package/src/prefs.ts +55 -0
  141. package/src/registry.ts +2 -0
  142. package/src/renderer-port.ts +31 -0
  143. package/src/replay.ts +163 -0
  144. package/src/review-store.ts +125 -0
  145. package/src/search.ts +113 -0
  146. package/src/standalone-compute.ts +8 -0
  147. package/src/standalone.ts +18 -0
  148. package/src/styles.ts +633 -0
  149. package/src/text-diff.ts +263 -0
  150. package/src/ui/context.ts +70 -0
  151. package/src/ui/detail.ts +929 -0
  152. package/src/ui/header.ts +278 -0
  153. package/src/ui/popovers.ts +251 -0
  154. package/src/ui/sidebar.ts +752 -0
  155. package/src/ui/stage.ts +853 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 iiwish and kgdiff contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,53 @@
1
- # Temporary Holding Version
1
+ # @kgdiff/viewer
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ `<kgdiff-viewer>`, a framework-agnostic web component for reviewing graph diffs. Four views
4
+ (Overlay, Swipe, Replay and Changes only), a searchable change list, a detail panel with
5
+ character-level diffs, review progress, deep links, keyboard shortcuts, light and dark themes, and
6
+ an English and Chinese UI.
7
+
8
+ ## Install
9
+
10
+ ```sh
11
+ pnpm add @kgdiff/viewer
12
+ ```
13
+
14
+ ESM only. Runs in evergreen browsers.
15
+
16
+ ## Quick start
17
+
18
+ ```html
19
+ <kgdiff-viewer theme="auto" locale="en" style="height: 640px"></kgdiff-viewer>
20
+ <script type="module">
21
+ import '@kgdiff/viewer'; // defines <kgdiff-viewer>
22
+
23
+ const viewer = document.querySelector('kgdiff-viewer');
24
+ viewer.addEventListener('kgdiff-ready', (event) => console.log(event.detail.stats));
25
+ await viewer.load({
26
+ before: { text: await (await fetch('v1.ttl')).text(), filename: 'v1.ttl' },
27
+ after: { text: await (await fetch('v2.ttl')).text(), filename: 'v2.ttl' },
28
+ });
29
+ </script>
30
+ ```
31
+
32
+ - `load()` also takes structured graphs (`{ nodes, edges }`). The parsers, the diff engine and the
33
+ force layout are imported on demand, so they stay out of your initial bundle.
34
+ - To show a precomputed diff without any work in the browser, set `viewer.payload` to a report
35
+ payload: that is what the `kgdiff` CLI embeds in its HTML reports.
36
+ - Without a bundler, `@kgdiff/viewer/standalone` (`dist/standalone/kgdiff-viewer.js`) is a
37
+ self-contained script that defines the element and shows embedded payloads. The optional
38
+ `@kgdiff/viewer/standalone/compute` add-on brings the diff engine and force layout for `load()`.
39
+
40
+ Attributes: `mode` (`overlay` | `swipe` | `replay` | `changes`), `theme`, `palette`, `locale`,
41
+ `sidebar`, `sync-hash`, `global-shortcuts`. Methods: `load`, `selectHunk`, `next`, `prev`, `play`, `pause`,
42
+ `fit`, `exportDelta`, `reviewState`, `setReviewed`. Events: `kgdiff-ready`, `kgdiff-select`,
43
+ `kgdiff-mode`, `kgdiff-review`, `kgdiff-error`.
44
+
45
+ ## Learn more
46
+
47
+ - [Interaction](../../docs/interaction.md): views, change list, keyboard map and the
48
+ [embedding API](../../docs/interaction.md#embedding-api).
49
+ - [Visual language](../../docs/visual-language.md): what every color, ring and glyph means.
50
+
51
+ ## License
52
+
53
+ [MIT](../../LICENSE)
@@ -0,0 +1,13 @@
1
+ export type Compute = typeof import('./compute.js');
2
+ /** Global set by the standalone compute add-on. */
3
+ export declare const COMPUTE_GLOBAL = "KgdiffCompute";
4
+ /**
5
+ * The compute module once loaded (synchronously), else null. The global is read on every call,
6
+ * so an add-on that arrives after the viewer (inlined later, or loaded on demand) is picked up
7
+ * without a reload.
8
+ */
9
+ export declare function computeNow(): Compute | null;
10
+ /** `ready`: loaded; `unavailable`: the last attempt failed and no add-on is present; else `unknown`. */
11
+ export declare function computeStatus(): 'ready' | 'unavailable' | 'unknown';
12
+ export declare function loadCompute(): Promise<Compute>;
13
+ //# sourceMappingURL=compute-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute-loader.d.ts","sourceRoot":"","sources":["../src/compute-loader.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,OAAO,GAAG,cAAc,cAAc,CAAC,CAAC;AAEpD,mDAAmD;AACnD,eAAO,MAAM,cAAc,kBAAkB,CAAC;AAW9C;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,OAAO,GAAG,IAAI,CAG3C;AAED,wGAAwG;AACxG,wBAAgB,aAAa,IAAI,OAAO,GAAG,aAAa,GAAG,SAAS,CAGnE;AAED,wBAAgB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAoB9C"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Lazy access to `compute.ts`. The standalone bundle leaves it out: there it comes from the
3
+ * optional `kgdiff-viewer-compute.js` add-on (which sets `globalThis.KgdiffCompute`) or from an
4
+ * import map entry for `@kgdiff/viewer/compute`.
5
+ */
6
+ import { KgdiffError } from '@kgdiff/core';
7
+ /** Global set by the standalone compute add-on. */
8
+ export const COMPUTE_GLOBAL = 'KgdiffCompute';
9
+ let pending = null;
10
+ let ready = null;
11
+ let failed = false;
12
+ function fromGlobal() {
13
+ const g = globalThis[COMPUTE_GLOBAL];
14
+ return typeof g === 'object' && g !== null ? g : null;
15
+ }
16
+ /**
17
+ * The compute module once loaded (synchronously), else null. The global is read on every call,
18
+ * so an add-on that arrives after the viewer (inlined later, or loaded on demand) is picked up
19
+ * without a reload.
20
+ */
21
+ export function computeNow() {
22
+ ready ??= fromGlobal();
23
+ return ready;
24
+ }
25
+ /** `ready`: loaded; `unavailable`: the last attempt failed and no add-on is present; else `unknown`. */
26
+ export function computeStatus() {
27
+ if (computeNow())
28
+ return 'ready';
29
+ return failed ? 'unavailable' : 'unknown';
30
+ }
31
+ export function loadCompute() {
32
+ const now = computeNow();
33
+ if (now)
34
+ return Promise.resolve(now);
35
+ pending ??= import('./compute.js').then((m) => {
36
+ ready = m;
37
+ failed = false;
38
+ return m;
39
+ }, (error) => {
40
+ pending = null;
41
+ failed = true;
42
+ throw new KgdiffError('invalid-input', 'Diffing in the browser needs the compute module: import @kgdiff/viewer as a module, or add kgdiff-viewer-compute.js.', { cause: error instanceof Error ? error.message : String(error) });
43
+ });
44
+ return pending;
45
+ }
46
+ //# sourceMappingURL=compute-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute-loader.js","sourceRoot":"","sources":["../src/compute-loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAI3C,mDAAmD;AACnD,MAAM,CAAC,MAAM,cAAc,GAAG,eAAe,CAAC;AAE9C,IAAI,OAAO,GAA4B,IAAI,CAAC;AAC5C,IAAI,KAAK,GAAmB,IAAI,CAAC;AACjC,IAAI,MAAM,GAAG,KAAK,CAAC;AAEnB,SAAS,UAAU;IACjB,MAAM,CAAC,GAAI,UAAsC,CAAC,cAAc,CAAC,CAAC;IAClE,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAE,CAAa,CAAC,CAAC,CAAC,IAAI,CAAC;AACrE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU;IACxB,KAAK,KAAK,UAAU,EAAE,CAAC;IACvB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,aAAa;IAC3B,IAAI,UAAU,EAAE;QAAE,OAAO,OAAO,CAAC;IACjC,OAAO,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,IAAI,GAAG;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACrC,OAAO,KAAK,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CACrC,CAAC,CAAC,EAAE,EAAE;QACJ,KAAK,GAAG,CAAC,CAAC;QACV,MAAM,GAAG,KAAK,CAAC;QACf,OAAO,CAAC,CAAC;IACX,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;QACjB,OAAO,GAAG,IAAI,CAAC;QACf,MAAM,GAAG,IAAI,CAAC;QACd,MAAM,IAAI,WAAW,CACnB,eAAe,EACf,sHAAsH,EACtH,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAClE,CAAC;IACJ,CAAC,CACF,CAAC;IACF,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The CPU-heavy part of the pipeline, loaded on demand (`compute-loader.ts`): the diff engine
3
+ * and the force layout. Reports (precomputed payloads) never need it, which keeps the
4
+ * standalone bundle small; the ESM build gets it as a separate chunk.
5
+ */
6
+ export { diff } from '@kgdiff/core';
7
+ export { extendLayout, layoutDiff } from '@kgdiff/layout';
8
+ //# sourceMappingURL=compute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute.d.ts","sourceRoot":"","sources":["../src/compute.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The CPU-heavy part of the pipeline, loaded on demand (`compute-loader.ts`): the diff engine
3
+ * and the force layout. Reports (precomputed payloads) never need it, which keeps the
4
+ * standalone bundle small; the ESM build gets it as a separate chunk.
5
+ */
6
+ export { diff } from '@kgdiff/core';
7
+ export { extendLayout, layoutDiff } from '@kgdiff/layout';
8
+ //# sourceMappingURL=compute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute.js","sourceRoot":"","sources":["../src/compute.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Viewer state and orchestration, independent of the UI:
3
+ *
4
+ * - load pipeline with progress steps (sources or a precomputed report);
5
+ * - mode, selection (with an animated spotlight `emphasis`), family filters, review progress;
6
+ * - changes-only focus with expandable collapsed groups (`extendLayout` + scene rebuild);
7
+ * - replay clock driven by one requestAnimationFrame loop that sleeps when idle, with a camera
8
+ * that follows the playing hunk / chapter unless the user moved it in the last 2 s;
9
+ * - swipe position, hover, theme / palette / locale (rebuilding the scene when they change).
10
+ *
11
+ * The UI subscribes to topic notifications (batched per microtask) and reads public fields.
12
+ */
13
+ import type { DiffResult, DiffStats, Locale, Rect, UnionId } from '@kgdiff/core';
14
+ import type { LayoutResult } from '@kgdiff/layout';
15
+ import type { Camera } from '@kgdiff/renderer';
16
+ import { type ChangeFamily, type FocusState, type PaletteName, type Scene, type Theme, type ThemeName, type VisualResolver } from '@kgdiff/scene';
17
+ import { type ChromeLayout } from './framing.js';
18
+ import type { LoadOptions, ReportPayload, ReviewState, ThemePreference, ViewerMode } from './index.js';
19
+ import { type ListModel } from './list-model.js';
20
+ import { type LoadedDiff, type LoadStep } from './pipeline.js';
21
+ import { ReplayClock } from './replay.js';
22
+ import { type StorageLike } from './review-store.js';
23
+ import { type SearchHit } from './search.js';
24
+ export type Status = 'idle' | 'loading' | 'ready' | 'error';
25
+ export type Topic = 'status' | 'data' | 'mode' | 'selection' | 'filters' | 'review' | 'replay' | 'hover' | 'theme' | 'locale' | 'focus' | 'swipe';
26
+ export interface ControllerHost {
27
+ ready(stats: DiffStats): void;
28
+ select(hunk: string | null, node: string | null): void;
29
+ mode(mode: ViewerMode): void;
30
+ review(hunk: string, reviewed: boolean, progress: ReviewState): void;
31
+ error(error: Error): void;
32
+ announce(text: string): void;
33
+ }
34
+ export interface ControllerDeps {
35
+ readonly now: () => number;
36
+ readonly requestFrame: (cb: (time: number) => void) => number;
37
+ readonly cancelFrame: (id: number) => void;
38
+ /** Resolves once the browser had a chance to paint (between loading steps). */
39
+ readonly yieldToPaint: () => Promise<void>;
40
+ readonly storage: StorageLike | null;
41
+ }
42
+ export type Preference = 'mode' | 'theme' | 'palette' | 'locale';
43
+ /** Camera follow is suppressed this long after the user moved the camera (ms). */
44
+ export declare const USER_CAMERA_GRACE = 2000;
45
+ /** The camera follows when less than this share of the target bounds is in view. */
46
+ export declare const FOLLOW_COVERAGE = 0.7;
47
+ /** Flights to a change never zoom in further, so its neighbourhood stays readable. */
48
+ export declare const FLY_MAX_ZOOM = 1.8;
49
+ /** Fitting everything never zooms in further (the renderer's default). */
50
+ export declare const FIT_MAX_ZOOM = 2.5;
51
+ /** Share of `bounds` inside `view`, in [0, 1]. */
52
+ export declare function coverage(bounds: Rect, view: Rect): number;
53
+ export declare class ViewerController {
54
+ #private;
55
+ status: Status;
56
+ /** Steps of the current load, in order; `step` is the running one. */
57
+ steps: LoadStep[];
58
+ step: LoadStep | null;
59
+ error: Error | null;
60
+ data: LoadedDiff | null;
61
+ layout: LayoutResult | null;
62
+ scene: Scene | null;
63
+ resolver: VisualResolver | null;
64
+ list: ListModel;
65
+ mode: ViewerMode;
66
+ themePreference: ThemePreference;
67
+ palette: PaletteName;
68
+ locale: Locale;
69
+ systemDark: boolean;
70
+ reducedMotion: boolean;
71
+ /** Preferences set explicitly by the embedder (a report's `view` does not override them). */
72
+ readonly explicit: Set<Preference>;
73
+ selectedHunk: number;
74
+ selectedNode: number;
75
+ /** An edge emphasized from the detail panel (drawn as hovered). */
76
+ pinnedEdge: number;
77
+ hoverNode: number;
78
+ hoverEdge: number;
79
+ hoverGroup: number;
80
+ readonly families: Set<ChangeFamily>;
81
+ hops: number;
82
+ readonly expanded: Set<string>;
83
+ focus: FocusState | null;
84
+ clock: ReplayClock | null;
85
+ split: number;
86
+ emphasis: number;
87
+ constructor(host: ControllerHost, deps: ControllerDeps);
88
+ subscribe(listener: (topics: ReadonlySet<Topic>) => void): () => void;
89
+ /** Deliver pending notifications now (also used by tests). */
90
+ flush(): void;
91
+ get themeName(): ThemeName;
92
+ get theme(): Theme;
93
+ get diff(): DiffResult | null;
94
+ get hunkCount(): number;
95
+ isReviewed(hunkId: string): boolean;
96
+ reviewState(): ReviewState;
97
+ search(query: string, limit?: number): SearchHit[];
98
+ load(options: LoadOptions): Promise<void>;
99
+ loadPayload(payload: ReportPayload): Promise<void>;
100
+ /** Show an error state (bad payload, failed load). */
101
+ fail(error: Error): void;
102
+ attach(stage: HTMLElement, minimapHost: HTMLElement | null): void;
103
+ detach(): void;
104
+ destroy(): void;
105
+ get camera(): Camera | null;
106
+ /**
107
+ * Where floating chrome covers the canvas (measured by the element at fit / flight time).
108
+ * Every fit and flight frames its target in the free part of the canvas (`framing.ts`).
109
+ */
110
+ setChrome(provider: (() => ChromeLayout) | null): void;
111
+ /** The canvas was laid out or resized: run the initial fit a new diff is waiting for. */
112
+ layoutChanged(): void;
113
+ /** The user panned / zoomed: suspend replay camera follow for `USER_CAMERA_GRACE`. */
114
+ noteUserCamera(): void;
115
+ /** Redraw on the next animation frame. */
116
+ invalidate(): void;
117
+ /** Resolve the current view and hand it to the renderer (and the minimap). */
118
+ draw(now?: number): void;
119
+ setMode(value: ViewerMode): void;
120
+ selectHunkById(id: string | null, options?: {
121
+ fly?: boolean;
122
+ }): void;
123
+ /**
124
+ * Select hunk `h` (scene index; -1 clears). `node` focuses one of its nodes in the detail
125
+ * panel. `fly` (default true) brings it into view. In replay, seeks to the end of its window.
126
+ */
127
+ selectHunk(h: number, options?: {
128
+ fly?: boolean;
129
+ node?: number;
130
+ }): void;
131
+ /** Select a node: its hunk when it has one, else the node itself. */
132
+ selectNode(i: number, options?: {
133
+ fly?: boolean;
134
+ }): void;
135
+ clearSelection(): void;
136
+ next(): void;
137
+ prev(): void;
138
+ first(): void;
139
+ last(): void;
140
+ /** Emphasize an edge (from the detail panel) and fly to it. */
141
+ pinEdge(j: number): void;
142
+ flyToHunk(h: number): void;
143
+ flyToNode(i: number): void;
144
+ flyToSelection(): void;
145
+ /**
146
+ * Fit everything visible (the focus in changes-only mode) into the free part of the canvas.
147
+ * Before the canvas is laid out it falls back to the renderer's own fit.
148
+ */
149
+ fit(options?: {
150
+ readonly animate?: boolean;
151
+ }): Promise<void>;
152
+ zoom(direction: 1 | -1): void;
153
+ /** Clear hover state (pointer left the canvas). */
154
+ clearHover(): void;
155
+ toggleFamily(family: ChangeFamily): void;
156
+ /** Replace the family filter (empty = all). Setting the current set again clears it. */
157
+ setFamilies(families: readonly ChangeFamily[]): void;
158
+ setHops(hops: number): void;
159
+ /**
160
+ * Expand collapsed group `index` of the current focus: its in-scene members become visible
161
+ * and, for a `changes`-scoped layout, the neighbours left out of the layout are placed with
162
+ * `extendLayout` (nothing already placed moves) and the scene is rebuilt.
163
+ */
164
+ expandGroup(index: number): void;
165
+ /**
166
+ * The collapsed group nearest the selection (else the view center), or -1. Groups that can
167
+ * be expanded at least partly come first.
168
+ */
169
+ nearestGroup(): number;
170
+ /** Expand the group nearest the selection (keyboard `e`); announces what happened. */
171
+ expandNearest(): void;
172
+ /**
173
+ * Whether collapsed group `index` can be expanded completely: always, unless some members lie
174
+ * outside a `changes`-scoped layout and the layout engine is known to be unavailable
175
+ * (standalone report without the compute add-on).
176
+ */
177
+ canExpand(index: number): boolean;
178
+ /** Bring a union node into the scene and the focus (search results), then select it. */
179
+ revealNode(id: UnionId): Promise<void>;
180
+ play(): void;
181
+ pause(): void;
182
+ togglePlay(): void;
183
+ seek(t: number): void;
184
+ stepReplay(direction: 1 | -1): void;
185
+ restart(): void;
186
+ cycleSpeed(): void;
187
+ setSpeed(speed: number): void;
188
+ setSplit(split: number): void;
189
+ setReviewed(hunkId: string, reviewed: boolean): void;
190
+ /** Another tab changed review progress (`storage` event): re-read it. */
191
+ syncReview(key: string | null): void;
192
+ toggleReviewed(hunkId?: string): void;
193
+ setThemePreference(pref: ThemePreference): void;
194
+ setPalette(palette: PaletteName): void;
195
+ setLocale(locale: Locale): void;
196
+ setSystemDark(dark: boolean): void;
197
+ setReducedMotion(reduced: boolean): void;
198
+ }
199
+ //# sourceMappingURL=controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"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"}