Summary
ctx.observe(rootElement) does not attach interaction listeners when rootElement itself has data-askable. Only annotated descendants are attached, so clicking/focusing the annotated root leaves context focus empty.
Root cause
packages/core/src/observer.ts resolves the root and calls:
rootEl.querySelectorAll<HTMLElement>('[data-askable]').forEach((el) => this.attach(el));
querySelectorAll() only returns descendants, not rootEl itself.
Verified reproduction
Against main at 40a3374:
- Create a button with
data-askable='{"id":"root"}'.
- Call
ctx.observe(button, { events: ['click'] }).
- Click the button.
ctx.getFocus() remains null.
Observed output:
Proposed fix
When the root is an HTMLElement, attach it first if it has data-askable, then scan descendants. Preserve the existing Document behavior.
Also verify attribute mutation behavior when an observed root gains or loses data-askable after observation.
Acceptance criteria
Summary
ctx.observe(rootElement)does not attach interaction listeners whenrootElementitself hasdata-askable. Only annotated descendants are attached, so clicking/focusing the annotated root leaves context focus empty.Root cause
packages/core/src/observer.tsresolves the root and calls:querySelectorAll()only returns descendants, notrootElitself.Verified reproduction
Against
mainat40a3374:data-askable='{"id":"root"}'.ctx.observe(button, { events: ['click'] }).ctx.getFocus()remainsnull.Observed output:
{"focus":null}Proposed fix
When the root is an
HTMLElement, attach it first if it hasdata-askable, then scan descendants. Preserve the existingDocumentbehavior.Also verify attribute mutation behavior when an observed root gains or loses
data-askableafter observation.Acceptance criteria
HTMLElementpassed directly toobserve()is interactivedata-askableon the observed root updates listener stateunobserve()detaches the root listener