@zoijs/core 1.3.1 → 1.3.2
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 +10 -0
- package/package.json +1 -1
- package/src/core/renderer.js +28 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@ All notable changes to Zoijs are documented here. The format is based on
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/), and Zoijs follows
|
|
5
5
|
[Semantic Versioning](https://semver.org/) (see `VERSIONING.md`).
|
|
6
6
|
|
|
7
|
+
## [1.3.2] — 2026-06-26
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- **Focus is preserved across a keyed reorder.** The 1.3.1 minimal-move change can
|
|
11
|
+
move the subtree that holds the focused element, which blurs it in browsers.
|
|
12
|
+
`each` now captures focus + caret position before reordering and restores them
|
|
13
|
+
after, so reordering a list never steals focus or selection — whichever nodes
|
|
14
|
+
happen to move. Verified in Chromium, Firefox, and WebKit
|
|
15
|
+
(`browser-tests/regression.spec.js`).
|
|
16
|
+
|
|
7
17
|
## [1.3.1] — 2026-06-26
|
|
8
18
|
|
|
9
19
|
### Performance
|
package/package.json
CHANGED
package/src/core/renderer.js
CHANGED
|
@@ -343,6 +343,23 @@ function setupKeyedList(anchor, marker) {
|
|
|
343
343
|
for (const n of rec.nodes) n.remove();
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
+
// Moving the subtree that holds the focused element blurs it in some browsers,
|
|
347
|
+
// so capture focus (and caret) before the moves and restore it after — a
|
|
348
|
+
// reorder must never steal focus or selection, whichever nodes happen to move.
|
|
349
|
+
const doc = anchor.ownerDocument;
|
|
350
|
+
const active = doc && doc.activeElement;
|
|
351
|
+
const refocus = active && active !== doc.body && parent.contains(active);
|
|
352
|
+
let selStart = null;
|
|
353
|
+
let selEnd = null;
|
|
354
|
+
if (refocus) {
|
|
355
|
+
try {
|
|
356
|
+
selStart = active.selectionStart;
|
|
357
|
+
selEnd = active.selectionEnd;
|
|
358
|
+
} catch {
|
|
359
|
+
selStart = null; // not a text field — focus only, no caret to restore
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
346
363
|
// Items in the longest increasing subsequence of old positions are already in
|
|
347
364
|
// the right relative order — leave them put (minimal DOM moves). Everything
|
|
348
365
|
// else (moved or new) is inserted before the running cursor, walking from the
|
|
@@ -362,6 +379,17 @@ function setupKeyedList(anchor, marker) {
|
|
|
362
379
|
cursor = rec.nodes[0] || cursor;
|
|
363
380
|
}
|
|
364
381
|
|
|
382
|
+
if (refocus && doc.activeElement !== active) {
|
|
383
|
+
active.focus();
|
|
384
|
+
if (selStart !== null && active.setSelectionRange) {
|
|
385
|
+
try {
|
|
386
|
+
active.setSelectionRange(selStart, selEnd);
|
|
387
|
+
} catch {
|
|
388
|
+
/* element no longer supports selection — focus alone is enough */
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
365
393
|
records = newRecords;
|
|
366
394
|
currentList = ordered;
|
|
367
395
|
};
|