Found while implementing #6802 (PR #6858). Filed rather than folded in: the
repair is in packages/components, outside that card's file surface, and it is
a behaviour change of its own.
What
packages/components/src/renderers/complex/data-table.tsx commits an inline
edit made in a HOST-INJECTED widget through a document-level pointerdown
listener, not through blur. The reason is written down at the declaration of
injectedEditorElRef:
The built-in input editors commit via their own onBlur, but the injected
widgets (text, number, date, lookup, …) have no such handler — a
document-level pointerdown listener (see below) uses this node to detect
click-outside and commit them.
That justification is weaker than it reads, and #6802 weakens it further.
onBlur is a DECLARED DOM pass-through key — named in FieldWidgetDomProps
(packages/fields/src/widgets/types.ts), named in
SDUI_DOM_PASS_THROUGH_KEYS (packages/core/src/utils/dom-props.ts), and
forwarded by toDomProps. So any widget that spreads toDomProps(props)
onto its control already delivers a caller-supplied onBlur to the real DOM
element, whether or not the widget has a blur handler of its own. The widgets
the comment names (text, date, lookup) are in that group: they have no handler,
which is exactly why a host handler passes straight through.
The five widgets that DO have their own blur handler used to be the risk —
a bare onBlur= written after the spread silently overrode the host's. That is
now closed across the class: #6780 / PR #6801 fixed NumberField,
PercentField and GeolocationField, and #6802 / PR #6858 fixed
CurrencyField and TagsField. All five compose the host handler; the only
control that deliberately takes no host DOM props is GeolocationField's
longitude box, because a composite widget must not duplicate id / name onto
a second element.
⇒ the data-table could plausibly pass onBlur to injected editors and retire
the document-level listener.
Why this is an observation, not a graded defect
Nothing is broken today: the pointerdown listener works, and this is a
simplification, not a repair. Two things a triage pass should weigh before
anyone acts:
- It is a real behaviour change.
pointerdown fires on press; blur fires
on focus loss. They are not the same moment, and they differ for keyboard
users (Tab commits under blur, never fires pointerdown) and for pointer
presses that never take focus. Any swap needs the commit semantics decided
deliberately, not assumed equivalent.
- The measurement should be redone at that point. The set of injected
editors that actually spread toDomProps should be enumerated rather than
assumed — a widget rendering a non-control root (ObjectRefField's trigger,
FileField's dropzone) hand-strips parts of the set already.
If the answer is "keep the listener", the comment still wants correcting: it
states as fact that injected widgets have no blur handler, which is no longer
the reason the listener is needed.
Where
packages/components/src/renderers/complex/data-table.tsx — the
injectedEditorElRef declaration and the pointerdown listener below it.
packages/fields/src/widgets/toDomProps.ts — the whitelist that already
forwards onBlur.
Unassigned and ungraded on purpose — filed by the #6802 seat, which did not
have packages/components in its file surface.
Found while implementing #6802 (PR #6858). Filed rather than folded in: the
repair is in
packages/components, outside that card's file surface, and it isa behaviour change of its own.
What
packages/components/src/renderers/complex/data-table.tsxcommits an inlineedit made in a HOST-INJECTED widget through a document-level
pointerdownlistener, not through blur. The reason is written down at the declaration of
injectedEditorElRef:That justification is weaker than it reads, and #6802 weakens it further.
onBluris a DECLARED DOM pass-through key — named inFieldWidgetDomProps(
packages/fields/src/widgets/types.ts), named inSDUI_DOM_PASS_THROUGH_KEYS(packages/core/src/utils/dom-props.ts), andforwarded by
toDomProps. So any widget that spreadstoDomProps(props)onto its control already delivers a caller-supplied
onBlurto the real DOMelement, whether or not the widget has a blur handler of its own. The widgets
the comment names (text, date, lookup) are in that group: they have no handler,
which is exactly why a host handler passes straight through.
The five widgets that DO have their own blur handler used to be the risk —
a bare
onBlur=written after the spread silently overrode the host's. That isnow closed across the class: #6780 / PR #6801 fixed
NumberField,PercentFieldandGeolocationField, and #6802 / PR #6858 fixedCurrencyFieldandTagsField. All five compose the host handler; the onlycontrol that deliberately takes no host DOM props is
GeolocationField'slongitude box, because a composite widget must not duplicate
id/nameontoa second element.
⇒ the data-table could plausibly pass
onBlurto injected editors and retirethe document-level listener.
Why this is an observation, not a graded defect
Nothing is broken today: the pointerdown listener works, and this is a
simplification, not a repair. Two things a triage pass should weigh before
anyone acts:
pointerdownfires on press;blurfireson focus loss. They are not the same moment, and they differ for keyboard
users (Tab commits under blur, never fires pointerdown) and for pointer
presses that never take focus. Any swap needs the commit semantics decided
deliberately, not assumed equivalent.
editors that actually spread
toDomPropsshould be enumerated rather thanassumed — a widget rendering a non-control root (
ObjectRefField's trigger,FileField's dropzone) hand-strips parts of the set already.If the answer is "keep the listener", the comment still wants correcting: it
states as fact that injected widgets have no blur handler, which is no longer
the reason the listener is needed.
Where
packages/components/src/renderers/complex/data-table.tsx— theinjectedEditorElRefdeclaration and thepointerdownlistener below it.packages/fields/src/widgets/toDomProps.ts— the whitelist that alreadyforwards
onBlur.Unassigned and ungraded on purpose — filed by the #6802 seat, which did not
have
packages/componentsin its file surface.