Skip to content

[SCF-2416] [Part 5] Replace ember-on-helper and ember-ref-bucket - #20

Open
Gaurav0 wants to merge 2 commits into
gaurav/chore/SCF-2416-part-4-node-20-embroider-util-forkfrom
gaurav/chore/SCF-2416-part-5-replace-on-helper-and-ref-bucket
Open

Gaurav0 wants to merge 2 commits into
gaurav/chore/SCF-2416-part-4-node-20-embroider-util-forkfrom
gaurav/chore/SCF-2416-part-5-replace-on-helper-and-ref-bucket

Conversation

@Gaurav0

@Gaurav0 Gaurav0 commented Nov 5, 2026 •

Copy link
Copy Markdown

Summary

Both addons depend on ember-cli-babel 7. ember-on-helper is unmaintained, and ember-ref-bucket was replaced upstream too. This is the main code change in the stack.

  • bs-on-document and bs-on-window replace ember-on-helper's on-document/on-window.
    • Both helpers share one classic Helper base, addon/utils/global-event-listener-helper.js. It adds the listener in compute, swaps it when the arguments change, and removes it in willDestroy.
    • Named arguments such as capture=true become listener options.
    • Targets without addEventListener are skipped, so BsModal's FastBoot guard and isFastBoot field are gone.
    • Used in bs-dropdown (3 sites) and bs-modal (1 site), and re-exported from app/.
  • Per-component track* modifiers replace {{create-ref}}. This is a hand port of upstream replace ember-ref-bucket with custom modifiers ember-bootstrap/ember-bootstrap#2270 (unreleased upstream, by Sander Knauff).
    • Each component gets a plain field and a modifier built with the new addon/utils/track-element.js, e.g. trackMainNode = trackElement(this, '_element').
    • 19 template sites change. The names match upstream.
    • Differences from upstream:
      • All the modifiers come from one shared helper.
      • { eager: false } avoids ember-modifier 3.2.7's deprecation.
      • BsModal's modalElement is @tracked, so scrollbarWidth is re-measured against a reopened modal's new element.

+378/−58 lines, not counting yarn.lock.

New tests:

  • Both helpers: they fire, tear down, swap on argument changes, and honor capture.
  • BsModal: a resize adjusts the padding, and so does reopening.
  • BsDropdown: once closed, it ignores outside clicks, Escape and Tab.
  • BsPopover and BsTooltip: clicking their own content doesn't close them.

Breaking changes (5.0.0 release notes)

  • {{create-ref}} is gone. It leaked into apps as an implicit app/ export of ember-ref-bucket. Apps that used it need to depend on ember-ref-bucket themselves.

Stack

Part of the SCF-2416 work (ember-bootstrap 5.0.0), split from scf-2416-rework for easier review. This is part 5 of 9. Stacked on Part 4: its base is gaurav/chore/SCF-2416-part-4-node-20-embroider-util-fork, so the diff only shows this part. Merge in order.

Part PR Title
1 #16 Drop Ember 3.28 and 4.4, bump to 5.0.0
2 #17 Upgrade test and lint tooling (ESLint 8, Prettier 3, ember-try 3, stylelint)
3 #18 Upgrade build dependencies and drop polyfills
4 #19 Require Node 20 and switch @embroider/util to a fork
5 this PR Replace ember-on-helper and ember-ref-bucket
6 #21 Upgrade addon dependencies off ember-cli-babel 7
7 #22 Keep Bootstrap 3 and subclassing, drop their deprecations
8 #23 ember-cli-update to the 5.4 addon blueprint
9 #24 Force and refresh remaining vulnerable dependencies

Review notes

Review the two commits separately. The ref-bucket commit message lists every difference from upstream ember-bootstrap#2270 and why. The BsModal @tracked modalElement change is the subtlest: an untracked field would trip Ember's mandatory-setter assertion, because @computed scrollbarWidth depends on it.

Testing

Run on this branch with Node 20.19.6: yarn install --frozen-lockfile passes, yarn lint reports 0 errors (the same 150 warnings as scf_master), and ember test (Ember 4.8, the default) has 550 passed, 9 skipped and 0 failed. +12 tests for the new helpers, BsModal, BsDropdown, BsPopover and BsTooltip. CI covers the ember-try matrix.

🤖 Generated with Claude Code

Gaurav0 and others added 2 commits November 5, 2026 09:02
ember-on-helper 0.1.0 depends on ember-cli-babel 7, and has had no
release since 2019 and no commits since January 2020, so it can't be
updated. Upstream ember-bootstrap still depends on it.

The new bs-on-document and bs-on-window helpers share one classic
Helper base class (utils/global-event-listener-helper). It adds the
listener in compute, removes the previous one with the same options
when the arguments change, and removes it in willDestroy. Named
arguments such as capture=true are passed as listener options.

ember-on-helper threw in FastBoot, which is why BsModal only rendered
on-window outside of it. The base class skips targets without
addEventListener (FastBoot's window has none), so that guard and the
modal's isFastBoot field are gone. The FastBoot modal test covers it.

Templates: bs-dropdown's three on-document calls and bs-modal's
on-window call use the bs- helpers. Both are re-exported from app/,
like bs-default.

New tests:
- both helpers: the callback fires, the listener is removed on
  teardown, and changing the event name or callback swaps it.
  capture=true catches events that stop propagation, and the
  capturing listener is removed with the same options.
- BsModal: a window resize adjusts the dialog padding (adjustDialog
  had no coverage).
- BsDropdown: once closed, outside clicks, Escape and Tab no longer
  call onHide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ember-ref-bucket 4.1.0 depends on ember-cli-babel 7. This ports
upstream ember-bootstrap ember-bootstrap#2270 ("replace ember-ref-bucket with custom
modifiers", by Sander Knauff, not yet released upstream) by hand,
since upstream is now TypeScript in a monorepo.

Each component that used @ref now has a plain field and a
function-based modifier that sets it, built by the new
addon/utils/track-element.js helper, e.g.

  trackMainNode = trackElement(this, '_element');

and its templates use {{this.trackMainNode}} instead of
{{create-ref "mainNode"}} (19 sites). The names match upstream:
trackMainNode, trackMenuElement, trackModalElement,
trackBackdropElement, trackOverlayElement and trackPopperElement.

Differences from upstream:
- The modifiers come from one shared helper rather than being written
  out in each component.
- trackElement passes { eager: false } to modifier(). ember-modifier
  3.2.7 (the version partners uses) deprecates function-based modifiers
  without it, and setupNoDeprecations turns that into a test failure.
  4.x ignores the option.
- BsModal's modalElement is @Tracked. It is a dependency of the
  @computed scrollbarWidth, so a plain assignment on reopen would trip
  Ember's DEBUG mandatory-setter assertion. ref-bucket's untracked
  getter meant scrollbarWidth was never invalidated; now it is
  re-measured against the new element.
- bs-form has no create-ref in this fork, so there is no
  trackFormElement.

popperElement stays tracked (was @trackedRef), as upstream. The other
fields were untracked getters before and are plain fields now; the
classic components only read them from JS, so no set() is needed.
The refs on child components (BsModal's dialog, the contextual-help
overlay) still work because the modifier reaches the child's element
through ...attributes.

ember-ref-bucket's {{create-ref}} modifier leaked into apps as an
implicit app/ export; it is gone now (release notes).

New tests:
- BsModal: after closing and reopening, the padding is measured
  against the new .modal element, on show and on resize.
- BsPopover and BsTooltip, rendered in place with click triggers:
  clicking their own content doesn't close them (overlayElement via
  ...attributes), clicking the trigger does.
All three fail with modalElement untracked or overlayElement unset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant