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');