diff --git a/docs/.eslintrc.js b/docs/.eslintrc.js
index 3f2e6510..121ac75c 100644
--- a/docs/.eslintrc.js
+++ b/docs/.eslintrc.js
@@ -15,9 +15,7 @@ module.exports = {
env: {
browser: true,
},
- rules: {
- 'ember/no-runloop': 0,
- },
+ rules: {},
overrides: [
// ts files
{
diff --git a/docs/app/components/snippets/content-events-1.js b/docs/app/components/snippets/content-events-1.js
index 08f3073d..c2255a63 100644
--- a/docs/app/components/snippets/content-events-1.js
+++ b/docs/app/components/snippets/content-events-1.js
@@ -1,6 +1,6 @@
import Component from '@glimmer/component';
import { action } from '@ember/object';
-import { later, cancel } from '@ember/runloop';
+import { runTask, cancelTask } from 'ember-lifeline';
export default class extends Component {
notifications = [
@@ -18,7 +18,7 @@ export default class extends Component {
@action
open(dropdown) {
if (this.closeTimer) {
- cancel(this.closeTimer);
+ cancelTask(this, this.closeTimer);
this.closeTimer = null;
} else {
dropdown.actions.open();
@@ -27,9 +27,13 @@ export default class extends Component {
@action
closeLater(dropdown) {
- this.closeTimer = later(() => {
- this.closeTimer = null;
- dropdown.actions.close();
- }, 200);
+ this.closeTimer = runTask(
+ this,
+ () => {
+ this.closeTimer = null;
+ dropdown.actions.close();
+ },
+ 200,
+ );
}
}
diff --git a/docs/app/controllers/public-pages/docs/content-events.js b/docs/app/controllers/public-pages/docs/content-events.js
index 8dc37d97..9435e238 100644
--- a/docs/app/controllers/public-pages/docs/content-events.js
+++ b/docs/app/controllers/public-pages/docs/content-events.js
@@ -1,5 +1,5 @@
import Controller from '@ember/controller';
-import { later, cancel } from '@ember/runloop';
+import { runTask, cancelTask } from 'ember-lifeline';
import { action } from '@ember/object';
import ContentEvents1Component from '../../../components/snippets/content-events-1';
@@ -20,7 +20,7 @@ export default class extends Controller {
@action
open(dropdown) {
if (this.closeTimer) {
- cancel(this.closeTimer);
+ cancelTask(this, this.closeTimer);
this.closeTimer = null;
} else {
dropdown.actions.open();
@@ -29,9 +29,13 @@ export default class extends Controller {
@action
closeLater(dropdown) {
- this.closeTimer = later(() => {
- this.closeTimer = null;
- dropdown.actions.close();
- }, 200);
+ this.closeTimer = runTask(
+ this,
+ () => {
+ this.closeTimer = null;
+ dropdown.actions.close();
+ },
+ 200,
+ );
}
}
diff --git a/docs/package.json b/docs/package.json
index 0f98dcf4..3eb0cc7d 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -89,6 +89,7 @@
"ember-code-snippet": "git://github.com/ef4/ember-code-snippet.git#d054b697098ad52481c94a952ccf8d89ba1f25fe",
"ember-concurrency": "^4.0.2",
"ember-fetch": "^8.1.2",
+ "ember-lifeline": "^7.0.0",
"ember-load-initializers": "^2.1.2",
"ember-modifier": "^4.1.0",
"ember-page-title": "^8.2.3",
diff --git a/ember-basic-dropdown/.eslintrc.cjs b/ember-basic-dropdown/.eslintrc.cjs
index 1cbe8633..3ceee093 100644
--- a/ember-basic-dropdown/.eslintrc.cjs
+++ b/ember-basic-dropdown/.eslintrc.cjs
@@ -15,9 +15,7 @@ module.exports = {
env: {
browser: true,
},
- rules: {
- 'ember/no-runloop': 0,
- },
+ rules: {},
overrides: [
// ts files
{
diff --git a/ember-basic-dropdown/package.json b/ember-basic-dropdown/package.json
index 9b6617a7..625eb132 100644
--- a/ember-basic-dropdown/package.json
+++ b/ember-basic-dropdown/package.json
@@ -72,6 +72,7 @@
"decorator-transforms": "^1.1.0",
"ember-element-helper": "^0.8.6",
"ember-modifier": "^4.1.0",
+ "ember-lifeline": "^7.0.0",
"ember-style-modifier": "^4.3.1",
"ember-truth-helpers": "^4.0.3"
},
diff --git a/ember-basic-dropdown/src/components/basic-dropdown-content.ts b/ember-basic-dropdown/src/components/basic-dropdown-content.ts
index 91ab2dae..47a07ddd 100644
--- a/ember-basic-dropdown/src/components/basic-dropdown-content.ts
+++ b/ember-basic-dropdown/src/components/basic-dropdown-content.ts
@@ -1,7 +1,6 @@
import { action } from '@ember/object';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
-import { join } from '@ember/runloop';
import { getScrollParent } from '../utils/calculate-position.ts';
import {
distributeScroll,
@@ -12,6 +11,7 @@ import hasMoved from '../utils/has-moved.ts';
import { isTesting } from '@embroider/macros';
import { modifier } from 'ember-modifier';
import type { Dropdown } from './basic-dropdown.ts';
+import { runTask } from 'ember-lifeline';
export interface BasicDropdownContentSignature {
Element: Element;
@@ -398,7 +398,13 @@ export default class BasicDropdownContent extends Component {
+ if (!this.args.dropdown) {
+ return;
+ }
+
+ this.args.dropdown.actions.reposition();
+ });
}
@action
diff --git a/ember-basic-dropdown/src/components/basic-dropdown.ts b/ember-basic-dropdown/src/components/basic-dropdown.ts
index 40caac01..7ecb0cc4 100644
--- a/ember-basic-dropdown/src/components/basic-dropdown.ts
+++ b/ember-basic-dropdown/src/components/basic-dropdown.ts
@@ -2,6 +2,7 @@ import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { guidFor } from '@ember/object/internals';
+import { scheduleTask } from 'ember-lifeline';
import calculatePosition from '../utils/calculate-position.ts';
import type {
CalculatePosition,
@@ -9,7 +10,6 @@ import type {
HorizontalPosition,
VerticalPosition,
} from '../utils/calculate-position.ts';
-import { schedule } from '@ember/runloop';
import { getOwner } from '@ember/application';
import type Owner from '@ember/owner';
import type { ComponentLike } from '@glint/template';
@@ -162,7 +162,7 @@ export default class BasicDropdown extends Component {
this._previousDisabled !== UNINITIALIZED &&
this._previousDisabled !== newVal
) {
- schedule('actions', () => {
+ scheduleTask(this, 'actions', () => {
if (newVal && this.publicAPI.isOpen) {
// eslint-disable-next-line ember/no-side-effects
this.isOpen = false;
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a869d720..675589bf 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -216,6 +216,9 @@ importers:
ember-fetch:
specifier: ^8.1.2
version: 8.1.2
+ ember-lifeline:
+ specifier: ^7.0.0
+ version: 7.0.0(@ember/test-helpers@3.3.0)
ember-load-initializers:
specifier: ^2.1.2
version: 2.1.2(@babel/core@7.24.5)
@@ -330,6 +333,9 @@ importers:
ember-element-helper:
specifier: ^0.8.6
version: 0.8.6(@glint/environment-ember-loose@1.4.0)(@glint/template@1.4.0)(ember-source@5.8.0)
+ ember-lifeline:
+ specifier: ^7.0.0
+ version: 7.0.0(@ember/test-helpers@3.3.0)
ember-modifier:
specifier: ^4.1.0
version: 4.1.0(ember-source@5.8.0)
@@ -658,6 +664,9 @@ importers:
ember-fetch:
specifier: ^8.1.2
version: 8.1.2
+ ember-lifeline:
+ specifier: ^7.0.0
+ version: 7.0.0(@ember/test-helpers@3.3.0)
ember-load-initializers:
specifier: ^2.1.2
version: 2.1.2(@babel/core@7.24.5)
@@ -2089,7 +2098,6 @@ packages:
- '@glint/template'
- supports-color
- webpack
- dev: true
/@ember/test-waiters@3.1.0:
resolution: {integrity: sha512-bb9h95ktG2wKY9+ja1sdsFBdOms2lB19VWs8wmNpzgHv1NCetonBoV5jHBV4DHt0uS1tg9z66cZqhUVlYs96KQ==}
@@ -2101,7 +2109,6 @@ packages:
semver: 7.6.0
transitivePeerDependencies:
- supports-color
- dev: true
/@embroider/addon-dev@4.3.1(@glint/template@1.4.0)(rollup@4.17.2):
resolution: {integrity: sha512-CNZ4Y69PPIZAAGGoERjvDcrwOwWTuUmnRYu+XnmqKk0opdlu/PTssO9YWyxp8AnvGd2l7iLCjEn5mpLFvifstA==}
@@ -6977,7 +6984,6 @@ packages:
/dom-element-descriptors@0.5.0:
resolution: {integrity: sha512-CVzntLid1oFVHTKdTp/Qu7Kz+wSm8uO30TSQyAJ6n4Dz09yTzVQn3S1oRhVhUubxdMuKs1DjDqt88pubHagbPw==}
- dev: true
/dom-serializer@1.4.1:
resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
@@ -7803,6 +7809,20 @@ packages:
- supports-color
dev: false
+ /ember-lifeline@7.0.0(@ember/test-helpers@3.3.0):
+ resolution: {integrity: sha512-2l51NzgH5vjN972zgbs+32rnXnnEFKB7qsSpJF+lBI4V5TG6DMy4SfowC72ZEuAtS58OVfwITbOO+RnM21EdpA==}
+ engines: {node: 16.* || >= 18}
+ peerDependencies:
+ '@ember/test-helpers': '>= 1.0.0'
+ peerDependenciesMeta:
+ '@ember/test-helpers':
+ optional: true
+ dependencies:
+ '@ember/test-helpers': 3.3.0(@glint/template@1.4.0)(ember-source@5.8.0)(webpack@5.91.0)
+ '@embroider/addon-shim': 1.8.7
+ transitivePeerDependencies:
+ - supports-color
+
/ember-load-initializers@2.1.2(@babel/core@7.24.5):
resolution: {integrity: sha512-CYR+U/wRxLbrfYN3dh+0Tb6mFaxJKfdyz+wNql6cqTrA0BBi9k6J3AaKXj273TqvEpyyXegQFFkZEiuZdYtgJw==}
engines: {node: 6.* || 8.* || >= 10.*}
diff --git a/test-app/.eslintrc.js b/test-app/.eslintrc.js
index 15a3dd03..0c32c9a2 100644
--- a/test-app/.eslintrc.js
+++ b/test-app/.eslintrc.js
@@ -15,9 +15,7 @@ module.exports = {
env: {
browser: true,
},
- rules: {
- 'ember/no-runloop': 0,
- },
+ rules: {},
overrides: [
// ts files
{
diff --git a/test-app/package.json b/test-app/package.json
index 2e4810e4..919cc465 100644
--- a/test-app/package.json
+++ b/test-app/package.json
@@ -80,6 +80,7 @@
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",
"ember-fetch": "^8.1.2",
+ "ember-lifeline": "^7.0.0",
"ember-load-initializers": "^2.1.2",
"ember-modifier": "^4.1.0",
"ember-page-title": "^8.2.3",
diff --git a/test-app/tests/integration/components/basic-dropdown-test.js b/test-app/tests/integration/components/basic-dropdown-test.js
index 46b812ce..89574db9 100644
--- a/test-app/tests/integration/components/basic-dropdown-test.js
+++ b/test-app/tests/integration/components/basic-dropdown-test.js
@@ -1,4 +1,4 @@
-import { run, scheduleOnce } from '@ember/runloop';
+import { scheduleTask } from 'ember-lifeline';
import { registerDeprecationHandler } from '@ember/debug';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
@@ -10,6 +10,7 @@ import {
triggerEvent,
waitUntil,
find,
+ settled,
} from '@ember/test-helpers';
let deprecations = [];
@@ -663,7 +664,7 @@ module('Integration | Component | basic-dropdown', function (hooks) {
assert
.dom('#dropdown-is-opened', this.element.getRootNode())
.exists('The select is open');
- run(() => this.set('isDisabled', true));
+ this.set('isDisabled', true);
assert
.dom('#dropdown-is-opened', this.element.getRootNode())
.doesNotExist('The select is now closed');
@@ -675,7 +676,7 @@ module('Integration | Component | basic-dropdown', function (hooks) {
this.isDisabled = false;
this.toggleDisabled = () => this.toggleProperty('isDisabled');
this.registerAPI = (api) =>
- scheduleOnce('actions', this, this.set, 'remoteController', api);
+ scheduleTask(this, 'actions', () => this.set('remoteController', api));
await render(hbs`
Click me
@@ -692,11 +693,11 @@ module('Integration | Component | basic-dropdown', function (hooks) {
assert
.dom('#is-disabled', this.element.getRootNode())
.doesNotExist('The select is enabled');
- run(() => this.set('isDisabled', true));
+ this.set('isDisabled', true);
assert
.dom('#is-disabled', this.element.getRootNode())
.exists('The select is disabled');
- run(() => this.set('isDisabled', false));
+ this.set('isDisabled', false);
assert
.dom('#is-disabled', this.element.getRootNode())
.doesNotExist('The select is enabled again');
@@ -805,9 +806,7 @@ module('Integration | Component | basic-dropdown', function (hooks) {
this.element.getRootNode().querySelector('.ember-basic-dropdown-trigger'),
);
- run(() => {
- returnValue = remoteController.actions.reposition();
- });
+ returnValue = remoteController.actions.reposition();
assert.ok(Object.prototype.hasOwnProperty.call(returnValue, 'hPosition'));
assert.ok(Object.prototype.hasOwnProperty.call(returnValue, 'vPosition'));
assert.ok(Object.prototype.hasOwnProperty.call(returnValue, 'top'));
@@ -1337,9 +1336,9 @@ module('Integration | Component | basic-dropdown', function (hooks) {
'The style attribute is the expected one',
);
- run(() => {
- publicApi.actions.reposition();
- });
+ publicApi.actions.reposition();
+
+ await settled();
assert
.dom('.ember-basic-dropdown-content', this.element.getRootNode())
diff --git a/test-app/tests/integration/components/content-test.js b/test-app/tests/integration/components/content-test.js
index 7eaa76bf..67dc8851 100644
--- a/test-app/tests/integration/components/content-test.js
+++ b/test-app/tests/integration/components/content-test.js
@@ -1,9 +1,8 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
+import { runTask } from 'ember-lifeline';
import { hbs } from 'ember-cli-htmlbars';
-import { run } from '@ember/runloop';
-import { render, click, triggerEvent } from '@ember/test-helpers';
-import settled from '@ember/test-helpers/settled';
+import { render, click, triggerEvent, settled } from '@ember/test-helpers';
module('Integration | Component | basic-dropdown-content', function (hooks) {
setupRenderingTest(hooks);
@@ -433,7 +432,7 @@ module('Integration | Component | basic-dropdown-content', function (hooks) {
cancelable: true,
bubbles: true,
});
- run(() => innerScrollable.dispatchEvent(innerScrollableEvent));
+ innerScrollable.dispatchEvent(innerScrollableEvent);
assert.false(
innerScrollableEvent.defaultPrevented,
'The inner scrollable does not cancel wheel events.',
@@ -445,7 +444,7 @@ module('Integration | Component | basic-dropdown-content', function (hooks) {
cancelable: true,
bubbles: true,
});
- run(() => innerScrollable.dispatchEvent(innerScrollableCanceledEvent));
+ innerScrollable.dispatchEvent(innerScrollableCanceledEvent);
assert.true(
innerScrollableCanceledEvent.defaultPrevented,
'The inner scrollable cancels out of bound wheel events.',
@@ -464,7 +463,7 @@ module('Integration | Component | basic-dropdown-content', function (hooks) {
cancelable: true,
bubbles: true,
});
- run(() => outerScrollable.dispatchEvent(outerScrollableEvent));
+ outerScrollable.dispatchEvent(outerScrollableEvent);
assert.true(
outerScrollableEvent.defaultPrevented,
'The outer scrollable cancels wheel events.',
@@ -487,7 +486,8 @@ module('Integration | Component | basic-dropdown-content', function (hooks) {
Lorem ipsum
`);
- run(() => window.dispatchEvent(new window.Event('scroll')));
+ window.dispatchEvent(new window.Event('scroll'));
+ await settled();
assert.strictEqual(
repositions,
2,
@@ -511,7 +511,8 @@ module('Integration | Component | basic-dropdown-content', function (hooks) {
Lorem ipsum
`);
- run(() => window.dispatchEvent(new window.Event('resize')));
+ window.dispatchEvent(new window.Event('resize'));
+ await settled();
assert.strictEqual(
repositions,
2,
@@ -535,7 +536,8 @@ module('Integration | Component | basic-dropdown-content', function (hooks) {
Lorem ipsum
`);
- run(() => window.dispatchEvent(new window.Event('orientationchange')));
+ window.dispatchEvent(new window.Event('orientationchange'));
+ await settled();
assert.strictEqual(
repositions,
2,
@@ -561,7 +563,7 @@ module('Integration | Component | basic-dropdown-content', function (hooks) {
`);
- await run(() => {
+ await runTask(this, () => {
let target = this.element
.getRootNode()
.querySelector('#content-target-div');
@@ -593,7 +595,7 @@ module('Integration | Component | basic-dropdown-content', function (hooks) {
{{/if}}
`);
- await run(() => {
+ await runTask(this, () => {
this.set('divVisible', true);
});
await settled();
@@ -629,7 +631,7 @@ module('Integration | Component | basic-dropdown-content', function (hooks) {
`);
- run(() => {
+ runTask(this, () => {
let target = this.element
.getRootNode()
.querySelector('#content-target-div');
@@ -654,7 +656,8 @@ module('Integration | Component | basic-dropdown-content', function (hooks) {
Lorem ipsum
`);
- run(() => window.dispatchEvent(new window.Event('scroll')));
+ window.dispatchEvent(new window.Event('scroll'));
+ await settled();
assert.strictEqual(
repositions,
2,
@@ -679,7 +682,7 @@ module('Integration | Component | basic-dropdown-content', function (hooks) {
assert
.dom('.ember-basic-dropdown-overlay', this.element.getRootNode())
.exists('There is one overlay');
- run(this, 'set', 'dropdown.isOpen', false);
+ this.set('dropdown.isOpen', false);
assert
.dom('.ember-basic-dropdown-overlay', this.element.getRootNode())
.doesNotExist('There is no overlay when closed');