@kgdiff/viewer 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +52 -2
- package/dist/compute-loader.d.ts +13 -0
- package/dist/compute-loader.d.ts.map +1 -0
- package/dist/compute-loader.js +46 -0
- package/dist/compute-loader.js.map +1 -0
- package/dist/compute.d.ts +8 -0
- package/dist/compute.d.ts.map +1 -0
- package/dist/compute.js +8 -0
- package/dist/compute.js.map +1 -0
- package/dist/controller.d.ts +199 -0
- package/dist/controller.d.ts.map +1 -0
- package/dist/controller.js +1254 -0
- package/dist/controller.js.map +1 -0
- package/dist/dom.d.ts +32 -0
- package/dist/dom.d.ts.map +1 -0
- package/dist/dom.js +105 -0
- package/dist/dom.js.map +1 -0
- package/dist/element.d.ts +43 -0
- package/dist/element.d.ts.map +1 -0
- package/dist/element.js +656 -0
- package/dist/element.js.map +1 -0
- package/dist/framing.d.ts +45 -0
- package/dist/framing.d.ts.map +1 -0
- package/dist/framing.js +107 -0
- package/dist/framing.js.map +1 -0
- package/dist/hash-sync.d.ts +18 -0
- package/dist/hash-sync.d.ts.map +1 -0
- package/dist/hash-sync.js +45 -0
- package/dist/hash-sync.js.map +1 -0
- package/dist/i18n.d.ts +223 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +436 -0
- package/dist/i18n.js.map +1 -0
- package/dist/icons.d.ts +37 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +36 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +151 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/keyboard.d.ts +64 -0
- package/dist/keyboard.d.ts.map +1 -0
- package/dist/keyboard.js +95 -0
- package/dist/keyboard.js.map +1 -0
- package/dist/list-model.d.ts +35 -0
- package/dist/list-model.d.ts.map +1 -0
- package/dist/list-model.js +70 -0
- package/dist/list-model.js.map +1 -0
- package/dist/payload.d.ts +10 -0
- package/dist/payload.d.ts.map +1 -0
- package/dist/payload.js +138 -0
- package/dist/payload.js.map +1 -0
- package/dist/pipeline.d.ts +31 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +122 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/prefs.d.ts +18 -0
- package/dist/prefs.d.ts.map +1 -0
- package/dist/prefs.js +38 -0
- package/dist/prefs.js.map +1 -0
- package/dist/registry.d.ts +3 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +3 -0
- package/dist/registry.js.map +1 -0
- package/dist/renderer-port.d.ts +14 -0
- package/dist/renderer-port.d.ts.map +1 -0
- package/dist/renderer-port.js +16 -0
- package/dist/renderer-port.js.map +1 -0
- package/dist/replay.d.ts +55 -0
- package/dist/replay.d.ts.map +1 -0
- package/dist/replay.js +147 -0
- package/dist/replay.js.map +1 -0
- package/dist/review-store.d.ts +30 -0
- package/dist/review-store.d.ts.map +1 -0
- package/dist/review-store.js +120 -0
- package/dist/review-store.js.map +1 -0
- package/dist/search.d.ts +25 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +90 -0
- package/dist/search.js.map +1 -0
- package/dist/standalone/kgdiff-viewer-compute.js +1 -0
- package/dist/standalone/kgdiff-viewer.js +5 -0
- package/dist/standalone-compute.d.ts +2 -0
- package/dist/standalone-compute.d.ts.map +1 -0
- package/dist/standalone-compute.js +8 -0
- package/dist/standalone-compute.js.map +1 -0
- package/dist/standalone.d.ts +2 -0
- package/dist/standalone.d.ts.map +1 -0
- package/dist/standalone.js +18 -0
- package/dist/standalone.js.map +1 -0
- package/dist/styles.d.ts +11 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +627 -0
- package/dist/styles.js.map +1 -0
- package/dist/text-diff.d.ts +32 -0
- package/dist/text-diff.d.ts.map +1 -0
- package/dist/text-diff.js +211 -0
- package/dist/text-diff.js.map +1 -0
- package/dist/ui/context.d.ts +32 -0
- package/dist/ui/context.d.ts.map +1 -0
- package/dist/ui/context.js +49 -0
- package/dist/ui/context.js.map +1 -0
- package/dist/ui/detail.d.ts +9 -0
- package/dist/ui/detail.d.ts.map +1 -0
- package/dist/ui/detail.js +566 -0
- package/dist/ui/detail.js.map +1 -0
- package/dist/ui/header.d.ts +14 -0
- package/dist/ui/header.d.ts.map +1 -0
- package/dist/ui/header.js +195 -0
- package/dist/ui/header.js.map +1 -0
- package/dist/ui/popovers.d.ts +20 -0
- package/dist/ui/popovers.d.ts.map +1 -0
- package/dist/ui/popovers.js +180 -0
- package/dist/ui/popovers.js.map +1 -0
- package/dist/ui/sidebar.d.ts +25 -0
- package/dist/ui/sidebar.d.ts.map +1 -0
- package/dist/ui/sidebar.js +609 -0
- package/dist/ui/sidebar.js.map +1 -0
- package/dist/ui/stage.d.ts +18 -0
- package/dist/ui/stage.d.ts.map +1 -0
- package/dist/ui/stage.js +664 -0
- package/dist/ui/stage.js.map +1 -0
- package/package.json +58 -3
- package/src/compute-loader.ts +58 -0
- package/src/compute.ts +7 -0
- package/src/controller.ts +1393 -0
- package/src/dom.ts +131 -0
- package/src/element.ts +697 -0
- package/src/framing.ts +150 -0
- package/src/hash-sync.ts +54 -0
- package/src/i18n.ts +469 -0
- package/src/icons.ts +48 -0
- package/src/index.ts +171 -0
- package/src/keyboard.ts +128 -0
- package/src/list-model.ts +86 -0
- package/src/payload.ts +165 -0
- package/src/pipeline.ts +179 -0
- package/src/prefs.ts +55 -0
- package/src/registry.ts +2 -0
- package/src/renderer-port.ts +31 -0
- package/src/replay.ts +163 -0
- package/src/review-store.ts +125 -0
- package/src/search.ts +113 -0
- package/src/standalone-compute.ts +8 -0
- package/src/standalone.ts +18 -0
- package/src/styles.ts +638 -0
- package/src/text-diff.ts +208 -0
- package/src/ui/context.ts +70 -0
- package/src/ui/detail.ts +921 -0
- package/src/ui/header.ts +278 -0
- package/src/ui/popovers.ts +251 -0
- package/src/ui/sidebar.ts +752 -0
- package/src/ui/stage.ts +853 -0
package/src/dom.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A tiny DOM helper: `h(tag, props, ...children)`. Text is always set as text (never HTML);
|
|
3
|
+
* only the static icon markup in `icons.ts` goes through `innerHTML`.
|
|
4
|
+
*/
|
|
5
|
+
import { ICONS, type IconName } from './icons.js';
|
|
6
|
+
|
|
7
|
+
type Child = Node | string | number | null | undefined | false | readonly Child[];
|
|
8
|
+
|
|
9
|
+
type Handler = (event: Event) => void;
|
|
10
|
+
|
|
11
|
+
export interface Props {
|
|
12
|
+
readonly class?: string;
|
|
13
|
+
readonly style?: string;
|
|
14
|
+
readonly text?: string;
|
|
15
|
+
readonly [attr: string]: string | number | boolean | null | undefined | Handler;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function append(parent: Node, child: Child): void {
|
|
19
|
+
if (child === null || child === undefined || child === false) return;
|
|
20
|
+
if (Array.isArray(child)) {
|
|
21
|
+
for (const c of child as readonly Child[]) append(parent, c);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
parent.appendChild(
|
|
25
|
+
typeof child === 'string' || typeof child === 'number'
|
|
26
|
+
? document.createTextNode(String(child))
|
|
27
|
+
: (child as Node),
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function h<K extends keyof HTMLElementTagNameMap>(
|
|
32
|
+
tag: K,
|
|
33
|
+
props?: Props | null,
|
|
34
|
+
...children: Child[]
|
|
35
|
+
): HTMLElementTagNameMap[K] {
|
|
36
|
+
const el = document.createElement(tag);
|
|
37
|
+
if (props) {
|
|
38
|
+
for (const [key, value] of Object.entries(props)) {
|
|
39
|
+
if (value === undefined || value === null || value === false) continue;
|
|
40
|
+
if (key === 'text') el.textContent = String(value);
|
|
41
|
+
else if (key.startsWith('on') && typeof value === 'function') {
|
|
42
|
+
el.addEventListener(key.slice(2), value as EventListener);
|
|
43
|
+
} else if (key === 'class') el.className = String(value);
|
|
44
|
+
else el.setAttribute(key, value === true ? '' : String(value));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
for (const c of children) append(el, c);
|
|
48
|
+
return el;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Replace all children of `el`. */
|
|
52
|
+
export function replace(el: Element, ...children: Child[]): void {
|
|
53
|
+
el.textContent = '';
|
|
54
|
+
for (const c of children) append(el, c);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Replace the children of `el` without losing keyboard focus: if focus was inside `el`, it moves
|
|
59
|
+
* to the new element with the same `data-focus-key`, else to `fallback` (never to `<body>`).
|
|
60
|
+
*/
|
|
61
|
+
export function replaceKeepingFocus(
|
|
62
|
+
root: DocumentOrShadowRoot,
|
|
63
|
+
el: Element,
|
|
64
|
+
fallback: HTMLElement | null,
|
|
65
|
+
...children: Child[]
|
|
66
|
+
): void {
|
|
67
|
+
const active = root.activeElement as HTMLElement | null;
|
|
68
|
+
const inside = active !== null && el.contains(active);
|
|
69
|
+
const key = inside ? (active.dataset.focusKey ?? '') : '';
|
|
70
|
+
replace(el, ...children);
|
|
71
|
+
if (!inside) return;
|
|
72
|
+
let next: HTMLElement | null = null;
|
|
73
|
+
if (key) {
|
|
74
|
+
for (const c of el.querySelectorAll<HTMLElement>('[data-focus-key]')) {
|
|
75
|
+
if (c.dataset.focusKey === key && !(c as HTMLButtonElement).disabled) {
|
|
76
|
+
next = c;
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
(next ?? fallback)?.focus({ preventScroll: true });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Set (or remove for null / false) an attribute only when it changes. */
|
|
85
|
+
export function attr(el: Element, name: string, value: string | boolean | null): void {
|
|
86
|
+
if (value === null || value === false) {
|
|
87
|
+
if (el.hasAttribute(name)) el.removeAttribute(name);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const v = value === true ? '' : value;
|
|
91
|
+
if (el.getAttribute(name) !== v) el.setAttribute(name, v);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function setText(el: Element, text: string): void {
|
|
95
|
+
if (el.textContent !== text) el.textContent = text;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** An inline SVG icon (16 × 16, 1.5 px stroke, `currentColor`), hidden from assistive tech. */
|
|
99
|
+
export function icon(name: IconName, cls = 'icon'): SVGSVGElement {
|
|
100
|
+
const tpl = document.createElement('template');
|
|
101
|
+
tpl.innerHTML = `<svg class="${cls}" viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">${ICONS[name]}</svg>`;
|
|
102
|
+
return tpl.content.firstElementChild as SVGSVGElement;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** An icon-only button with an accessible name and a tooltip. */
|
|
106
|
+
export function iconButton(
|
|
107
|
+
name: IconName,
|
|
108
|
+
label: string,
|
|
109
|
+
onClick: (event: Event) => void,
|
|
110
|
+
extra: Props = {},
|
|
111
|
+
): HTMLButtonElement {
|
|
112
|
+
const button = h(
|
|
113
|
+
'button',
|
|
114
|
+
{
|
|
115
|
+
type: 'button',
|
|
116
|
+
class: 'icon-btn',
|
|
117
|
+
'aria-label': label,
|
|
118
|
+
title: label,
|
|
119
|
+
onclick: onClick,
|
|
120
|
+
...extra,
|
|
121
|
+
},
|
|
122
|
+
icon(name),
|
|
123
|
+
);
|
|
124
|
+
return button;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Keep the accessible name and tooltip of an icon button in sync with the locale. */
|
|
128
|
+
export function relabel(el: Element, label: string): void {
|
|
129
|
+
attr(el, 'aria-label', label);
|
|
130
|
+
attr(el, 'title', label);
|
|
131
|
+
}
|