Refresh UI components and showcase; release updated framework packages
This commit is contained in:
1 parent
d800228585
commit
c77f5e1cec
293 files changed
+22544
-35778
No files matched your search
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/csr",
|
||||
"version": "0.8.40",
|
||||
"version": "0.8.41",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -557,6 +557,11 @@ export const NAV_RUNTIME = String.raw`
|
||||
|
||||
syncWrnStyles(doc);
|
||||
|
||||
document.querySelectorAll('script[data-wrn-controls]').forEach(function (node) { node.remove(); });
|
||||
doc.querySelectorAll('script[data-wrn-controls]').forEach(function (node) {
|
||||
document.body.appendChild(document.importNode(node, true));
|
||||
});
|
||||
|
||||
var importedNodes = [];
|
||||
|
||||
for (
|
||||
|
||||
@@ -875,6 +875,15 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
}
|
||||
|
||||
function setupScope(el) {
|
||||
// Capture the document's registry nodes for retained scopes across navigation.
|
||||
var controlRegistries = Array.prototype.slice.call(document.querySelectorAll('script[data-wrn-controls]'));
|
||||
for (var registryParent = el.parentElement; registryParent; registryParent = registryParent.parentElement) {
|
||||
if (registryParent.__wrnControlRegistries) {
|
||||
controlRegistries = controlRegistries.concat(registryParent.__wrnControlRegistries);
|
||||
break;
|
||||
}
|
||||
}
|
||||
el.__wrnControlRegistries = controlRegistries;
|
||||
if (el.__wrnexusScope) {
|
||||
el.removeAttribute("data-scope");
|
||||
el.removeAttribute("data-wrn-scope");
|
||||
@@ -1989,6 +1998,14 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
// materialize the appropriate branch/rows and hydrate their bindings.
|
||||
function decodeControlDefinition(value) {
|
||||
try {
|
||||
if (value && value.charAt(0) === "@") {
|
||||
var split = value.lastIndexOf(":");
|
||||
var registryId = value.slice(1, split);
|
||||
var registry = controlRegistries.find(function (node) { return node.id === registryId; });
|
||||
if (!registry) throw new Error("Missing control template registry");
|
||||
if (!registry.__wrnDefinitions) registry.__wrnDefinitions = JSON.parse(registry.textContent);
|
||||
return registry.__wrnDefinitions[Number(value.slice(split + 1))];
|
||||
}
|
||||
var binary = window.atob(value || "");
|
||||
var bytes = new Uint8Array(binary.length);
|
||||
for (var index = 0; index < binary.length; index++) {
|
||||
@@ -2389,16 +2406,14 @@ export const REACTIVE_RUNTIME = String.raw`
|
||||
}
|
||||
});
|
||||
|
||||
var keyedFragment = document.createDocumentFragment();
|
||||
// Leave already-positioned keyed nodes attached. Detaching every row
|
||||
// restarts CSS animations (notably existing toast progress timers).
|
||||
var keyedCursor = marker.nextSibling;
|
||||
orderedNodes.forEach(function (node) {
|
||||
keyedFragment.appendChild(node);
|
||||
if (node !== keyedCursor) parent.insertBefore(node, keyedCursor);
|
||||
keyedCursor = node.nextSibling;
|
||||
});
|
||||
|
||||
parent.insertBefore(
|
||||
keyedFragment,
|
||||
marker.nextSibling,
|
||||
);
|
||||
|
||||
keyedRecords = nextRecords;
|
||||
clones = orderedNodes;
|
||||
});
|
||||
|
||||
@@ -71,6 +71,15 @@ test("intercepts an internal link click and swaps #app in place", async () => {
|
||||
expect(win.document.title).toBe("About");
|
||||
});
|
||||
|
||||
test("navigation replaces document control registries before hydration", async () => {
|
||||
install('<div id="app"><a href="/next" id="lnk">Next</a></div><script type="application/json" data-wrn-controls id="old">[]</script>');
|
||||
nextHtml = '<html><body><div id="app">Next</div><script type="application/json" data-wrn-controls id="new">[[{"cond":null,"body":"Ready"}]]</script></body></html>';
|
||||
win.document.getElementById("lnk").click();
|
||||
await flush();
|
||||
expect(win.document.getElementById("old")).toBeNull();
|
||||
expect(win.document.getElementById("new")?.textContent).toContain("Ready");
|
||||
});
|
||||
|
||||
test("prefetches focused routes once and reuses the document during navigation", async () => {
|
||||
install(`<div id="app"><a href="/about" id="prefetch">About</a></div>`);
|
||||
nextHtml =
|
||||
|
||||
@@ -149,6 +149,21 @@ test("compiled if blocks switch branches after hydration", () => {
|
||||
expect(win.document.querySelector(".open")?.textContent).toBe("Open 3");
|
||||
});
|
||||
|
||||
test("registry controls retain nested markup and work after the registry leaves the document", () => {
|
||||
const definitions = [
|
||||
[{ cond: "open", body: '<template data-wrn-if="@registry:1"></template><b>Nested</b><template data-wrn-control-end></template>' }, { cond: null, body: '<i>Closed</i>' }],
|
||||
[{ cond: null, body: '<b>Nested</b>' }],
|
||||
];
|
||||
const win = mount(`<script type="application/json" data-wrn-controls id="registry">${JSON.stringify(definitions)}</script>` +
|
||||
'<div data-scope="open: false"><button data-on-click="open = !open">Toggle</button><template data-wrn-if="@registry:0"></template><i>Closed</i><template data-wrn-control-end></template></div>');
|
||||
win.document.getElementById("registry")!.remove();
|
||||
win.document.querySelector("button")!.click();
|
||||
expect(win.document.querySelector("b")?.textContent).toBe("Nested");
|
||||
expect(win.document.querySelector("i")).toBeNull();
|
||||
win.document.querySelector("button")!.click();
|
||||
expect(win.document.querySelector("i")?.textContent).toBe("Closed");
|
||||
});
|
||||
|
||||
test("compiled each blocks rerender rows and their empty branch", () => {
|
||||
const definition = Buffer.from(
|
||||
JSON.stringify({
|
||||
@@ -1890,3 +1905,16 @@ test("a @change binding still fires for a bubbling event inside a component", ()
|
||||
|
||||
expect(win.document.querySelector("#out")?.textContent).toBe("changed");
|
||||
});
|
||||
|
||||
|
||||
test("appending keyed notifications does not detach existing rows", () => {
|
||||
const win = mount(`<div data-scope="rows: [{id: 1, name: 'first'}]"><ul><li data-for="row in rows key row.id">{row.name}</li></ul><button data-on-click="rows = [...rows, {id: 2, name: 'second'}]">add</button></div>`);
|
||||
const list = win.document.querySelector("ul")!;
|
||||
const first = list.querySelector("li");
|
||||
const observer = new win.MutationObserver(() => {});
|
||||
observer.observe(list, {childList: true});
|
||||
(win.document.querySelector("button") as unknown as HTMLElement).click();
|
||||
expect(list.querySelectorAll("li").length).toBe(2);
|
||||
expect(observer.takeRecords().flatMap(record => Array.from(record.removedNodes))).not.toContain(first);
|
||||
observer.disconnect();
|
||||
});
|
||||
Reference in new issue
Block a user