fix(dev-server): preserve nested component named slots
This commit is contained in:
1 parent
25a421c727
commit
1dd60ded0d
4 files changed
+37
-7
No files matched your search
@@ -357,7 +357,7 @@
|
|||||||
},
|
},
|
||||||
"packages/dev-server": {
|
"packages/dev-server": {
|
||||||
"name": "@wrnexus/dev-server",
|
"name": "@wrnexus/dev-server",
|
||||||
"version": "0.8.57",
|
"version": "0.8.58",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/authz": "workspace:*",
|
"@wrnexus/authz": "workspace:*",
|
||||||
"@wrnexus/cache": "workspace:*",
|
"@wrnexus/cache": "workspace:*",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/dev-server",
|
"name": "@wrnexus/dev-server",
|
||||||
"version": "0.8.57",
|
"version": "0.8.58",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -2622,8 +2622,9 @@ function extractSlots(inner: string): { named: Record<string, string>; def: stri
|
|||||||
const named: Record<string, string> = {};
|
const named: Record<string, string> = {};
|
||||||
if (!inner.includes("data-slot=")) return { named, def: inner };
|
if (!inner.includes("data-slot=")) return { named, def: inner };
|
||||||
|
|
||||||
const SLOT_MOUNT_RE =
|
// Only direct children belong to this mount. Descendant named slots belong
|
||||||
/<([A-Za-z][A-Za-z0-9-]*)\b([^>]*?\bdata-slot="([A-Za-z0-9_-]+)"[^>]*?)(\/?)>/;
|
// to their own component (for example a splitter inside a shell's slot).
|
||||||
|
const SLOT_MOUNT_RE = /<([A-Za-z][A-Za-z0-9-]*)\b([^>]*?)(\/?)>/;
|
||||||
let def = "";
|
let def = "";
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -2634,11 +2635,16 @@ function extractSlots(inner: string): { named: Record<string, string>; def: stri
|
|||||||
}
|
}
|
||||||
const tagStart = i + m.index;
|
const tagStart = i + m.index;
|
||||||
def += inner.slice(i, tagStart);
|
def += inner.slice(i, tagStart);
|
||||||
const [open, tag, , name, selfClose] = m;
|
const [open, tag, attributes, selfClose] = m;
|
||||||
|
const name = /\bdata-slot="([A-Za-z0-9_-]+)"/.exec(attributes!)?.[1];
|
||||||
const openEnd = tagStart + open.length;
|
const openEnd = tagStart + open.length;
|
||||||
const { inner: content, end } =
|
const { inner: content, end } =
|
||||||
selfClose === "/" ? { inner: "", end: openEnd } : readElementBody(inner, tag!, openEnd);
|
selfClose === "/" ||
|
||||||
named[name!] = content;
|
/^(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)$/i.test(tag!)
|
||||||
|
? { inner: "", end: openEnd }
|
||||||
|
: readElementBody(inner, tag!, openEnd);
|
||||||
|
if (name) named[name] = content;
|
||||||
|
else def += inner.slice(tagStart, end);
|
||||||
i = end;
|
i = end;
|
||||||
}
|
}
|
||||||
return { named, def };
|
return { named, def };
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { expect, test } from "bun:test";
|
||||||
|
import { fillSlots } from "../src/runtime.ts";
|
||||||
|
|
||||||
|
test("an outer default slot preserves a nested component's named slots", () => {
|
||||||
|
const child =
|
||||||
|
'<div data-component="LayoutSplitter"><div data-slot="start">Inbox</div><div data-slot="end">Message</div></div>';
|
||||||
|
const shell = fillSlots("<main><slot></slot></main>", child, true);
|
||||||
|
expect(shell).toContain(child);
|
||||||
|
const panes = fillSlots(
|
||||||
|
'<section><slot name="start"></slot><slot name="end"></slot></section>',
|
||||||
|
'<div data-slot="start">Inbox</div><div data-slot="end">Message</div>',
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(panes).toContain("Inbox</wrn-slot>");
|
||||||
|
expect(panes).toContain("Message</wrn-slot>");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("void children do not swallow following direct named slots", () => {
|
||||||
|
const html = fillSlots(
|
||||||
|
'<slot name="header"></slot><slot></slot>',
|
||||||
|
'Text<input><div data-slot="header">Heading</div><p>Body</p>',
|
||||||
|
);
|
||||||
|
expect(html).toBe("HeadingText<input><p>Body</p>");
|
||||||
|
});
|
||||||
Reference in new issue
Block a user