@davmash/bygone 0.9.2 → 0.9.5
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/CHANGELOG.md +21 -0
- package/cli/tourHistory.js +8 -7
- package/media/webview.css +1 -1
- package/media/webview.js +161 -158
- package/out/standalone-main.js +194 -26
- package/package.json +1 -1
- package/standalone/index.html +4 -4
- package/web/index.html +4 -4
- package/web/presenter.css +6 -0
- package/web/web-host.js +7 -7
package/out/standalone-main.js
CHANGED
|
@@ -2452,6 +2452,10 @@ var init_gitHistory = __esm({
|
|
|
2452
2452
|
shortCommit: commit.shortCommit,
|
|
2453
2453
|
summary: commit.summary,
|
|
2454
2454
|
timestamp: commit.timestamp,
|
|
2455
|
+
author: commit.author,
|
|
2456
|
+
authorEmail: commit.authorEmail,
|
|
2457
|
+
message: commit.message,
|
|
2458
|
+
parents: commit.parents,
|
|
2455
2459
|
parentSummary: parentMetadata.summary,
|
|
2456
2460
|
parentTimestamp: parentMetadata.timestamp,
|
|
2457
2461
|
leftLabel: `${fileName} @ ${parentCommit.slice(0, 7)}`,
|
|
@@ -2468,6 +2472,10 @@ var init_gitHistory = __esm({
|
|
|
2468
2472
|
shortCommit: entry.shortCommit,
|
|
2469
2473
|
summary: entry.summary,
|
|
2470
2474
|
timestamp: entry.timestamp,
|
|
2475
|
+
author: entry.author,
|
|
2476
|
+
authorEmail: entry.authorEmail,
|
|
2477
|
+
message: entry.message,
|
|
2478
|
+
parents: entry.parents,
|
|
2471
2479
|
parentSummary: entry.parentSummary,
|
|
2472
2480
|
parentTimestamp: entry.parentTimestamp,
|
|
2473
2481
|
leftLabel: entry.leftLabel,
|
|
@@ -2490,7 +2498,7 @@ var init_gitHistory = __esm({
|
|
|
2490
2498
|
"--max-count",
|
|
2491
2499
|
String(maxCommits),
|
|
2492
2500
|
"--follow",
|
|
2493
|
-
"--format=%H%
|
|
2501
|
+
"--format=%H%x00%h%x00%cI%x00%s%x00%P%x00%an%x00%ae%x00%B%x1e",
|
|
2494
2502
|
"--",
|
|
2495
2503
|
relativePath
|
|
2496
2504
|
], {
|
|
@@ -2559,21 +2567,19 @@ var init_gitHistory = __esm({
|
|
|
2559
2567
|
}, /* @__PURE__ */ new Map());
|
|
2560
2568
|
}
|
|
2561
2569
|
parseHistoryCommitRecords(logOutput) {
|
|
2562
|
-
return logOutput.split("
|
|
2563
|
-
const
|
|
2564
|
-
const
|
|
2565
|
-
const shortCommit = parts[1];
|
|
2566
|
-
const timestamp = parts[2];
|
|
2567
|
-
const hasParentField = parts.length >= 5;
|
|
2568
|
-
const parentField = hasParentField ? parts[parts.length - 1] || "" : "";
|
|
2569
|
-
const summaryParts = hasParentField ? parts.slice(3, -1) : parts.slice(3);
|
|
2570
|
-
const firstParentCommit = parentField.split(" ").find((candidate) => candidate.length > 0);
|
|
2570
|
+
return logOutput.split("").map((record) => record.replace(/^\n+|\n+$/g, "")).filter(Boolean).map((record) => {
|
|
2571
|
+
const [commit, shortCommit, timestamp, summary, parentField, author, authorEmail, message] = record.split("\0");
|
|
2572
|
+
const parents = parentField.split(" ").filter(Boolean);
|
|
2571
2573
|
return {
|
|
2572
2574
|
commit,
|
|
2573
2575
|
shortCommit,
|
|
2574
2576
|
timestamp,
|
|
2575
|
-
summary
|
|
2576
|
-
|
|
2577
|
+
summary,
|
|
2578
|
+
author,
|
|
2579
|
+
authorEmail,
|
|
2580
|
+
message: message.trimEnd(),
|
|
2581
|
+
parents,
|
|
2582
|
+
parentCommit: parents[0]
|
|
2577
2583
|
};
|
|
2578
2584
|
});
|
|
2579
2585
|
}
|
|
@@ -15989,11 +15995,11 @@ var require_tourHistory = __commonJS({
|
|
|
15989
15995
|
return input;
|
|
15990
15996
|
}
|
|
15991
15997
|
function listCommitHistory(root, commit) {
|
|
15992
|
-
const output = git(root, ["log", "--topo-order", "--format=%x1e%H%x00%P%x00%s%x00%cI%x00", commit, "--"]);
|
|
15998
|
+
const output = git(root, ["log", "--topo-order", "--format=%x1e%H%x00%P%x00%s%x00%cI%x00%an%x00%ae%x00%B%x00", commit, "--"]);
|
|
15993
15999
|
const entries = [];
|
|
15994
16000
|
for (const record of output.split("").slice(1)) {
|
|
15995
16001
|
const fields = record.split("\0");
|
|
15996
|
-
const [oid, parents, summary, timestamp] = fields;
|
|
16002
|
+
const [oid, parents, summary, timestamp, author, authorEmail, message] = fields;
|
|
15997
16003
|
if (!oid) continue;
|
|
15998
16004
|
entries.push({
|
|
15999
16005
|
commit: oid,
|
|
@@ -16002,7 +16008,10 @@ var require_tourHistory = __commonJS({
|
|
|
16002
16008
|
parents: parents.split(" ").filter(Boolean),
|
|
16003
16009
|
shortCommit: oid.slice(0, 7),
|
|
16004
16010
|
summary,
|
|
16005
|
-
timestamp
|
|
16011
|
+
timestamp,
|
|
16012
|
+
author,
|
|
16013
|
+
authorEmail,
|
|
16014
|
+
message: message.trimEnd()
|
|
16006
16015
|
});
|
|
16007
16016
|
}
|
|
16008
16017
|
return entries;
|
|
@@ -16261,7 +16270,7 @@ var require_tourHistory = __commonJS({
|
|
|
16261
16270
|
"--topo-order",
|
|
16262
16271
|
"--follow",
|
|
16263
16272
|
"-M",
|
|
16264
|
-
"--format=%x1e%H%x00%P%x00%s%x00%cI%x00",
|
|
16273
|
+
"--format=%x1e%H%x00%P%x00%s%x00%cI%x00%an%x00%ae%x00%B%x00",
|
|
16265
16274
|
"--name-status",
|
|
16266
16275
|
"-z",
|
|
16267
16276
|
commit,
|
|
@@ -16272,8 +16281,8 @@ var require_tourHistory = __commonJS({
|
|
|
16272
16281
|
let historicalPath = filePath;
|
|
16273
16282
|
for (const record of output.split("").slice(1)) {
|
|
16274
16283
|
const fields = record.split("\0");
|
|
16275
|
-
const [oid, parents, summary, timestamp] = fields;
|
|
16276
|
-
const changes = parseNameStatusZ2(fields.slice(
|
|
16284
|
+
const [oid, parents, summary, timestamp, author, authorEmail, message] = fields;
|
|
16285
|
+
const changes = parseNameStatusZ2(fields.slice(7).join("\0").replace(/^\0?\n/, ""));
|
|
16277
16286
|
const change = changes.find((item) => item.path === historicalPath || item.previousPath === historicalPath) || changes[0];
|
|
16278
16287
|
if (!change) continue;
|
|
16279
16288
|
entries.push({
|
|
@@ -16283,6 +16292,10 @@ var require_tourHistory = __commonJS({
|
|
|
16283
16292
|
shortCommit: oid.slice(0, 7),
|
|
16284
16293
|
summary,
|
|
16285
16294
|
timestamp,
|
|
16295
|
+
author,
|
|
16296
|
+
authorEmail,
|
|
16297
|
+
message: message.trimEnd(),
|
|
16298
|
+
parents: parents.split(" ").filter(Boolean),
|
|
16286
16299
|
path: change.path,
|
|
16287
16300
|
...change.previousPath ? { previousPath: change.previousPath } : {}
|
|
16288
16301
|
});
|
|
@@ -16961,6 +16974,12 @@ var require_workspaceHost = __commonJS({
|
|
|
16961
16974
|
commit: entry.commit,
|
|
16962
16975
|
label: `${entry.shortCommit} ${entry.summary}`.trim(),
|
|
16963
16976
|
meta: entry.timestamp,
|
|
16977
|
+
summary: entry.summary,
|
|
16978
|
+
timestamp: entry.timestamp,
|
|
16979
|
+
author: entry.author,
|
|
16980
|
+
authorEmail: entry.authorEmail,
|
|
16981
|
+
message: entry.message,
|
|
16982
|
+
parents: entry.parents || (entry.parentCommit ? [entry.parentCommit] : []),
|
|
16964
16983
|
selectionEnabled: index < history.entries.length,
|
|
16965
16984
|
selected: current.draft.includes(entry.commit),
|
|
16966
16985
|
active: active === entry.commit,
|
|
@@ -17116,7 +17135,7 @@ var require_workspaceHost = __commonJS({
|
|
|
17116
17135
|
const workspaceAction = message.type.startsWith("workspace");
|
|
17117
17136
|
const current = host.getSession();
|
|
17118
17137
|
const derived = Boolean(current.workspaceView);
|
|
17119
|
-
const sharedAction =
|
|
17138
|
+
const sharedAction = ["toggleHistorySelection", "selectHistoryEntry", "compareHistoryEntry"].includes(message.type);
|
|
17120
17139
|
const derivedAction = derived && ["refreshSession", "selectHistoryEntry", "historyBack", "historyForward", "openDirectoryEntry", "navigateFile", "multiAddPanel", "multiRemovePanel", "historyToggleStaged", "historyToggleSkipUnchanged"].includes(message.type);
|
|
17121
17140
|
if (!workspaceAction && !sharedAction && !derivedAction) return false;
|
|
17122
17141
|
ensure();
|
|
@@ -17170,15 +17189,21 @@ var require_workspaceHost = __commonJS({
|
|
|
17170
17189
|
} finally {
|
|
17171
17190
|
if (!accepted) tour?.dispose?.();
|
|
17172
17191
|
}
|
|
17192
|
+
} else if (message.type === "compareHistoryEntry") {
|
|
17193
|
+
const entry = backend().entries[message.index];
|
|
17194
|
+
if (entry?.parentCommit) {
|
|
17195
|
+
const next = makeSession("compare", [entry.parentCommit, entry.commit], activePath());
|
|
17196
|
+
if (await leave()) await install(makeSession("compare", next.workspaceView.revisions, next.workspaceView.path), "compare");
|
|
17197
|
+
}
|
|
17173
17198
|
} else if (message.type === "selectHistoryEntry" && state.mode === "compare") {
|
|
17174
17199
|
const revision = backend().entries[message.index]?.commit;
|
|
17175
17200
|
const panel = current.multi?.files.find((item) => item.revision === revision);
|
|
17176
17201
|
if (panel) {
|
|
17177
17202
|
current.multi.activePanelId = panel.id;
|
|
17178
17203
|
host.send({ type: "focusHistoryPanel", panelId: panel.id });
|
|
17179
|
-
} else {
|
|
17180
|
-
|
|
17181
|
-
|
|
17204
|
+
} else if (revision) {
|
|
17205
|
+
const next = makeSession("history", windowAround(backend().entries, message.index, Math.max(2, current.multi?.files.length || 2)), activePath());
|
|
17206
|
+
if (await leave()) await install(makeSession("history", next.workspaceView.revisions, next.workspaceView.path), "history");
|
|
17182
17207
|
}
|
|
17183
17208
|
} else if (derivedAction) {
|
|
17184
17209
|
if (message.type === "refreshSession") {
|
|
@@ -17921,7 +17946,11 @@ function createWorkspaceHistory(context, options = {}) {
|
|
|
17921
17946
|
parentCommit: entry.parentCommit,
|
|
17922
17947
|
shortCommit: entry.shortCommit,
|
|
17923
17948
|
summary: entry.summary,
|
|
17924
|
-
timestamp: entry.timestamp
|
|
17949
|
+
timestamp: entry.timestamp,
|
|
17950
|
+
author: entry.author,
|
|
17951
|
+
authorEmail: entry.authorEmail,
|
|
17952
|
+
message: entry.message,
|
|
17953
|
+
parents: entry.parents
|
|
17925
17954
|
}))
|
|
17926
17955
|
];
|
|
17927
17956
|
const changedCommitsCache = /* @__PURE__ */ new Map();
|
|
@@ -18177,7 +18206,7 @@ function readCommitMetadataBatch(repoRoot, selectedRoots, axis) {
|
|
|
18177
18206
|
"log",
|
|
18178
18207
|
"--topo-order",
|
|
18179
18208
|
"--reverse",
|
|
18180
|
-
"--format=%H%x00%h%x00%cI%x00%s%x00%P%x1e",
|
|
18209
|
+
"--format=%H%x00%h%x00%cI%x00%s%x00%P%x00%an%x00%ae%x00%B%x1e",
|
|
18181
18210
|
...selectedRoots.slice().sort()
|
|
18182
18211
|
], repoRoot, MAX_GIT_METADATA_BYTES);
|
|
18183
18212
|
const axisSet = new Set(axis);
|
|
@@ -18187,7 +18216,7 @@ function readCommitMetadataBatch(repoRoot, selectedRoots, axis) {
|
|
|
18187
18216
|
if (!record) {
|
|
18188
18217
|
continue;
|
|
18189
18218
|
}
|
|
18190
|
-
const [commit = "", shortCommit = "", timestamp = "", summary = "", parentField = ""] = record.split("\0");
|
|
18219
|
+
const [commit = "", shortCommit = "", timestamp = "", summary = "", parentField = "", author = "", authorEmail = "", message = ""] = record.split("\0");
|
|
18191
18220
|
if (!axisSet.has(commit)) {
|
|
18192
18221
|
continue;
|
|
18193
18222
|
}
|
|
@@ -18196,6 +18225,10 @@ function readCommitMetadataBatch(repoRoot, selectedRoots, axis) {
|
|
|
18196
18225
|
shortCommit: shortCommit || commit.slice(0, 7),
|
|
18197
18226
|
timestamp,
|
|
18198
18227
|
summary,
|
|
18228
|
+
author,
|
|
18229
|
+
authorEmail,
|
|
18230
|
+
message: message.trimEnd(),
|
|
18231
|
+
parents: parentField.split(" ").filter(Boolean),
|
|
18199
18232
|
parentCommit: parentField.split(" ").find(Boolean) ?? null
|
|
18200
18233
|
});
|
|
18201
18234
|
}
|
|
@@ -18752,7 +18785,7 @@ var require_package = __commonJS({
|
|
|
18752
18785
|
displayName: "Bygone",
|
|
18753
18786
|
desktopName: "com.davidmashburn.bygone.desktop",
|
|
18754
18787
|
description: "See how change happened. Visual diff and file history for VS Code.",
|
|
18755
|
-
version: "0.9.
|
|
18788
|
+
version: "0.9.5",
|
|
18756
18789
|
author: "David Mashburn",
|
|
18757
18790
|
license: "MIT",
|
|
18758
18791
|
private: false,
|
|
@@ -32452,6 +32485,141 @@ ${error.message}`);
|
|
|
32452
32485
|
assert.equal(session2().multi.files.at(-1).editable, true);
|
|
32453
32486
|
const checkboxes = await evaluate("document.querySelectorAll('#history-rail [role=checkbox]').length");
|
|
32454
32487
|
assert.ok(checkboxes >= 4, `Expected all commits, got ${checkboxes}`);
|
|
32488
|
+
const hoverElapsed = await evaluate(`new Promise((resolve, reject) => {
|
|
32489
|
+
document.dispatchEvent(new Event('pointerdown', { bubbles: true }));
|
|
32490
|
+
const details = document.querySelector('.commit-hover-details');
|
|
32491
|
+
const started = performance.now();
|
|
32492
|
+
const timeout = setTimeout(() => { observer.disconnect(); reject(new Error('Commit hover did not open')); }, 5000);
|
|
32493
|
+
const observer = new MutationObserver(() => {
|
|
32494
|
+
if (details.hidden) return;
|
|
32495
|
+
observer.disconnect(); clearTimeout(timeout); resolve(performance.now() - started);
|
|
32496
|
+
});
|
|
32497
|
+
observer.observe(details, { attributes: true, attributeFilter: ['hidden'] });
|
|
32498
|
+
document.querySelector('[data-commit-row] .history-rail-entry').dispatchEvent(
|
|
32499
|
+
new MouseEvent('mouseover', { bubbles: true, relatedTarget: document.querySelector('[data-commit-row] [data-rail-menu]') }));
|
|
32500
|
+
})`);
|
|
32501
|
+
assert.ok(hoverElapsed >= 480, `Commit details wait for the shared 500ms hover delay (got ${hoverElapsed}ms)`);
|
|
32502
|
+
const overlays = await evaluate(`(async () => {
|
|
32503
|
+
const row = document.querySelector('[data-commit-row]');
|
|
32504
|
+
const details = document.querySelector('.commit-hover-details');
|
|
32505
|
+
const selected = document.querySelectorAll('[aria-checked=true]').length;
|
|
32506
|
+
const detailStyle = getComputedStyle(details);
|
|
32507
|
+
const hover = { visible: !details.hidden, background: detailStyle.backgroundColor, font: detailStyle.fontFamily };
|
|
32508
|
+
row.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true, cancelable: true, clientX: 40, clientY: 200 }));
|
|
32509
|
+
const menu = document.querySelector('.commit-context-menu');
|
|
32510
|
+
const menuStyle = getComputedStyle(menu);
|
|
32511
|
+
const buttonStyle = getComputedStyle(menu.querySelector('button'));
|
|
32512
|
+
const result = { hover, menuVisible: !menu.hidden, background: menuStyle.backgroundColor,
|
|
32513
|
+
font: menuStyle.fontFamily, buttonFont: buttonStyle.fontFamily,
|
|
32514
|
+
singleNavigationTooltip: ['previous-file', 'next-file'].every(id => {
|
|
32515
|
+
const button = document.getElementById(id);
|
|
32516
|
+
return button.hasAttribute('data-tooltip') && !button.hasAttribute('title');
|
|
32517
|
+
}),
|
|
32518
|
+
selectionUnchanged: selected === document.querySelectorAll('[aria-checked=true]').length };
|
|
32519
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
32520
|
+
await new Promise(resolve => setTimeout(resolve, 700));
|
|
32521
|
+
result.dismissed = menu.hidden && details.hidden;
|
|
32522
|
+
return result;
|
|
32523
|
+
})()`);
|
|
32524
|
+
assert.equal(overlays.hover.visible, true);
|
|
32525
|
+
assert.equal(overlays.menuVisible, true);
|
|
32526
|
+
assert.equal(overlays.selectionUnchanged, true);
|
|
32527
|
+
assert.equal(overlays.singleNavigationTooltip, true, "File navigation must not show both managed and native tooltips");
|
|
32528
|
+
assert.equal(overlays.dismissed, true, "Escape must not reopen the tooltip through focus restoration");
|
|
32529
|
+
for (const [surface, background] of Object.entries({ details: overlays.hover.background, menu: overlays.background })) {
|
|
32530
|
+
assert.match(background, /^rgb\(/, `${surface} must be opaque: ${JSON.stringify(overlays)}`);
|
|
32531
|
+
}
|
|
32532
|
+
assert.match(overlays.hover.font, /system-ui/);
|
|
32533
|
+
assert.match(overlays.font, /system-ui/);
|
|
32534
|
+
assert.equal(overlays.buttonFont, overlays.font);
|
|
32535
|
+
const canceledCommitHover = await evaluate(`(async () => {
|
|
32536
|
+
const entry = document.querySelector('[data-commit-row] .history-rail-entry');
|
|
32537
|
+
entry.dispatchEvent(new MouseEvent('mouseover', { bubbles: true, relatedTarget: document.body }));
|
|
32538
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
|
|
32539
|
+
await new Promise(resolve => setTimeout(resolve, 700));
|
|
32540
|
+
return document.querySelector('.commit-hover-details').hidden;
|
|
32541
|
+
})()`);
|
|
32542
|
+
assert.equal(canceledCommitHover, true, "Escape cancels pending commit hovers as well as visible ones");
|
|
32543
|
+
const tooltipChecks = await evaluate(`(async () => {
|
|
32544
|
+
const tooltip = document.getElementById('bygone-ui-tooltip');
|
|
32545
|
+
const toolbar = document.getElementById('directory-tree-toolbar');
|
|
32546
|
+
const originallyHidden = toolbar.hidden;
|
|
32547
|
+
toolbar.hidden = false;
|
|
32548
|
+
const hover = async (button, dismiss = true) => {
|
|
32549
|
+
document.dispatchEvent(new Event('pointerdown', { bubbles: true }));
|
|
32550
|
+
const started = performance.now();
|
|
32551
|
+
const elapsed = await new Promise((resolve, reject) => {
|
|
32552
|
+
const timeout = setTimeout(() => { observer.disconnect(); reject(new Error('Tooltip did not open for ' + button.id)); }, 5000);
|
|
32553
|
+
const observer = new MutationObserver(() => {
|
|
32554
|
+
if (tooltip.hidden) return;
|
|
32555
|
+
observer.disconnect(); clearTimeout(timeout); resolve(performance.now() - started);
|
|
32556
|
+
});
|
|
32557
|
+
observer.observe(tooltip, { attributes: true, attributeFilter: ['hidden'] });
|
|
32558
|
+
const svg = button.querySelector('svg') || button;
|
|
32559
|
+
svg.dispatchEvent(new MouseEvent('mouseover', { bubbles: true, relatedTarget: document.body }));
|
|
32560
|
+
// Moving across the icon must not restart or cancel the timer.
|
|
32561
|
+
(svg.querySelector('path') || svg).dispatchEvent(new MouseEvent('mouseover', { bubbles: true, relatedTarget: svg }));
|
|
32562
|
+
});
|
|
32563
|
+
const style = getComputedStyle(tooltip);
|
|
32564
|
+
const anchor = button.getBoundingClientRect();
|
|
32565
|
+
const bounds = tooltip.getBoundingClientRect();
|
|
32566
|
+
const result = { id: button.id, elapsed, text: tooltip.textContent, nativeTitle: button.hasAttribute('title'),
|
|
32567
|
+
opacity: style.opacity, background: style.backgroundColor, font: style.fontFamily,
|
|
32568
|
+
placedBelow: Math.abs(bounds.top - anchor.bottom - 8) < 1,
|
|
32569
|
+
inViewport: bounds.left >= 8 && bounds.right <= innerWidth - 8,
|
|
32570
|
+
pseudoContent: getComputedStyle(button, '::after').content };
|
|
32571
|
+
if (dismiss) button.dispatchEvent(new MouseEvent('mouseout', { bubbles: true, relatedTarget: document.body }));
|
|
32572
|
+
result.dismissed = tooltip.hidden;
|
|
32573
|
+
return result;
|
|
32574
|
+
};
|
|
32575
|
+
const checks = [];
|
|
32576
|
+
for (const id of ['directory-expand-all', 'directory-collapse-all', 'directory-collapse-unchanged', 'previous-file', 'next-file']) {
|
|
32577
|
+
const button = document.getElementById(id);
|
|
32578
|
+
const originallyHidden = button.hidden;
|
|
32579
|
+
button.hidden = false;
|
|
32580
|
+
checks.push(await hover(button));
|
|
32581
|
+
button.hidden = originallyHidden;
|
|
32582
|
+
}
|
|
32583
|
+
const button = document.getElementById('directory-expand-all');
|
|
32584
|
+
const oldText = button.dataset.tooltip;
|
|
32585
|
+
button.title = 'Updated tooltip';
|
|
32586
|
+
await Promise.resolve();
|
|
32587
|
+
checks.push({ updatedTitle: button.dataset.tooltip === 'Updated tooltip' && !button.hasAttribute('title') });
|
|
32588
|
+
button.title = oldText;
|
|
32589
|
+
document.dispatchEvent(new Event('pointerdown', { bubbles: true }));
|
|
32590
|
+
const modal = document.createElement('dialog');
|
|
32591
|
+
const action = document.createElement('button');
|
|
32592
|
+
action.id = 'modal-tooltip-smoke';
|
|
32593
|
+
action.title = 'Tooltip inside modal';
|
|
32594
|
+
action.textContent = 'Action';
|
|
32595
|
+
modal.appendChild(action);
|
|
32596
|
+
document.body.appendChild(modal);
|
|
32597
|
+
modal.showModal();
|
|
32598
|
+
const modalCheck = await hover(action, false);
|
|
32599
|
+
modalCheck.parentIsModal = tooltip.parentElement === modal;
|
|
32600
|
+
modal.close();
|
|
32601
|
+
await Promise.resolve();
|
|
32602
|
+
modalCheck.modalDismissed = tooltip.hidden && tooltip.parentElement === document.body;
|
|
32603
|
+
modal.remove();
|
|
32604
|
+
checks.push(modalCheck);
|
|
32605
|
+
toolbar.hidden = originallyHidden;
|
|
32606
|
+
return checks;
|
|
32607
|
+
})()`);
|
|
32608
|
+
const modalCheck = tooltipChecks.pop();
|
|
32609
|
+
assert.ok(
|
|
32610
|
+
modalCheck.text === "Tooltip inside modal" && modalCheck.parentIsModal && modalCheck.modalDismissed,
|
|
32611
|
+
"Modal tooltips render in the top layer and close with their dialog"
|
|
32612
|
+
);
|
|
32613
|
+
assert.equal(tooltipChecks.pop().updatedTitle, true, "Dynamic title updates use the managed tooltip");
|
|
32614
|
+
for (const check of tooltipChecks) {
|
|
32615
|
+
assert.ok(check.elapsed >= 480, `${check.id} must wait 500ms: ${JSON.stringify(check)}`);
|
|
32616
|
+
assert.ok(check.text && !check.nativeTitle && check.dismissed, JSON.stringify(check));
|
|
32617
|
+
assert.equal(check.opacity, "1", "Tooltip opacity is independent of disabled buttons");
|
|
32618
|
+
assert.match(check.background, /^rgb\(/);
|
|
32619
|
+
assert.match(check.font, /system-ui/);
|
|
32620
|
+
assert.equal(check.pseudoContent, "none", "No CSS bubble can appear instantly");
|
|
32621
|
+
assert.ok(check.placedBelow && check.inViewport, JSON.stringify(check));
|
|
32622
|
+
}
|
|
32455
32623
|
await evaluate("document.querySelectorAll('#history-rail [role=checkbox]')[1].click()");
|
|
32456
32624
|
await waitFor("document.querySelector('[data-action=workspaceApply]').textContent.includes('(1)')");
|
|
32457
32625
|
await evaluate("document.querySelectorAll('#history-rail [role=checkbox]')[2].click()");
|
package/package.json
CHANGED
package/standalone/index.html
CHANGED
|
@@ -30,13 +30,13 @@
|
|
|
30
30
|
<div id="change-toolbar" class="change-toolbar header-align-diff" hidden>
|
|
31
31
|
<div class="change-toolbar-main">
|
|
32
32
|
<div class="change-toolbar-nav">
|
|
33
|
-
<button id="previous-file" class="change-button icon-button" type="button"
|
|
33
|
+
<button id="previous-file" class="change-button icon-button" type="button" data-tooltip="Open previous file" aria-label="Previous file">
|
|
34
34
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
35
35
|
<path d="M17 11l-5-5-5 5"></path>
|
|
36
36
|
<path d="M17 18l-5-5-5 5" opacity="0.7"></path>
|
|
37
37
|
</svg>
|
|
38
38
|
</button>
|
|
39
|
-
<button id="next-file" class="change-button change-button-primary icon-button" type="button"
|
|
39
|
+
<button id="next-file" class="change-button change-button-primary icon-button" type="button" data-tooltip="Open next file" aria-label="Next file">
|
|
40
40
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
41
41
|
<path d="M7 13l5 5 5-5"></path>
|
|
42
42
|
<path d="M7 6l5 5 5-5" opacity="0.7"></path>
|
|
@@ -102,14 +102,14 @@
|
|
|
102
102
|
<div id="history-left-time" class="history-time"></div>
|
|
103
103
|
</div>
|
|
104
104
|
<div class="history-nav">
|
|
105
|
-
<button id="history-back" class="history-button icon-button" type="button"
|
|
105
|
+
<button id="history-back" class="history-button icon-button" type="button" data-tooltip="Open older commit (Alt+Left)" aria-label="Older commit">
|
|
106
106
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
107
107
|
<path d="M15 18l-6-6 6-6"></path>
|
|
108
108
|
<path d="M10 18l-6-6 6-6" opacity="0.7"></path>
|
|
109
109
|
</svg>
|
|
110
110
|
</button>
|
|
111
111
|
<div id="history-position" class="history-position" role="status" aria-live="polite" aria-atomic="true"></div>
|
|
112
|
-
<button id="history-forward" class="history-button icon-button" type="button"
|
|
112
|
+
<button id="history-forward" class="history-button icon-button" type="button" data-tooltip="Open newer commit (Alt+Right)" aria-label="Newer commit">
|
|
113
113
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
114
114
|
<path d="M9 18l6-6-6-6"></path>
|
|
115
115
|
<path d="M14 18l6-6-6-6" opacity="0.7"></path>
|
package/web/index.html
CHANGED
|
@@ -177,13 +177,13 @@
|
|
|
177
177
|
<div id="change-toolbar" class="change-toolbar header-align-diff" hidden>
|
|
178
178
|
<div class="change-toolbar-main">
|
|
179
179
|
<div class="change-toolbar-nav">
|
|
180
|
-
<button id="previous-file" class="change-button icon-button" type="button"
|
|
180
|
+
<button id="previous-file" class="change-button icon-button" type="button" data-tooltip="Open previous file" aria-label="Previous file">
|
|
181
181
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
182
182
|
<path d="M17 11l-5-5-5 5"></path>
|
|
183
183
|
<path d="M17 18l-5-5-5 5"></path>
|
|
184
184
|
</svg>
|
|
185
185
|
</button>
|
|
186
|
-
<button id="next-file" class="change-button icon-button" type="button"
|
|
186
|
+
<button id="next-file" class="change-button icon-button" type="button" data-tooltip="Open next file" aria-label="Next file">
|
|
187
187
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
188
188
|
<path d="M7 13l5 5 5-5"></path>
|
|
189
189
|
<path d="M7 6l5 5 5-5"></path>
|
|
@@ -249,14 +249,14 @@
|
|
|
249
249
|
<div id="history-left-time" class="history-time"></div>
|
|
250
250
|
</div>
|
|
251
251
|
<div class="history-nav">
|
|
252
|
-
<button id="history-back" class="history-button icon-button" type="button"
|
|
252
|
+
<button id="history-back" class="history-button icon-button" type="button" data-tooltip="Open older commit" aria-label="Older commit">
|
|
253
253
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
254
254
|
<path d="M15 18l-6-6 6-6"></path>
|
|
255
255
|
<path d="M10 18l-6-6 6-6" opacity="0.7"></path>
|
|
256
256
|
</svg>
|
|
257
257
|
</button>
|
|
258
258
|
<div id="history-position" class="history-position" role="status" aria-live="polite" aria-atomic="true"></div>
|
|
259
|
-
<button id="history-forward" class="history-button icon-button" type="button"
|
|
259
|
+
<button id="history-forward" class="history-button icon-button" type="button" data-tooltip="Open newer commit" aria-label="Newer commit">
|
|
260
260
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
261
261
|
<path d="M9 18l6-6-6-6"></path>
|
|
262
262
|
<path d="M14 18l6-6-6-6" opacity="0.7"></path>
|
package/web/presenter.css
CHANGED
|
@@ -253,12 +253,18 @@ body.tour-mode #container {
|
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
.tour-coverage-item {
|
|
256
|
+
position: relative;
|
|
256
257
|
display: grid;
|
|
257
258
|
gap: 5px;
|
|
258
259
|
padding-left: 8px;
|
|
259
260
|
border-left: 2px solid var(--tour-accent-bright);
|
|
260
261
|
}
|
|
261
262
|
|
|
263
|
+
.tour-coverage-item:focus-visible {
|
|
264
|
+
outline: 2px solid var(--tour-accent-bright);
|
|
265
|
+
outline-offset: 3px;
|
|
266
|
+
}
|
|
267
|
+
|
|
262
268
|
.tour-coverage-item[data-metric="assignment"] {
|
|
263
269
|
border-left-color: #74d6ad;
|
|
264
270
|
}
|