fix(ink): restore host prop updates in React 19 reconciler (#589)

React 19's react-reconciler@0.33 mutation path calls commitUpdate with
(instance, type, oldProps, newProps, fiber), but our Ink host config
still expected an updatePayload from prepareUpdate. That left mounted
ink-* nodes with stale onKeyDown, tabIndex, and textStyles, making menu
navigation and highlights appear stuck until remount.

Diff old/new props directly inside commitUpdate and add regression tests
covering in-place updates for ink-box handlers/attributes and ink-text
styles.
This commit is contained in:
Alina Lisova
2026-04-11 16:19:39 +03:00
committed by GitHub
parent 91e4cfb15b
commit 6e94dd9136
2 changed files with 383 additions and 6 deletions

View File

@@ -449,17 +449,25 @@ const reconciler = createReconciler<
},
commitUpdate(
node: DOMElement,
updatePayload: UpdatePayload | null,
_type: ElementNames,
_oldProps: Props,
_newProps: Props,
oldProps: Props,
newProps: Props,
): void {
if (!updatePayload) {
// React 19 mutation mode calls commitUpdate as
// (instance, type, oldProps, newProps, fiber) and does not pass the
// prepareUpdate() payload here. This renderer used to treat the second
// argument as updatePayload, which left mounted ink-* nodes with stale
// attributes, event handlers, and textStyles until something forced a
// remount. Recompute the prop/style diff here so host nodes update
// correctly in place on rerender.
const props = diff(oldProps, newProps)
const style = diff(oldProps['style'] as Styles, newProps['style'] as Styles)
const nextStyle = newProps['style'] as Styles | undefined
if (!props && !style) {
return
}
const { props, style, nextStyle } = updatePayload
if (props) {
for (const [key, value] of Object.entries(props)) {
if (key === 'style') {