Fix children not rendering when render() called from different module
Create stable component function references at definition time instead of on every render. This fixes Hono's JSX reconciliation losing track of children when the component type identity keeps changing. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
e772e0e711
commit
9b8d789da0
|
|
@ -147,8 +147,10 @@ function makeStyle(def: TagDef) {
|
||||||
return style
|
return style
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ROOT_PROPS_KEY = '_forgeRootProps'
|
||||||
|
|
||||||
// turns a TagDef into a JSX component
|
// turns a TagDef into a JSX component
|
||||||
function makeComponent(baseName: string, rootDef: TagDef, rootProps: Record<string, any>, partName?: string) {
|
function makeComponent(baseName: string, rootDef: TagDef, partName?: string) {
|
||||||
const def = partName ? rootDef.parts?.[partName]! : rootDef
|
const def = partName ? rootDef.parts?.[partName]! : rootDef
|
||||||
const base = def.base ?? 'div'
|
const base = def.base ?? 'div'
|
||||||
|
|
||||||
|
|
@ -167,7 +169,7 @@ function makeComponent(baseName: string, rootDef: TagDef, rootProps: Record<stri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ({ children, ...props }: { children: any, [key: string]: any }) => {
|
return ({ [ROOT_PROPS_KEY]: rootProps = {}, children, ...props }: { [ROOT_PROPS_KEY]?: Record<string, any>, children: any, [key: string]: any }) => {
|
||||||
const classNames = [makeClassName(baseName, partName)]
|
const classNames = [makeClassName(baseName, partName)]
|
||||||
|
|
||||||
const allProps = { ...rootProps, ...props }
|
const allProps = { ...rootProps, ...props }
|
||||||
|
|
@ -286,14 +288,28 @@ export function define(nameOrDef: string | TagDef, defIfNamed?: TagDef) {
|
||||||
if (styles[name]) throw `${name} is already defined! Must use unique names.`
|
if (styles[name]) throw `${name} is already defined! Must use unique names.`
|
||||||
registerStyles(name, def)
|
registerStyles(name, def)
|
||||||
|
|
||||||
|
// ensure component function identity doesn't change between renders
|
||||||
|
const components: Record<string, (props: any) => any> = {}
|
||||||
|
|
||||||
|
for (const [partName] of Object.entries(def.parts ?? {}))
|
||||||
|
components[partName] = makeComponent(name, def, partName)
|
||||||
|
|
||||||
|
const RootComponent = makeComponent(name, def)
|
||||||
|
|
||||||
return (props: Record<string, any>) => {
|
return (props: Record<string, any>) => {
|
||||||
const parts: Record<string, Function> = {}
|
if (def.render) {
|
||||||
|
// For custom render, create parts object that injects _forgeRootProps
|
||||||
|
const parts: Record<string, (partProps: any) => any> = {}
|
||||||
|
|
||||||
for (const [part] of Object.entries(def.parts ?? {}))
|
for (const [partName, Comp] of Object.entries(components))
|
||||||
parts[part] = makeComponent(name, def, props, part)
|
parts[partName] = (partProps: any) => <Comp {...{ [ROOT_PROPS_KEY]: props }} {...partProps} />
|
||||||
|
|
||||||
parts.Root = makeComponent(name, def, props)
|
parts.Root = (partProps: any) => <RootComponent {...{ [ROOT_PROPS_KEY]: props }} {...partProps} />
|
||||||
return def.render?.({ props, parts }) ?? <parts.Root {...props}>{props.children}</parts.Root>
|
return def.render({ props, parts })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default render
|
||||||
|
return <RootComponent {...{ [ROOT_PROPS_KEY]: props }} {...props}>{props.children}</RootComponent>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user