Extract key from props in h() for UElement, keep key in props for URoot
This commit is contained in:
@@ -3,18 +3,19 @@ import type { UNode, UElement, URoot, UType, UComponent, UniversalProps } from "
|
|||||||
let _idCounter = 0;
|
let _idCounter = 0;
|
||||||
|
|
||||||
export function h(type: UType, props?: UniversalProps | null, ...children: UNode[]): UElement | URoot {
|
export function h(type: UType, props?: UniversalProps | null, ...children: UNode[]): UElement | URoot {
|
||||||
const { key, ...restProps } = props ?? {};
|
|
||||||
const resolvedProps: UniversalProps = restProps;
|
|
||||||
const flatChildren = children.flat(Infinity as 1).filter((c: UNode) => c != null && c !== false) as UNode[];
|
const flatChildren = children.flat(Infinity as 1).filter((c: UNode) => c != null && c !== false) as UNode[];
|
||||||
|
|
||||||
if (type === "root") {
|
if (type === "root") {
|
||||||
return {
|
return {
|
||||||
type: "root",
|
type: "root",
|
||||||
props: resolvedProps,
|
props: { ...(props ?? {}) },
|
||||||
children: flatChildren,
|
children: flatChildren,
|
||||||
} as URoot;
|
} as URoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { key, ...restProps } = props ?? {};
|
||||||
|
const resolvedProps: UniversalProps = restProps;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: type as string,
|
type: type as string,
|
||||||
props: resolvedProps,
|
props: resolvedProps,
|
||||||
|
|||||||
@@ -100,6 +100,34 @@ describe("type guards", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("UElement key field", () => {
|
describe("UElement key field", () => {
|
||||||
|
it("h('div', { key: 'a' }) produces UElement with key: 'a' and no key in props", () => {
|
||||||
|
const el = h("div", { key: "a" });
|
||||||
|
expect(isUElement(el)).toBe(true);
|
||||||
|
if (isUElement(el)) {
|
||||||
|
expect(el.key).toBe("a");
|
||||||
|
expect(el.props.key).toBeUndefined();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("h('div', { key: 'b', class: 'x' }) — key promoted, class remains in props", () => {
|
||||||
|
const el = h("div", { key: "b", class: "x" });
|
||||||
|
expect(isUElement(el)).toBe(true);
|
||||||
|
if (isUElement(el)) {
|
||||||
|
expect(el.key).toBe("b");
|
||||||
|
expect(el.props.key).toBeUndefined();
|
||||||
|
expect(el.props.class).toBe("x");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("h('div', null) — key is undefined, no key in props", () => {
|
||||||
|
const el = h("div", null);
|
||||||
|
expect(isUElement(el)).toBe(true);
|
||||||
|
if (isUElement(el)) {
|
||||||
|
expect(el.key).toBeUndefined();
|
||||||
|
expect(el.props).toEqual({});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it("h() extracts key from props and promotes to element level", () => {
|
it("h() extracts key from props and promotes to element level", () => {
|
||||||
const el = h("div", { key: "item-1", class: "test" }, "hello");
|
const el = h("div", { key: "item-1", class: "test" }, "hello");
|
||||||
expect(isUElement(el)).toBe(true);
|
expect(isUElement(el)).toBe(true);
|
||||||
@@ -144,11 +172,11 @@ describe("UElement key field", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("h() with root type does not promote key to URoot", () => {
|
it("h() with root type does not promote key to URoot", () => {
|
||||||
const root = h("root", { key: "should-not-appear", id: "test" }, "child");
|
const root = h("root", { key: "x", id: "test" }, "child");
|
||||||
expect(isURoot(root)).toBe(true);
|
expect(isURoot(root)).toBe(true);
|
||||||
if (isURoot(root)) {
|
if (isURoot(root)) {
|
||||||
expect("key" in root).toBe(false);
|
expect("key" in root).toBe(false);
|
||||||
expect(root.props.key).toBeUndefined();
|
expect(root.props.key).toBe("x");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user