Skip to content

feat: Add signal-based binding support to ObserverMap and TemplateElement#7306

Open
radium-v wants to merge 5 commits intomainfrom
users/radium-v/observer-map-signal
Open

feat: Add signal-based binding support to ObserverMap and TemplateElement#7306
radium-v wants to merge 5 commits intomainfrom
users/radium-v/observer-map-signal

Conversation

@radium-v
Copy link
Collaborator

@radium-v radium-v commented Mar 6, 2026

Pull Request

📖 Description

Replace the Observable.notify-based change propagation in fast-html's Observer Map and template binding system with Signal-based pub/sub from @microsoft/fast-element/binding/signal.js.

The Observer Map feature previously relied on Observable.notify(target, property) to inform bindings of deep property changes in proxied objects. This approach coupled change detection to the Observable property accessor system, which wasn't designed for the proxy-mediated, deeply-nested data patterns used in Declarative Shadow DOM templates.

This PR introduces a Signal-based notification model that follows the patterns established by the SignalBinding module in fast-element:

  • Each element instance gets a unique signal channel (fh:<id>) via a WeakMap
  • A hybrid ObserverMapObserver combines Signal subscriptions (for deep proxy changes) with standard Observable.binding expression watching (for direct property access like array items)
  • ObserverMapBinding extends the Binding base class and supports multi-signal subscriptions for nested repeat contexts
  • Proxy set traps and ObserverMap.defineChanged handlers now broadcast via Signal.send instead of Observable.notify

The public API (TemplateElement.options, ObserverMap, template syntax) is unchanged — developers use observer maps and observables in DSD exactly as before.

👩‍💻 Reviewer Notes

  • The ObserverMapObserver is the central new abstraction — it's worth reviewing its dual-subscription model (Signal + Observable expression watcher) to ensure correctness across all binding contexts.
  • Repeat data bindings intentionally remain plain functions (not signal bindings) to avoid double-rendering conflicts with the repeat's internal array observation.
  • notifyObservables now walks up the target chain recursively so nested proxies ultimately signal the owning element.

📑 Test Plan

All existing Playwright fixture tests pass across Chromium, Firefox, and WebKit (336 tests). No new tests were added — the existing observer-map, deep-merge, and other fixture tests validate the behavioral equivalence of the Signal-based approach.

✅ Checklist

General

  • I have included a change request file using $ npm run change
  • I have added tests for my changes.
  • I have tested my changes.
  • I have updated the project documentation to reflect my changes.
  • I have read the CONTRIBUTING documentation and followed the standards for this project.

@radium-v radium-v force-pushed the users/radium-v/observer-map-signal branch from d9d0666 to 863f330 Compare March 6, 2026 22:29
@radium-v radium-v force-pushed the users/radium-v/observer-map-signal branch from 863f330 to 1d10b3b Compare March 9, 2026 22:36
@radium-v radium-v marked this pull request as ready for review March 9, 2026 22:37
Copy link
Collaborator

@janechu janechu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's check on the performance on this change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants