@happy-nut/monacori 0.1.13 → 0.1.15
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/dist/viewer.client.js +38 -10
- package/dist/viewer.css +6 -2
- package/package.json +1 -1
package/dist/viewer.client.js
CHANGED
|
@@ -164,7 +164,7 @@ function setupCustomSelect(id, getOptions, getCurrent, onPick) {
|
|
|
164
164
|
var r = el.getBoundingClientRect(), cur = getCurrent();
|
|
165
165
|
showCustomDropdown(r.left, r.bottom + 4, getOptions().map(function (o) {
|
|
166
166
|
return { label: (o.value === cur ? '✓ ' : ' ') + o.label, onSelect: function () { onPick(o.value); render(); } };
|
|
167
|
-
}));
|
|
167
|
+
}), r.top - 4);
|
|
168
168
|
});
|
|
169
169
|
render();
|
|
170
170
|
return { render: render };
|
|
@@ -2091,7 +2091,28 @@ function saveMergePrompt(kind, text) {
|
|
|
2091
2091
|
|
|
2092
2092
|
// Reusable custom dropdown (keyboard + mouse). options: [{ label, onSelect }]. First item is pre-selected;
|
|
2093
2093
|
// Arrow keys move, Enter chooses, Esc / click-outside dismiss. Replaces native <select>/menus everywhere.
|
|
2094
|
-
|
|
2094
|
+
// Approximate the caret's pixel position in the (monospace) merged textarea so the dropdown can open right
|
|
2095
|
+
// under it — and flip above when there isn't room below. Returns { x, top (caret line top), below }.
|
|
2096
|
+
function mergedCaretXY(area) {
|
|
2097
|
+
var pos = area.selectionStart || 0;
|
|
2098
|
+
var nl = area.value.slice(0, pos).split('\n');
|
|
2099
|
+
var lineNum = nl.length - 1;
|
|
2100
|
+
var col = nl[lineNum].length;
|
|
2101
|
+
var cs = getComputedStyle(area);
|
|
2102
|
+
var lineH = parseFloat(cs.lineHeight) || 18;
|
|
2103
|
+
var rect = area.getBoundingClientRect();
|
|
2104
|
+
var span = document.createElement('span');
|
|
2105
|
+
span.style.cssText = 'position:absolute;visibility:hidden;white-space:pre';
|
|
2106
|
+
span.style.font = cs.font;
|
|
2107
|
+
span.textContent = 'MMMMMMMMMMMMMMMMMMMM';
|
|
2108
|
+
document.body.appendChild(span);
|
|
2109
|
+
var charW = span.getBoundingClientRect().width / 20;
|
|
2110
|
+
span.remove();
|
|
2111
|
+
var caretTop = rect.top + (parseFloat(cs.paddingTop) || 0) + lineNum * lineH - area.scrollTop;
|
|
2112
|
+
var x = Math.min(rect.left + (parseFloat(cs.paddingLeft) || 0) + col * charW, rect.right - 24);
|
|
2113
|
+
return { x: x, top: caretTop, below: caretTop + lineH + 2 };
|
|
2114
|
+
}
|
|
2115
|
+
function showCustomDropdown(x, y, options, flipTop) {
|
|
2095
2116
|
var existing = document.getElementById('mc-dropdown');
|
|
2096
2117
|
if (existing) existing.remove();
|
|
2097
2118
|
var dd = document.createElement('div');
|
|
@@ -2116,9 +2137,16 @@ function showCustomDropdown(x, y, options) {
|
|
|
2116
2137
|
item.addEventListener('mousemove', function () { setActive(i); });
|
|
2117
2138
|
dd.appendChild(item);
|
|
2118
2139
|
});
|
|
2119
|
-
dd.style.left = Math.round(x) + 'px';
|
|
2120
|
-
dd.style.top = Math.round(y) + 'px';
|
|
2121
2140
|
document.body.appendChild(dd);
|
|
2141
|
+
// Position after measuring: open at (x, y); flip above (flipTop) when it would overflow the bottom,
|
|
2142
|
+
// and nudge in from the right/bottom edges so it never clips offscreen.
|
|
2143
|
+
var ddr = dd.getBoundingClientRect();
|
|
2144
|
+
var top = y, left = x;
|
|
2145
|
+
if (typeof flipTop === 'number' && top + ddr.height > window.innerHeight - 8) top = Math.max(8, flipTop - ddr.height);
|
|
2146
|
+
else if (top + ddr.height > window.innerHeight - 8) top = Math.max(8, window.innerHeight - ddr.height - 8);
|
|
2147
|
+
if (left + ddr.width > window.innerWidth - 8) left = Math.max(8, window.innerWidth - ddr.width - 8);
|
|
2148
|
+
dd.style.left = Math.round(left) + 'px';
|
|
2149
|
+
dd.style.top = Math.round(top) + 'px';
|
|
2122
2150
|
document.addEventListener('keydown', onKey, true);
|
|
2123
2151
|
document.addEventListener('mousedown', onOutside, true);
|
|
2124
2152
|
}
|
|
@@ -2221,20 +2249,20 @@ function openMergedView(kind) {
|
|
|
2221
2249
|
e.stopPropagation();
|
|
2222
2250
|
var seqs = mergedCommentSeqs(kind, area.selectionStart, area.selectionEnd);
|
|
2223
2251
|
if (!seqs.length) return;
|
|
2224
|
-
var
|
|
2225
|
-
var x =
|
|
2252
|
+
var cxy = mergedCaretXY(area);
|
|
2253
|
+
var x = cxy.x, y = cxy.below, flipTop = cxy.top;
|
|
2226
2254
|
var rerender = function () {
|
|
2227
2255
|
if (!reviewComments.filter(function (c) { return c.kind === kind; }).length) { modal.remove(); return; }
|
|
2228
2256
|
area.value = buildMergedText(kind);
|
|
2229
2257
|
};
|
|
2230
2258
|
if (area.selectionStart !== area.selectionEnd || seqs.length > 1) {
|
|
2231
|
-
showCustomDropdown(x, y, [{ label: t('dropdown.remove'), onSelect: function () { seqs.forEach(deleteComment); rerender(); } }]);
|
|
2259
|
+
showCustomDropdown(x, y, [{ label: t('dropdown.remove'), onSelect: function () { seqs.forEach(deleteComment); rerender(); } }], flipTop);
|
|
2232
2260
|
} else {
|
|
2233
2261
|
var seq = seqs[0];
|
|
2234
2262
|
showCustomDropdown(x, y, [
|
|
2235
2263
|
{ label: t('dropdown.navigate'), onSelect: function () { modal.remove(); navigateToComment(seq); } },
|
|
2236
2264
|
{ label: t('dropdown.remove'), onSelect: function () { deleteComment(seq); rerender(); } },
|
|
2237
|
-
]);
|
|
2265
|
+
], flipTop);
|
|
2238
2266
|
}
|
|
2239
2267
|
});
|
|
2240
2268
|
closeBtn.addEventListener('click', function () { modal.remove(); });
|
|
@@ -2264,12 +2292,12 @@ function openMergedView(kind) {
|
|
|
2264
2292
|
document.body.appendChild(modal);
|
|
2265
2293
|
// Focus the send button (Enter starts pane-pick) when present, else the read-only text. Electron
|
|
2266
2294
|
// async-restores focus to <body>, so retry briefly (same as the composer).
|
|
2267
|
-
var modalFocusTarget =
|
|
2295
|
+
var modalFocusTarget = area; // focus the text (not the send button) so the caret is visible and Opt+Arrow/Enter work; Send-to-terminal is a click
|
|
2268
2296
|
var modalFocusTries = 0;
|
|
2269
2297
|
var tryFocusModal = function () {
|
|
2270
2298
|
if (!document.getElementById('mc-modal')) return true;
|
|
2271
2299
|
if (document.activeElement === modalFocusTarget) return true;
|
|
2272
|
-
try { modalFocusTarget.focus();
|
|
2300
|
+
try { modalFocusTarget.focus(); modalFocusTarget.selectionStart = modalFocusTarget.selectionEnd = 0; } catch (e) {}
|
|
2273
2301
|
return document.activeElement === modalFocusTarget;
|
|
2274
2302
|
};
|
|
2275
2303
|
if (!tryFocusModal()) {
|
package/dist/viewer.css
CHANGED
|
@@ -685,6 +685,10 @@ h1 { margin: 0; font-size: 18px; }
|
|
|
685
685
|
font-size: 14px; line-height: 1; padding: 0 3px; cursor: pointer; border-radius: 3px;
|
|
686
686
|
}
|
|
687
687
|
.source-tab-close:hover { background: var(--line); color: var(--text); }
|
|
688
|
+
/* Scrolloff: keep the caret / focused row near the vertical middle while navigating, so holding an arrow
|
|
689
|
+
key scrolls the view CONTINUOUSLY instead of leaving it still until the caret reaches the viewport edge
|
|
690
|
+
(the "stutter every ~viewport" the user reported). Applies to the source body, the diff, and the sidebar. */
|
|
691
|
+
.source-body, #diff2html-container, .sidebar-scroll { scroll-padding-block: 35vh; }
|
|
688
692
|
.source-body {
|
|
689
693
|
border: 1px solid var(--border);
|
|
690
694
|
overflow: auto;
|
|
@@ -860,8 +864,8 @@ body.mc-composing .source-row.cursor-line .num { color: inherit; }
|
|
|
860
864
|
.mc-modal-head span { margin-right: auto; }
|
|
861
865
|
.mc-modal-text { width: 100%; height: 100%; box-sizing: border-box; resize: none; border: 0; padding: 12px; background: var(--bg); color: var(--text); caret-color: var(--text); font: 12px/1.55 Monaco, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
|
|
862
866
|
.mc-modal-text:focus { outline: none; }
|
|
863
|
-
.mc-dropdown { position: fixed; z-index: 70; min-width:
|
|
864
|
-
.mc-dropdown-item { display: block; width: 100%; text-align: left; padding:
|
|
867
|
+
.mc-dropdown { position: fixed; z-index: 70; min-width: 0; background: var(--panel); border: 1px solid var(--border); border-radius: 6px; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4); padding: 3px; }
|
|
868
|
+
.mc-dropdown-item { display: block; width: 100%; text-align: left; padding: 4px 10px; border: 0; background: transparent; color: var(--text); border-radius: 4px; font-size: 12px; line-height: 1.5; cursor: pointer; white-space: nowrap; }
|
|
865
869
|
.mc-dropdown-item.active, .mc-dropdown-item:hover { background: var(--active); color: #fff; }
|
|
866
870
|
#mc-toasts { position: fixed; left: 16px; bottom: 16px; z-index: 80; display: flex; flex-direction: column; gap: 8px; max-width: 360px; pointer-events: none; }
|
|
867
871
|
.mc-toast { background: var(--panel); color: var(--text); border: 1px solid var(--border); border-left: 3px solid var(--active); border-radius: 8px; padding: 10px 14px; font-size: 13px; line-height: 1.45; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); opacity: 0; transform: translateY(8px); transition: opacity .25s ease, transform .25s ease; }
|