@kgdiff/viewer 0.4.0 → 0.6.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 (257) hide show
  1. package/README.md +43 -16
  2. package/custom-elements.json +2347 -0
  3. package/dist/bind.d.ts +41 -0
  4. package/dist/bind.d.ts.map +1 -0
  5. package/dist/bind.js +47 -0
  6. package/dist/bind.js.map +1 -0
  7. package/dist/context.d.ts +42 -0
  8. package/dist/context.d.ts.map +1 -0
  9. package/dist/context.js +87 -0
  10. package/dist/context.js.map +1 -0
  11. package/dist/controller.d.ts +26 -237
  12. package/dist/controller.d.ts.map +1 -1
  13. package/dist/controller.js +33 -1484
  14. package/dist/controller.js.map +1 -1
  15. package/dist/dom.d.ts +10 -0
  16. package/dist/dom.d.ts.map +1 -1
  17. package/dist/dom.js +29 -0
  18. package/dist/dom.js.map +1 -1
  19. package/dist/element.d.ts +51 -42
  20. package/dist/element.d.ts.map +1 -1
  21. package/dist/element.js +381 -602
  22. package/dist/element.js.map +1 -1
  23. package/dist/elements/actions.d.ts +27 -0
  24. package/dist/elements/actions.d.ts.map +1 -0
  25. package/dist/elements/actions.js +81 -0
  26. package/dist/elements/actions.js.map +1 -0
  27. package/dist/elements/bound.d.ts +63 -0
  28. package/dist/elements/bound.d.ts.map +1 -0
  29. package/dist/elements/bound.js +213 -0
  30. package/dist/elements/bound.js.map +1 -0
  31. package/dist/elements/change-detail.d.ts +25 -0
  32. package/dist/elements/change-detail.d.ts.map +1 -0
  33. package/dist/elements/change-detail.js +19 -0
  34. package/dist/elements/change-detail.js.map +1 -0
  35. package/dist/elements/change-list.d.ts +27 -0
  36. package/dist/elements/change-list.d.ts.map +1 -0
  37. package/dist/elements/change-list.js +29 -0
  38. package/dist/elements/change-list.js.map +1 -0
  39. package/dist/elements/filters.d.ts +25 -0
  40. package/dist/elements/filters.d.ts.map +1 -0
  41. package/dist/elements/filters.js +19 -0
  42. package/dist/elements/filters.js.map +1 -0
  43. package/dist/elements/legend.d.ts +40 -0
  44. package/dist/elements/legend.d.ts.map +1 -0
  45. package/dist/elements/legend.js +87 -0
  46. package/dist/elements/legend.js.map +1 -0
  47. package/dist/elements/minimap.d.ts +38 -0
  48. package/dist/elements/minimap.d.ts.map +1 -0
  49. package/dist/elements/minimap.js +59 -0
  50. package/dist/elements/minimap.js.map +1 -0
  51. package/dist/elements/root.d.ts +40 -0
  52. package/dist/elements/root.d.ts.map +1 -0
  53. package/dist/elements/root.js +67 -0
  54. package/dist/elements/root.js.map +1 -0
  55. package/dist/elements/search.d.ts +29 -0
  56. package/dist/elements/search.d.ts.map +1 -0
  57. package/dist/elements/search.js +23 -0
  58. package/dist/elements/search.js.map +1 -0
  59. package/dist/elements/stage-context.d.ts +31 -0
  60. package/dist/elements/stage-context.d.ts.map +1 -0
  61. package/dist/elements/stage-context.js +4 -0
  62. package/dist/elements/stage-context.js.map +1 -0
  63. package/dist/elements/stage.d.ts +65 -0
  64. package/dist/elements/stage.d.ts.map +1 -0
  65. package/dist/elements/stage.js +259 -0
  66. package/dist/elements/stage.js.map +1 -0
  67. package/dist/elements/title.d.ts +25 -0
  68. package/dist/elements/title.d.ts.map +1 -0
  69. package/dist/elements/title.js +19 -0
  70. package/dist/elements/title.js.map +1 -0
  71. package/dist/elements/transport.d.ts +29 -0
  72. package/dist/elements/transport.d.ts.map +1 -0
  73. package/dist/elements/transport.js +24 -0
  74. package/dist/elements/transport.js.map +1 -0
  75. package/dist/elements/view-bound.d.ts +39 -0
  76. package/dist/elements/view-bound.d.ts.map +1 -0
  77. package/dist/elements/view-bound.js +88 -0
  78. package/dist/elements/view-bound.js.map +1 -0
  79. package/dist/elements/view-dock.d.ts +28 -0
  80. package/dist/elements/view-dock.d.ts.map +1 -0
  81. package/dist/elements/view-dock.js +28 -0
  82. package/dist/elements/view-dock.js.map +1 -0
  83. package/dist/elements/zoom.d.ts +28 -0
  84. package/dist/elements/zoom.d.ts.map +1 -0
  85. package/dist/elements/zoom.js +22 -0
  86. package/dist/elements/zoom.js.map +1 -0
  87. package/dist/i18n.d.ts +10 -0
  88. package/dist/i18n.d.ts.map +1 -1
  89. package/dist/i18n.js +20 -0
  90. package/dist/i18n.js.map +1 -1
  91. package/dist/icons.d.ts +1 -0
  92. package/dist/icons.d.ts.map +1 -1
  93. package/dist/icons.js +1 -0
  94. package/dist/icons.js.map +1 -1
  95. package/dist/index.d.ts +331 -36
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +13 -0
  98. package/dist/index.js.map +1 -1
  99. package/dist/keyboard.d.ts +39 -2
  100. package/dist/keyboard.d.ts.map +1 -1
  101. package/dist/keyboard.js +145 -62
  102. package/dist/keyboard.js.map +1 -1
  103. package/dist/layout-store.d.ts +26 -0
  104. package/dist/layout-store.d.ts.map +1 -0
  105. package/dist/layout-store.js +46 -0
  106. package/dist/layout-store.js.map +1 -0
  107. package/dist/panel-levels.d.ts +18 -0
  108. package/dist/panel-levels.d.ts.map +1 -0
  109. package/dist/panel-levels.js +41 -0
  110. package/dist/panel-levels.js.map +1 -0
  111. package/dist/panels.d.ts +28 -0
  112. package/dist/panels.d.ts.map +1 -0
  113. package/dist/panels.js +73 -0
  114. package/dist/panels.js.map +1 -0
  115. package/dist/pipeline.d.ts.map +1 -1
  116. package/dist/pipeline.js +3 -2
  117. package/dist/pipeline.js.map +1 -1
  118. package/dist/prefs.d.ts +5 -2
  119. package/dist/prefs.d.ts.map +1 -1
  120. package/dist/prefs.js +12 -3
  121. package/dist/prefs.js.map +1 -1
  122. package/dist/react.d.ts +460 -0
  123. package/dist/react.d.ts.map +1 -0
  124. package/dist/react.js +2 -0
  125. package/dist/react.js.map +1 -0
  126. package/dist/root-element.d.ts +122 -0
  127. package/dist/root-element.d.ts.map +1 -0
  128. package/dist/root-element.js +541 -0
  129. package/dist/root-element.js.map +1 -0
  130. package/dist/root.d.ts +54 -0
  131. package/dist/root.d.ts.map +1 -0
  132. package/dist/root.js +288 -0
  133. package/dist/root.js.map +1 -0
  134. package/dist/schedule.d.ts +22 -0
  135. package/dist/schedule.d.ts.map +1 -0
  136. package/dist/schedule.js +41 -0
  137. package/dist/schedule.js.map +1 -0
  138. package/dist/session.d.ts +269 -0
  139. package/dist/session.d.ts.map +1 -0
  140. package/dist/session.js +1237 -0
  141. package/dist/session.js.map +1 -0
  142. package/dist/standalone/kgdiff-viewer-compute.js +1 -1
  143. package/dist/standalone/kgdiff-viewer.js +4 -4
  144. package/dist/styles.d.ts +17 -6
  145. package/dist/styles.d.ts.map +1 -1
  146. package/dist/styles.js +367 -258
  147. package/dist/styles.js.map +1 -1
  148. package/dist/theme.d.ts +32 -0
  149. package/dist/theme.d.ts.map +1 -0
  150. package/dist/theme.js +152 -0
  151. package/dist/theme.js.map +1 -0
  152. package/dist/topics.d.ts +8 -0
  153. package/dist/topics.d.ts.map +1 -0
  154. package/dist/topics.js +18 -0
  155. package/dist/topics.js.map +1 -0
  156. package/dist/ui/change-list.d.ts +18 -0
  157. package/dist/ui/change-list.d.ts.map +1 -0
  158. package/dist/ui/change-list.js +331 -0
  159. package/dist/ui/change-list.js.map +1 -0
  160. package/dist/ui/context.d.ts +34 -7
  161. package/dist/ui/context.d.ts.map +1 -1
  162. package/dist/ui/context.js.map +1 -1
  163. package/dist/ui/filters.d.ts +9 -0
  164. package/dist/ui/filters.d.ts.map +1 -0
  165. package/dist/ui/filters.js +68 -0
  166. package/dist/ui/filters.js.map +1 -0
  167. package/dist/ui/header.d.ts +41 -3
  168. package/dist/ui/header.d.ts.map +1 -1
  169. package/dist/ui/header.js +101 -36
  170. package/dist/ui/header.js.map +1 -1
  171. package/dist/ui/legend.d.ts +15 -0
  172. package/dist/ui/legend.d.ts.map +1 -0
  173. package/dist/ui/legend.js +68 -0
  174. package/dist/ui/legend.js.map +1 -0
  175. package/dist/ui/popovers.d.ts +3 -1
  176. package/dist/ui/popovers.d.ts.map +1 -1
  177. package/dist/ui/popovers.js +62 -23
  178. package/dist/ui/popovers.js.map +1 -1
  179. package/dist/ui/search.d.ts +13 -0
  180. package/dist/ui/search.d.ts.map +1 -0
  181. package/dist/ui/search.js +192 -0
  182. package/dist/ui/search.js.map +1 -0
  183. package/dist/ui/sidebar.d.ts +32 -17
  184. package/dist/ui/sidebar.d.ts.map +1 -1
  185. package/dist/ui/sidebar.js +327 -519
  186. package/dist/ui/sidebar.js.map +1 -1
  187. package/dist/ui/stage.d.ts +56 -1
  188. package/dist/ui/stage.d.ts.map +1 -1
  189. package/dist/ui/stage.js +244 -256
  190. package/dist/ui/stage.js.map +1 -1
  191. package/dist/ui/swatch.js +1 -1
  192. package/dist/ui/swatch.js.map +1 -1
  193. package/dist/ui/transport.d.ts +12 -0
  194. package/dist/ui/transport.d.ts.map +1 -0
  195. package/dist/ui/transport.js +198 -0
  196. package/dist/ui/transport.js.map +1 -0
  197. package/dist/ui/zoom.d.ts +15 -0
  198. package/dist/ui/zoom.d.ts.map +1 -0
  199. package/dist/ui/zoom.js +30 -0
  200. package/dist/ui/zoom.js.map +1 -0
  201. package/dist/view.d.ts +94 -0
  202. package/dist/view.d.ts.map +1 -0
  203. package/dist/view.js +441 -0
  204. package/dist/view.js.map +1 -0
  205. package/package.json +95 -12
  206. package/src/bind.ts +80 -0
  207. package/src/context.ts +106 -0
  208. package/src/controller.ts +52 -1630
  209. package/src/dom.ts +30 -0
  210. package/src/element.ts +386 -619
  211. package/src/elements/actions.ts +94 -0
  212. package/src/elements/bound.ts +247 -0
  213. package/src/elements/change-detail.ts +34 -0
  214. package/src/elements/change-list.ts +51 -0
  215. package/src/elements/filters.ts +34 -0
  216. package/src/elements/legend.ts +103 -0
  217. package/src/elements/minimap.ts +75 -0
  218. package/src/elements/root.ts +86 -0
  219. package/src/elements/search.ts +38 -0
  220. package/src/elements/stage-context.ts +34 -0
  221. package/src/elements/stage.ts +285 -0
  222. package/src/elements/title.ts +34 -0
  223. package/src/elements/transport.ts +39 -0
  224. package/src/elements/view-bound.ts +118 -0
  225. package/src/elements/view-dock.ts +43 -0
  226. package/src/elements/zoom.ts +38 -0
  227. package/src/i18n.ts +20 -0
  228. package/src/icons.ts +1 -0
  229. package/src/index.ts +350 -35
  230. package/src/keyboard.ts +188 -61
  231. package/src/layout-store.ts +71 -0
  232. package/src/panel-levels.ts +53 -0
  233. package/src/panels.ts +81 -0
  234. package/src/pipeline.ts +4 -1
  235. package/src/prefs.ts +12 -4
  236. package/src/react.ts +459 -0
  237. package/src/root-element.ts +624 -0
  238. package/src/root.ts +335 -0
  239. package/src/schedule.ts +43 -0
  240. package/src/session.ts +1375 -0
  241. package/src/styles.ts +396 -263
  242. package/src/theme.ts +170 -0
  243. package/src/topics.ts +37 -0
  244. package/src/ui/change-list.ts +405 -0
  245. package/src/ui/context.ts +36 -7
  246. package/src/ui/filters.ts +79 -0
  247. package/src/ui/header.ts +129 -58
  248. package/src/ui/legend.ts +112 -0
  249. package/src/ui/popovers.ts +68 -25
  250. package/src/ui/search.ts +225 -0
  251. package/src/ui/sidebar.ts +362 -639
  252. package/src/ui/stage.ts +267 -331
  253. package/src/ui/swatch.ts +1 -1
  254. package/src/ui/transport.ts +240 -0
  255. package/src/ui/zoom.ts +45 -0
  256. package/src/view.ts +516 -0
  257. package/vscode.html-custom-data.json +726 -0
@@ -0,0 +1,38 @@
1
+ /**
2
+ * `<kgdiff-zoom>` (RFC 0001 §3), documented on its class. Importing this module defines it.
3
+ */
4
+ import type { Region } from '../bind.js';
5
+ import type { KgdiffStageBoundElement } from '../index.js';
6
+ import type { UiContext } from '../ui/context.js';
7
+ import { ZoomBar } from '../ui/zoom.js';
8
+ import type { StageView } from '../view.js';
9
+ import { define } from './bound.js';
10
+ import { ViewBoundElement } from './view-bound.js';
11
+
12
+ /**
13
+ * Zoom in, zoom out and fit, for one stage's view (the `+` / `−` / `f` keys act on every stage of
14
+ * the root). Binds to the nearest `<kgdiff-stage>` around it, or to the one `stage="<id>"` names
15
+ * (`stage`, `stageElement`, `rootElement`). Slotted into a stage it replaces the stage's built-in
16
+ * zoom buttons; placed anywhere else it is not kept clear of fits and flights unless registered.
17
+ *
18
+ * @tagname kgdiff-zoom
19
+ * @experimental In 0.6; stable from 0.7 (RFC 0001, decision 7).
20
+ */
21
+ export class KgdiffZoom extends ViewBoundElement implements KgdiffStageBoundElement {
22
+ protected readonly name = 'zoom';
23
+
24
+ protected build(ui: UiContext, view: StageView): Region {
25
+ const zoom = new ZoomBar(ui, () => view);
26
+ this.shadow.append(zoom.el);
27
+ return zoom;
28
+ }
29
+ }
30
+
31
+ define('kgdiff-zoom', KgdiffZoom);
32
+
33
+ declare global {
34
+ interface HTMLElementTagNameMap {
35
+ /** @experimental In 0.6. */
36
+ 'kgdiff-zoom': KgdiffStageBoundElement;
37
+ }
38
+ }
package/src/i18n.ts CHANGED
@@ -67,6 +67,7 @@ const en = {
67
67
  'sidebar.search': 'Search nodes',
68
68
  'sidebar.searchPlaceholder': 'Search nodes…',
69
69
  'sidebar.searchClear': 'Clear search',
70
+ 'sidebar.searchResults': 'Matching nodes',
70
71
  'sidebar.noResults': 'No nodes match “{q}”',
71
72
  'sidebar.results.one': '{n} node',
72
73
  'sidebar.results.other': '{n} nodes',
@@ -76,12 +77,19 @@ const en = {
76
77
  'sidebar.noChanges': 'No changes to review.',
77
78
  'sidebar.sheet': 'Resize panel',
78
79
  'sidebar.sheetValue': '{p} of the height',
80
+ 'sidebar.resize': 'Resize the sidebar',
81
+ 'sidebar.split': 'Resize the change list and the details',
82
+ 'sidebar.splitValue': 'Change list {p} of the height',
83
+ 'sidebar.hideList': 'Collapse the change list',
84
+ 'sidebar.showList': 'Expand the change list',
79
85
  'review.progress': '{done} of {total} reviewed',
80
86
  'review.toggle': 'Reviewed',
81
87
  'review.mark': 'Mark as reviewed',
82
88
  'review.unmark': 'Mark as not reviewed',
83
89
  'review.complete': 'All changes reviewed',
84
90
  'detail.label': 'Change details',
91
+ 'detail.hide': 'Collapse the details',
92
+ 'detail.show': 'Expand the details',
85
93
  'detail.empty': 'Select a change to see what happened.',
86
94
  'detail.emptyHint': 'Use j / k to step through changes.',
87
95
  'detail.prev': 'Previous change',
@@ -152,6 +160,8 @@ const en = {
152
160
  'legend.title': 'Legend',
153
161
  'legend.toggle': 'Toggle legend',
154
162
  'minimap.label': 'Overview',
163
+ 'zoom.label': 'Zoom',
164
+ 'stage.label': 'Graph diff',
155
165
  'tooltip.relations.one': '{n} relation',
156
166
  'tooltip.relations.other': '{n} relations',
157
167
  'tooltip.select': 'Click to select',
@@ -256,6 +266,7 @@ const zhCN: Messages = {
256
266
  'sidebar.search': '搜索节点',
257
267
  'sidebar.searchPlaceholder': '搜索节点…',
258
268
  'sidebar.searchClear': '清除搜索',
269
+ 'sidebar.searchResults': '匹配的节点',
259
270
  'sidebar.noResults': '没有与「{q}」匹配的节点',
260
271
  'sidebar.results.one': '{n} 个节点',
261
272
  'sidebar.results.other': '{n} 个节点',
@@ -265,12 +276,19 @@ const zhCN: Messages = {
265
276
  'sidebar.noChanges': '没有需要审阅的变更。',
266
277
  'sidebar.sheet': '调整面板高度',
267
278
  'sidebar.sheetValue': '占高度的 {p}',
279
+ 'sidebar.resize': '调整侧栏宽度',
280
+ 'sidebar.split': '调整变更列表与详情的高度',
281
+ 'sidebar.splitValue': '变更列表占高度的 {p}',
282
+ 'sidebar.hideList': '收起变更列表',
283
+ 'sidebar.showList': '展开变更列表',
268
284
  'review.progress': '已审阅 {done} / {total}',
269
285
  'review.toggle': '已审阅',
270
286
  'review.mark': '标记为已审阅',
271
287
  'review.unmark': '标记为未审阅',
272
288
  'review.complete': '全部变更已审阅',
273
289
  'detail.label': '变更详情',
290
+ 'detail.hide': '收起详情',
291
+ 'detail.show': '展开详情',
274
292
  'detail.empty': '选择一项变更,查看具体发生了什么。',
275
293
  'detail.emptyHint': '按 j / k 逐项浏览变更。',
276
294
  'detail.prev': '上一项变更',
@@ -341,6 +359,8 @@ const zhCN: Messages = {
341
359
  'legend.title': '图例',
342
360
  'legend.toggle': '显示或隐藏图例',
343
361
  'minimap.label': '全局缩略图',
362
+ 'zoom.label': '缩放',
363
+ 'stage.label': '图谱差异',
344
364
  'tooltip.relations.one': '{n} 条关系',
345
365
  'tooltip.relations.other': '{n} 条关系',
346
366
  'tooltip.select': '点击选中',
package/src/icons.ts CHANGED
@@ -20,6 +20,7 @@ export const ICONS = {
20
20
  moon: '<path d="M13.25 9.6A5.5 5.5 0 0 1 6.4 2.75a5.5 5.5 0 1 0 6.85 6.85Z"/>',
21
21
  monitor:
22
22
  '<rect x="2" y="2.75" width="12" height="8.5" rx="1.5"/><path d="M5.5 13.75h5M8 11.25v2.5"/>',
23
+ filter: '<path d="M2.5 3.25h11L9.25 8.5v3.75l-2.5 1.25v-5Z"/>',
23
24
  search: '<circle cx="7.25" cy="7.25" r="4.5"/><path d="m10.6 10.6 3 3"/>',
24
25
  close: '<path d="m4.25 4.25 7.5 7.5M11.75 4.25l-7.5 7.5"/>',
25
26
  check: '<path d="m3.5 8.4 3 2.9 6-6.6"/>',
package/src/index.ts CHANGED
@@ -1,13 +1,19 @@
1
1
  /**
2
- * @kgdiff/viewer: the drop-in `<kgdiff-viewer>` web component.
2
+ * @kgdiff/viewer: the drop-in `<kgdiff-viewer>` web component, and the elements it is made of.
3
3
  *
4
- * Importing this module defines `<kgdiff-viewer>` (if not yet defined).
5
- * Behaviour: docs/interaction.md. Visuals: docs/visual-language.md.
4
+ * Importing this module defines `<kgdiff-viewer>` and the experimental elements
5
+ * `<kgdiff-root>`, `<kgdiff-stage>`, `<kgdiff-change-list>`, `<kgdiff-change-detail>`,
6
+ * `<kgdiff-search>` and `<kgdiff-filters>` (each not yet defined; each also has a subpath,
7
+ * `@kgdiff/viewer/elements/<name>`, that defines only it). Behaviour: docs/interaction.md.
8
+ * Visuals: docs/visual-language.md. Design: docs/rfcs/0001-viewer-components.md.
6
9
  *
7
- * Modules: `element.ts` (the custom element), `controller.ts` (state, load pipeline, replay
8
- * clock, camera follow), `ui/*` (header, sidebar, detail panel, canvas chrome, popovers),
9
- * `i18n.ts`, `styles.ts`, `review-store.ts`, `hash-sync.ts`, `payload.ts`, `text-diff.ts`,
10
- * `keyboard.ts`.
10
+ * Modules: `session.ts` (the headless diff session), `controller.ts` (its canvas view),
11
+ * `root.ts` / `root-element.ts` (the root: keyboard map, live region, events, tokens,
12
+ * preferences), `element.ts` (the default layout, with `panels.ts` and `layout-store.ts`),
13
+ * `elements/*` (the public elements), `ui/*` (the regions: stage, change list, search, filters,
14
+ * detail panel, header, sidebar, popovers), `context.ts` / `bind.ts` (how they find their root),
15
+ * `i18n.ts`, `styles.ts`, `theme.ts`, `review-store.ts`, `hash-sync.ts`, `payload.ts`,
16
+ * `text-diff.ts`, `keyboard.ts`.
11
17
  */
12
18
  import type {
13
19
  Delta,
@@ -17,11 +23,27 @@ import type {
17
23
  GraphInput,
18
24
  KGraph,
19
25
  Locale,
26
+ PackedDiffJSON,
20
27
  } from '@kgdiff/core';
21
28
  import type { ParseOptions } from '@kgdiff/formats';
22
29
  import type { LayoutJSON, LayoutOptions } from '@kgdiff/layout';
23
30
  import type { PaletteName } from '@kgdiff/scene';
24
31
  import { KgdiffViewer } from './element.js';
32
+ import type { Keymap } from './keyboard.js';
33
+ import type { ShortcutScope } from './root-element.js';
34
+ import './elements/root.js';
35
+ import './elements/stage.js';
36
+ import './elements/change-list.js';
37
+ import './elements/change-detail.js';
38
+ import './elements/search.js';
39
+ import './elements/filters.js';
40
+ import './elements/view-dock.js';
41
+ import './elements/transport.js';
42
+ import './elements/legend.js';
43
+ import './elements/zoom.js';
44
+ import './elements/minimap.js';
45
+ import './elements/title.js';
46
+ import './elements/actions.js';
25
47
  import { hydrate } from './payload.js';
26
48
  import { viewerTags } from './registry.js';
27
49
 
@@ -34,12 +56,82 @@ export type ThemePreference = 'auto' | 'light' | 'dark';
34
56
  export type ViewerChrome = 'full' | 'none';
35
57
  /** The legend card, one line of dots, no legend, or `auto` (the card, one line without chrome). */
36
58
  export type ViewerLegend = 'auto' | 'full' | 'mini' | 'none';
59
+ export type { Keymap, ShortcutName } from './keyboard.js';
60
+ export type { ShortcutScope } from './root-element.js';
61
+
62
+ /**
63
+ * A region of the default layout (`KgdiffViewerElement.panels`): the change list, the detail
64
+ * panel, the search, the family filters (the sidebar's four), the view dock, the replay
65
+ * transport, the legend, the zoom buttons, the minimap, the title and the actions.
66
+ */
67
+ export type PanelRegion =
68
+ | 'list'
69
+ | 'detail'
70
+ | 'search'
71
+ | 'filters'
72
+ | 'dock'
73
+ | 'transport'
74
+ | 'legend'
75
+ | 'zoom'
76
+ | 'minimap'
77
+ | 'title'
78
+ | 'actions';
79
+
80
+ /**
81
+ * `open`; `collapsed`: folded to the control that opens it again (the list to its title, the
82
+ * detail panel to its bar, the search to a button, the filters to a button, the legend to its
83
+ * head; the sidebar folds away when all four of its regions are collapsed) and inert; `hidden`:
84
+ * not shown, and no control brings it back. Regions without a fold of their own (dock,
85
+ * transport, zoom, minimap, title, actions) are not shown while collapsed.
86
+ */
87
+ export type PanelState = 'open' | 'collapsed' | 'hidden';
88
+
89
+ /** The state of every region. */
90
+ export type PanelStates = { readonly [R in PanelRegion]: PanelState };
91
+
92
+ /** The states of some regions; the others keep theirs. */
93
+ export type ViewerPanels = { readonly [R in PanelRegion]?: PanelState };
94
+
95
+ /**
96
+ * The version a `<kgdiff-stage>` draws whatever the mode (`version`): `before` or `after`, for
97
+ * side-by-side canvases of one session.
98
+ *
99
+ * @experimental Like the elements, in 0.6.
100
+ */
101
+ export type StageVersion = 'before' | 'after';
102
+
103
+ /**
104
+ * The regions of `<kgdiff-stage>`'s built-in chrome (its `panels`).
105
+ *
106
+ * @experimental Like the elements, in 0.6.
107
+ */
108
+ export type StageRegion = 'dock' | 'transport' | 'legend' | 'zoom' | 'minimap';
109
+
110
+ /**
111
+ * The states of some of the stage's chrome regions; the others keep theirs.
112
+ *
113
+ * @experimental Like the elements, in 0.6.
114
+ */
115
+ export type StagePanels = { readonly [R in StageRegion]?: PanelState };
116
+
117
+ /** The default layout's panel states and sizes (`kgdiff-layout`). */
118
+ export interface ViewerLayout {
119
+ readonly panels: PanelStates;
120
+ /** The sidebar's width, px (360 by default). */
121
+ readonly sidebarWidth: number;
122
+ /**
123
+ * The detail panel's share of the sidebar's height (0–1), once the user dragged the split
124
+ * between it and the change list; null while it takes its content's height (up to 58%).
125
+ */
126
+ readonly detailShare: number | null;
127
+ }
37
128
 
38
129
  /** A precomputed diff + layout: what the CLI embeds in HTML reports. Deterministic. */
39
130
  export interface ReportPayload {
40
131
  readonly format: 'kgdiff.report';
41
132
  readonly version: 1;
42
- readonly diff: DiffJSON;
133
+ /** The diff, packed (`packDiffJSON`, what the CLI writes) or not. */
134
+ readonly diff: DiffJSON | PackedDiffJSON;
43
135
  readonly layout: LayoutJSON;
44
136
  readonly meta: {
45
137
  readonly title?: string;
@@ -58,6 +150,11 @@ export interface ReportPayload {
58
150
  readonly theme?: ThemePreference;
59
151
  readonly palette?: PaletteName;
60
152
  readonly locale?: Locale;
153
+ /**
154
+ * Initial panel states of the default layout (`panels`). A choice the user made in the
155
+ * viewer before, or a `panels` attribute the page sets, wins over these.
156
+ */
157
+ readonly panels?: ViewerPanels;
61
158
  };
62
159
  }
63
160
 
@@ -82,21 +179,42 @@ export interface ReviewState {
82
179
  readonly total: number;
83
180
  }
84
181
 
85
- export interface KgdiffViewerEventMap {
182
+ /**
183
+ * The events of `<kgdiff-viewer>` and `<kgdiff-root>` (`CustomEvent`s that bubble and are
184
+ * composed). Merged into the global event maps, so `addEventListener('kgdiff-select', …)` on
185
+ * any element, the document or the window types `event.detail`.
186
+ */
187
+ export interface KgdiffEventMap {
188
+ /** A diff is shown, from `load()` or a `payload`; `stats` counts its nodes, edges and changes. */
86
189
  'kgdiff-ready': CustomEvent<{ readonly stats: DiffStats }>;
190
+ /**
191
+ * The selection changed: a change (`hunk`, its id, with the node chosen in it if any), a node
192
+ * alone (`hunk` null), or nothing (both null).
193
+ */
87
194
  'kgdiff-select': CustomEvent<{ readonly hunk: string | null; readonly node: string | null }>;
195
+ /** The mode or the scope changed, by the user, a key or the host. */
88
196
  'kgdiff-mode': CustomEvent<{ readonly mode: ViewerMode; readonly scope: ViewerScope }>;
197
+ /** A change was marked reviewed, or not; `progress` is the review state after it. */
89
198
  'kgdiff-review': CustomEvent<{
90
199
  readonly hunk: string;
91
200
  readonly reviewed: boolean;
92
201
  readonly progress: ReviewState;
93
202
  }>;
203
+ /** Loading or showing a diff failed; `error` is a `KgdiffError` for bad input. */
94
204
  'kgdiff-error': CustomEvent<{ readonly error: Error }>;
95
205
  /**
96
206
  * Playback reached the end of the replay (not fired for seeking or stepping there). `loop`:
97
207
  * it starts again after `loopDelay` ms; set `loop = false` or call `pause()` to stop it.
98
208
  */
99
209
  'kgdiff-replay-end': CustomEvent<{ readonly loop: boolean }>;
210
+ /**
211
+ * The default layout changed: a panel opened, collapsed or was hidden, or a size changed (once
212
+ * a drag ends). `source`: the user did it in the viewer, or the host (attributes, properties,
213
+ * a report's `view.panels`).
214
+ *
215
+ * @defaultLayout `<kgdiff-viewer>` fires it; `<kgdiff-root>` has no layout of its own.
216
+ */
217
+ 'kgdiff-layout': CustomEvent<ViewerLayout & { readonly source: 'user' | 'host' }>;
100
218
  }
101
219
 
102
220
  export interface FitOptions {
@@ -107,21 +225,15 @@ export interface FitOptions {
107
225
  }
108
226
 
109
227
  /**
110
- * Public surface of the `<kgdiff-viewer>` element.
228
+ * What `<kgdiff-viewer>` and `<kgdiff-root>` share: a root of a diff session, its preferences,
229
+ * methods and events (`KgdiffEventMap`, but `kgdiff-layout`).
111
230
  *
112
- * Boolean attributes: `sync-hash` (deep links `#kgdiff=hunk:<id>;mode:<mode>;scope:<scope>`) and
113
- * `global-shortcuts`: keyboard shortcuts normally apply only while focus is inside the viewer;
114
- * with this attribute they also apply when nothing on the page has focus (for full-page
115
- * viewers such as HTML reports), except the keys pages scroll with (arrows, Home / End, Page
116
- * Up / Down, Space).
117
- *
118
- * `header="compact"` leaves the brand and the compared names out of the canvas, for hosts that
119
- * show their own (such as the playground).
231
+ * Boolean attribute `sync-hash`: deep links `#kgdiff=hunk:<id>;mode:<mode>;scope:<scope>`.
120
232
  *
121
- * A small looping replay for another page: `mode="replay" chrome="none" loop` (with a height of
122
- * your choosing, such as 320px).
233
+ * `<kgdiff-viewer>` is stable; `<kgdiff-root>`, the element of this type on its own, is
234
+ * experimental in 0.6 (its tag name map entry says so).
123
235
  */
124
- export interface KgdiffViewerElement extends HTMLElement {
236
+ export interface KgdiffRootElement extends HTMLElement {
125
237
  /** Reflected to the `mode` attribute. Default `overlay`. */
126
238
  get mode(): ViewerMode;
127
239
  /** The legacy `changes` mode sets `overlay` + scope `changes`. */
@@ -137,20 +249,6 @@ export interface KgdiffViewerElement extends HTMLElement {
137
249
  palette: PaletteName;
138
250
  /** Reflected to the `locale` attribute. Default from `navigator.language`. */
139
251
  locale: Locale;
140
- /**
141
- * Reflected to the `chrome` attribute. `none` shows the graph alone: no title, actions, view
142
- * dock (with the step caption and playback bar), change list, zoom buttons, minimap or legend
143
- * card; the hover tooltip and a one-line legend stay. Clicks and keyboard shortcuts do nothing, the minimum height drops
144
- * from 420px to 120px, and the view stays fitted: when the canvas is resized (unless the user
145
- * panned or zoomed since) and at the start of every loop. Labels are never cut at the edge:
146
- * one pushed from its spot by a neighbour moves inside or is left out. Default `full`.
147
- */
148
- chrome: ViewerChrome;
149
- /**
150
- * Reflected to the `legend` attribute: `full` (the card), `mini` (one line: the families this
151
- * diff has, then unchanged), `none`. Default `auto`: `full`, or `mini` with `chrome="none"`.
152
- */
153
- legend: ViewerLegend;
154
252
  /**
155
253
  * Reflected to the boolean `loop` attribute. In `replay` mode the replay plays by itself and
156
254
  * starts again `loopDelay` ms after it ends. `pause()` stops it until `play()`. Default false.
@@ -169,16 +267,228 @@ export interface KgdiffViewerElement extends HTMLElement {
169
267
  load(options: LoadOptions): Promise<void>;
170
268
  /** Select a hunk by id (null clears) and bring it into view. */
171
269
  selectHunk(id: string | null): void;
270
+ /** Select the next change (`j`), in the list's order, and bring it into view. */
172
271
  next(): void;
272
+ /** Select the previous change (`k`). */
173
273
  prev(): void;
274
+ /** Play the replay (in `replay` mode), from where it is. */
174
275
  play(): void;
276
+ /** Pause the replay; a looping one stays paused until `play()`. */
175
277
  pause(): void;
176
278
  /** Fit the whole graph, labels included, into view. */
177
279
  fit(options?: FitOptions): Promise<void>;
178
280
  /** The full delta of the current diff. */
179
281
  exportDelta(): Delta;
282
+ /** Which changes are reviewed, and how many of all. */
180
283
  reviewState(): ReviewState;
284
+ /** Mark a change (by its id) reviewed or not; saved per diff, as the reader's `x` is. */
181
285
  setReviewed(hunkId: string, reviewed: boolean): void;
286
+ /**
287
+ * Reflected to the `shortcuts` attribute: where the keyboard shortcuts apply. `scoped` (the
288
+ * default): while focus is inside the root, or in an element bound to it with `for` (those
289
+ * forward their keys). `global`: also when nothing on the page has focus (for full-page
290
+ * viewers such as HTML reports), for the first such root, except the keys pages scroll with
291
+ * (arrows, Home / End, Page Up / Down, Space); the boolean `global-shortcuts` attribute is an
292
+ * alias. `none`: no shortcuts (a focused change list keeps its arrow keys, Home / End and
293
+ * Enter).
294
+ */
295
+ shortcuts: ShortcutScope;
296
+ /**
297
+ * Single keys of the keyboard map bound to another shortcut, or unbound with `null`:
298
+ * `{ x: null, r: 'review' }`. The `keymap` attribute takes the same as text,
299
+ * `"x:none r:review"` (`Space` names the space bar). Keys are `KeyboardEvent.key` values; a
300
+ * letter stands for both its cases unless the other case is named too; keys not named keep the
301
+ * default map; entries naming no shortcut are ignored with a warning.
302
+ *
303
+ * @experimental The shortcut names (`ShortcutName`) are new in 0.6.
304
+ */
305
+ get keymap(): Keymap | null;
306
+ set keymap(value: Keymap | string | null);
307
+ /**
308
+ * Draw the canvas with the `--kgdiff-*` tokens as computed now: after the page changed
309
+ * tokens in a way the root cannot observe (a class on an ancestor, a new stylesheet). Theme,
310
+ * palette and system color scheme changes are followed by themselves.
311
+ */
312
+ refreshTheme(): void;
313
+ }
314
+
315
+ /**
316
+ * The drop-in viewer: a root (`KgdiffRootElement`) with the default layout, the canvas with its
317
+ * chrome, the change list, the search, the filters and the detail panel.
318
+ *
319
+ * `header="compact"` leaves the brand and the compared names out of the canvas, for hosts that
320
+ * show their own (such as the playground): the preset `panels="title:hidden"`.
321
+ * `sidebar="closed"` starts with the sidebar folded (`\` and the sidebar button open it).
322
+ *
323
+ * A small looping replay for another page: `mode="replay" chrome="none" loop` (with a height of
324
+ * your choosing, such as 320px).
325
+ *
326
+ * The canvas has the slots of `<kgdiff-stage>` (`top-start`, `top-end`, `bottom-start`,
327
+ * `bottom-center`, `bottom-end`; the top ones under the title and the actions while those
328
+ * show): a child with `slot="top-end"` goes over the canvas, kept clear of fits and flights. A
329
+ * chrome element slotted in replaces the built-in region of its kind, the title and the
330
+ * actions included; `<kgdiff-zoom>` and `<kgdiff-minimap>` inside the viewer act on its canvas.
331
+ */
332
+ export interface KgdiffViewerElement extends KgdiffRootElement {
333
+ /**
334
+ * Reflected to the `chrome` attribute. `none` shows the graph alone: no title, actions, view
335
+ * dock (with the step caption and playback bar), change list, zoom buttons, minimap or legend
336
+ * card; the hover tooltip and a one-line legend stay. Clicks and keyboard shortcuts do nothing, the minimum height drops
337
+ * from 420px to 120px, and the view stays fitted: when the canvas is resized (unless the user
338
+ * panned or zoomed since) and at the start of every loop. Labels are never cut at the edge:
339
+ * one pushed from its spot by a neighbour moves inside or is left out. Default `full`.
340
+ */
341
+ chrome: ViewerChrome;
342
+ /**
343
+ * The page's declaration of panel states, reflected to the `panels` attribute: a string
344
+ * (`"detail:collapsed minimap:hidden"`) or an object (`{ detail: 'collapsed' }`); reading it
345
+ * gives the object. Regions not named keep their state; entries that name no region or
346
+ * state are ignored with a warning. It wins over what the user chose before (remembered) and
347
+ * a report's `view.panels`; the user can still open and close collapsed regions, and
348
+ * declaring the same again keeps what they did. The presets `sidebar="closed"` (list,
349
+ * detail, search and filters collapsed), `header="compact"` (title hidden) and
350
+ * `chrome="none"` (everything but the canvas and the legend hidden) are panel states too;
351
+ * `panels` wins over them for the regions it names. The states every region has now are in
352
+ * `layout`.
353
+ */
354
+ get panels(): ViewerPanels;
355
+ set panels(value: ViewerPanels | string | null);
356
+ /** Every region's state and the sizes now (what `kgdiff-layout` reports, without `source`). */
357
+ readonly layout: ViewerLayout;
358
+ /**
359
+ * Reflected to the `persist` attribute. `local` (the default): the layout remembers the
360
+ * user's panel states, sizes, theme, palette and language in `localStorage` (under
361
+ * `persistKey`, shared by the viewers of the origin with the same key). `none`: it remembers
362
+ * nothing.
363
+ */
364
+ persist: 'local' | 'none';
365
+ /**
366
+ * Reflected to the `persist-key` attribute: the `localStorage` key the layout remembers
367
+ * under. Viewers with the same key share what they remember; give each app on a shared origin
368
+ * (a GitHub Pages user site, say) a key of its own. Default `kgdiff:viewer`.
369
+ */
370
+ persistKey: string;
371
+ /**
372
+ * Reflected to the `legend` attribute: `full` (the card), `mini` (one line: the families this
373
+ * diff has, then unchanged), `none`. Default `auto`: `full`, or `mini` with `chrome="none"`.
374
+ */
375
+ legend: ViewerLegend;
376
+ }
377
+
378
+ /**
379
+ * An element bound to a root (experimental): `<kgdiff-stage>`, `<kgdiff-change-list>`,
380
+ * `<kgdiff-change-detail>`, `<kgdiff-search>`, `<kgdiff-filters>`. It shows the session of the
381
+ * nearest `<kgdiff-root>` or `<kgdiff-viewer>` around it (across shadow roots), or of the one
382
+ * named by its `for` attribute (an element id) anywhere on the page; a root defined or
383
+ * connected later is found then.
384
+ *
385
+ * @experimental The elements are experimental in 0.6: names, attributes and markup may change
386
+ * in a minor release before they are stable.
387
+ */
388
+ export interface KgdiffBoundElement extends HTMLElement {
389
+ /**
390
+ * Reflects the `for` attribute, as on `<label>` and `<output>`: the id of the root to show,
391
+ * or '' (no attribute; setting '' removes it) for the nearest one around the element.
392
+ * Changing it binds again.
393
+ */
394
+ htmlFor: string;
395
+ /** The root this element shows, or null while it waits for one (`for`'s element, resolved). */
396
+ readonly rootElement: KgdiffRootElement | null;
397
+ }
398
+
399
+ /**
400
+ * `<kgdiff-legend>`'s `variant`: `full` (the card of every family) or `mini` (one line).
401
+ *
402
+ * @experimental Like the elements, in 0.6.
403
+ */
404
+ export type LegendVariant = 'full' | 'mini';
405
+
406
+ /**
407
+ * `<kgdiff-legend>` (experimental): what the colors mean, bound to a root.
408
+ *
409
+ * @experimental The elements are experimental in 0.6: names, attributes and markup may change
410
+ * in a minor release before they are stable.
411
+ */
412
+ export interface KgdiffLegendElement extends KgdiffBoundElement {
413
+ /** Reflected to `variant`: `full` (default) or `mini`; another value reads `full`. */
414
+ variant: LegendVariant;
415
+ /** Reflected to the boolean `open`: whether the card is open (the user's toggle too). */
416
+ open: boolean;
417
+ }
418
+
419
+ /**
420
+ * An element that acts on one stage's view (experimental): `<kgdiff-zoom>`,
421
+ * `<kgdiff-minimap>`. It binds to the nearest `<kgdiff-stage>` around it, or to the one its
422
+ * `stage` attribute (an element id) names anywhere on the page.
423
+ *
424
+ * @experimental The elements are experimental in 0.6: names, attributes and markup may change
425
+ * in a minor release before they are stable.
426
+ */
427
+ export interface KgdiffStageBoundElement extends HTMLElement {
428
+ /**
429
+ * Reflects the `stage` attribute: the id of the stage to act on, or '' (no attribute;
430
+ * setting '' removes it) for the nearest one around the element. Changing it binds again.
431
+ */
432
+ stage: string;
433
+ /**
434
+ * The stage this element acts on, or null while it waits for one. Inside a `<kgdiff-viewer>`
435
+ * (or naming one) it is the viewer, whose built-in stage it acts on.
436
+ */
437
+ readonly stageElement: KgdiffStageElement | KgdiffViewerElement | null;
438
+ /** The root whose session the stage shows, or null while the element or the stage waits. */
439
+ readonly rootElement: KgdiffRootElement | null;
440
+ }
441
+
442
+ /**
443
+ * `<kgdiff-minimap>` (experimental): an overview of one stage's view.
444
+ *
445
+ * @experimental The elements are experimental in 0.6: names, attributes and markup may change
446
+ * in a minor release before they are stable.
447
+ */
448
+ export interface KgdiffMinimapElement extends KgdiffStageBoundElement {
449
+ /**
450
+ * Whether the whole graph is in view: the element is in the custom state `overview` then
451
+ * (`kgdiff-minimap:state(overview)`). Placed by the page it stays shown
452
+ * (`kgdiff-minimap:state(overview) { visibility: hidden }` hides it in place); slotted into a
453
+ * stage it replaces the stage's own minimap and hides as that one does.
454
+ */
455
+ readonly overview: boolean;
456
+ }
457
+
458
+ /**
459
+ * `<kgdiff-stage>` (experimental): the canvas, with five named slots for the page's content
460
+ * over it (`top-start`, `top-end`, `bottom-start`, `bottom-center`, `bottom-end`). Every
461
+ * slotted element is kept clear of fits and flights. A chrome element slotted in
462
+ * (`<kgdiff-view-dock>`, `<kgdiff-transport>`, `<kgdiff-legend>`, `<kgdiff-zoom>`,
463
+ * `<kgdiff-minimap>`) replaces the built-in region; `panels` keeps applying to the rest. Content
464
+ * placed anywhere else over the canvas is no obstacle unless registered (`registerObstacle`).
465
+ *
466
+ * @experimental The elements are experimental in 0.6: names, attributes and markup may change
467
+ * in a minor release before they are stable.
468
+ */
469
+ export interface KgdiffStageElement extends KgdiffBoundElement {
470
+ /**
471
+ * The states of the built-in chrome (`dock`, `transport`, `legend`, `zoom`, `minimap`),
472
+ * reflected to the `panels` attribute, in the syntax of `<kgdiff-viewer>`'s `panels`:
473
+ * `"minimap:hidden zoom:hidden"` or `{ minimap: 'hidden' }`; reading it gives the object.
474
+ * Other regions are ignored with a warning. Default: all open, the legend collapsed.
475
+ */
476
+ get panels(): StagePanels;
477
+ set panels(value: StagePanels | string | null);
478
+ /**
479
+ * Reflected to the `version` attribute: the version this stage draws whatever the root's
480
+ * mode, `before` or `after` (two stages of one root side by side), or null to follow the
481
+ * mode. Another value is ignored with a warning. Each stage has its own camera; the
482
+ * selection, hover, filters and search are the root's, so both bring the same change into
483
+ * view.
484
+ */
485
+ version: StageVersion | null;
486
+ /**
487
+ * Keep `element` (content over the canvas the stage does not place) clear of fits and
488
+ * flights; returns the function that stops it. Also on the stage context descendants can
489
+ * request (`Symbol.for('kgdiff.stage/1')`).
490
+ */
491
+ registerObstacle(element: Element): () => void;
182
492
  }
183
493
 
184
494
  /**
@@ -220,10 +530,15 @@ export function hydrateEmbeddedPayloads(root?: ParentNode): Promise<void> {
220
530
  return scope ? hydrate(scope) : Promise.resolve();
221
531
  }
222
532
 
533
+ /** @deprecated Use `KgdiffEventMap` (the same map, for the viewer and its elements). */
534
+ export type KgdiffViewerEventMap = KgdiffEventMap;
535
+
223
536
  declare global {
224
537
  interface HTMLElementTagNameMap {
225
538
  'kgdiff-viewer': KgdiffViewerElement;
226
539
  }
540
+ // The events bubble and are composed: elements, the document and the window all see them.
541
+ interface GlobalEventHandlersEventMap extends KgdiffEventMap {}
227
542
  }
228
543
 
229
544
  defineViewer();