From 0c94b171aa98d11643a9c1490c73be0fa7b40105 Mon Sep 17 00:00:00 2001 From: Markus Sanin Date: Sun, 30 Nov 2025 17:41:07 +0100 Subject: [PATCH 1/5] Add `setConfig` and deprecate passing config over `environment` --- docs/app/app.ts | 6 +- ember-basic-dropdown/rollup.config.mjs | 1 + .../components/basic-dropdown-wormhole.gts | 40 +++++++--- .../src/components/basic-dropdown.gts | 76 ++++++++++++++----- ember-basic-dropdown/src/config.ts | 16 ++++ test-app/app/app.ts | 7 ++ .../basic-dropdown-wormhole-test.ts | 20 ++--- 7 files changed, 124 insertions(+), 42 deletions(-) create mode 100644 ember-basic-dropdown/src/config.ts diff --git a/docs/app/app.ts b/docs/app/app.ts index 1704a816..db597763 100644 --- a/docs/app/app.ts +++ b/docs/app/app.ts @@ -3,13 +3,17 @@ import Resolver from 'ember-resolver'; import loadInitializers from 'ember-load-initializers'; import config from './config/environment'; import { importSync, isDevelopingApp, macroCondition } from '@embroider/macros'; - import compatModules from '@embroider/virtual/compat-modules'; +import { setConfig } from 'ember-basic-dropdown/config'; if (macroCondition(isDevelopingApp())) { importSync('./deprecation-workflow'); } +setConfig({ + rootElement: config.APP['rootElement'] as string | undefined +}); + export default class App extends Application { modulePrefix = config.modulePrefix; podModulePrefix = config.podModulePrefix; diff --git a/ember-basic-dropdown/rollup.config.mjs b/ember-basic-dropdown/rollup.config.mjs index 44fe1a9d..fe765b9e 100644 --- a/ember-basic-dropdown/rollup.config.mjs +++ b/ember-basic-dropdown/rollup.config.mjs @@ -54,6 +54,7 @@ export default [ // See https://github.com/embroider-build/embroider/blob/main/docs/v2-faq.md#how-can-i-define-the-public-exports-of-my-addon addon.publicEntrypoints([ 'index.js', + 'config.js', 'styles.js', 'components/**/*.js', 'modifiers/**/*.js', diff --git a/ember-basic-dropdown/src/components/basic-dropdown-wormhole.gts b/ember-basic-dropdown/src/components/basic-dropdown-wormhole.gts index 5a77b627..45242cc9 100644 --- a/ember-basic-dropdown/src/components/basic-dropdown-wormhole.gts +++ b/ember-basic-dropdown/src/components/basic-dropdown-wormhole.gts @@ -1,5 +1,7 @@ import Component from '@glimmer/component'; import { getOwner } from '@ember/application'; +import { config as utilConfig, _configSet, type Config } from '../config.ts'; +import { deprecate } from '@ember/debug'; export interface BasicDropdownWormholeSignature { Element: HTMLElement; @@ -7,18 +9,38 @@ export interface BasicDropdownWormholeSignature { export default class BasicDropdownWormholeComponent extends Component { get getDestinationId(): string { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - const config = getOwner(this).resolveRegistration('config:environment') as { - 'ember-basic-dropdown'?: { - destination?: string; + let config = utilConfig; + + if (!_configSet) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + const configEnvironment = getOwner(this).resolveRegistration('config:environment') as { + 'ember-basic-dropdown'?: Config; }; - }; + + if (configEnvironment['ember-basic-dropdown']) { + const legacyConfigString = JSON.stringify(configEnvironment['ember-basic-dropdown']); + deprecate( + `You have configured \`ember-basic-dropdown\` in \`ember-cli-build.js\`. Remove that configuration and instead use \`import { setConfig } from 'ember-basic-dropdown/config'; setConfig(${legacyConfigString});`, + false, + { + for: 'ember-basic-dropdown', + id: 'ember-basic-dropdown.config-environment', + since: { + enabled: '8.9', + available: '8.9', + }, + until: '9.0.0', + }, + ); + + config = configEnvironment['ember-basic-dropdown']; + } + } return ( - (config['ember-basic-dropdown'] && - config['ember-basic-dropdown'].destination) || + config.destination || 'ember-basic-dropdown-wormhole' ); } diff --git a/ember-basic-dropdown/src/components/basic-dropdown.gts b/ember-basic-dropdown/src/components/basic-dropdown.gts index 3a4bb432..fd3a01be 100644 --- a/ember-basic-dropdown/src/components/basic-dropdown.gts +++ b/ember-basic-dropdown/src/components/basic-dropdown.gts @@ -27,6 +27,8 @@ import type { TRootEventType, } from '../types.ts'; import { deprecate } from '@ember/debug'; +import { isTesting } from '@embroider/macros'; +import { config as utilConfig, _configSet, type Config } from '../config.ts'; // To avoid breaking the current types export we need this export type { Dropdown, DropdownActions, TRootEventType }; @@ -393,20 +395,58 @@ export default class BasicDropdown extends Component { } _getDestinationId(): string { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - const config = getOwner(this).resolveRegistration('config:environment') as { - environment: string; - APP: { - rootElement: string; + let config = utilConfig; + + if (!_configSet) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + const configEnvironment = getOwner(this).resolveRegistration('config:environment') as { + APP: { + rootElement: string; + }; + 'ember-basic-dropdown': Config; }; - 'ember-basic-dropdown': { - destination: string; - }; - }; - if (config.environment === 'test') { + if (configEnvironment['ember-basic-dropdown']) { + const legacyConfigString = JSON.stringify(configEnvironment['ember-basic-dropdown']); + deprecate( + `You have configured \`ember-basic-dropdown\` in \`ember-cli-build.js\`. Remove that configuration and instead use \`import { setConfig } from 'ember-basic-dropdown/config'; setConfig(${legacyConfigString});`, + false, + { + for: 'ember-basic-dropdown', + id: 'ember-basic-dropdown.config-environment', + since: { + enabled: '8.9', + available: '8.9', + }, + until: '9.0.0', + }, + ); + + config = configEnvironment['ember-basic-dropdown']; + } + + if (configEnvironment['APP']?.rootElement) { + deprecate( + `ember-basic-dropdown received the \`APP.rootElement\` value from \`ember-cli-build.js\`. You now need to pass this value using \`import { setConfig } from 'ember-basic-dropdown/config'; setConfig({rootElement: config.APP['rootElement']});`, + false, + { + for: 'ember-basic-dropdown', + id: 'ember-basic-dropdown.config-environment', + since: { + enabled: '8.9', + available: '8.9', + }, + until: '9.0.0', + }, + ); + + config.rootElement = configEnvironment['APP']?.rootElement; + } + } + + if (isTesting()) { // document doesn't exist in fastboot apps, for this reason we need this check if (typeof document === 'undefined') { return 'ember-basic-dropdown-wormhole'; @@ -414,10 +454,9 @@ export default class BasicDropdown extends Component { // check if destination exists in tests: if ( - config['ember-basic-dropdown'] && - config['ember-basic-dropdown'].destination + config.destination ) { - const destination = config['ember-basic-dropdown'].destination; + const destination = config.destination; if (document.getElementById(destination) !== null) { return destination; } @@ -429,16 +468,15 @@ export default class BasicDropdown extends Component { } // fall back to rootElement as destination - const rootElement = config['APP']?.rootElement; + const rootElement = config.rootElement; return ( - document.querySelector(rootElement)?.id ?? + (rootElement ? document.querySelector(rootElement)?.id : undefined) ?? 'ember-basic-dropdown-wormhole' ); } return ( - (config['ember-basic-dropdown'] && - config['ember-basic-dropdown'].destination) || + config.destination || 'ember-basic-dropdown-wormhole' ); } diff --git a/ember-basic-dropdown/src/config.ts b/ember-basic-dropdown/src/config.ts new file mode 100644 index 00000000..e0eb9fd0 --- /dev/null +++ b/ember-basic-dropdown/src/config.ts @@ -0,0 +1,16 @@ +export interface Config { + destination?: string; + rootElement?: string; +} + +let _config: Config = {}; + +// This will be removed in next major, don't use this outside the package! +let _configSet = false; + +export function setConfig(config: Config) { + _config = config; + _configSet = true; +} + +export { _config as config, _configSet }; diff --git a/test-app/app/app.ts b/test-app/app/app.ts index 9ef983e2..e467d155 100644 --- a/test-app/app/app.ts +++ b/test-app/app/app.ts @@ -3,11 +3,18 @@ import Resolver from 'ember-resolver'; import loadInitializers from 'ember-load-initializers'; import config from 'test-app/config/environment'; import { importSync, isDevelopingApp, macroCondition } from '@embroider/macros'; +import { setConfig, type Config } from 'ember-basic-dropdown/config'; if (macroCondition(isDevelopingApp())) { importSync('./deprecation-workflow'); } +export const defaultBasicDropdownConfig: Config = { + rootElement: config.APP['rootElement'] as string | undefined +} + +setConfig(defaultBasicDropdownConfig); + export default class App extends Application { modulePrefix = config.modulePrefix; podModulePrefix = config.podModulePrefix; diff --git a/test-app/tests/integration/components/basic-dropdown-wormhole-test.ts b/test-app/tests/integration/components/basic-dropdown-wormhole-test.ts index 42ec1fb3..2b5202ff 100644 --- a/test-app/tests/integration/components/basic-dropdown-wormhole-test.ts +++ b/test-app/tests/integration/components/basic-dropdown-wormhole-test.ts @@ -2,12 +2,12 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import { hbs } from 'ember-cli-htmlbars'; import { render } from '@ember/test-helpers'; -import config from 'test-app/config/environment'; +import { setConfig } from 'ember-basic-dropdown/config'; +import { defaultBasicDropdownConfig } from 'test-app/app'; import type { TestContext } from '@ember/test-helpers'; interface ExtendedTestContext extends TestContext { element: HTMLElement; - originalConfig: Record; } function getRootNode(element: Element): HTMLElement { @@ -17,15 +17,8 @@ function getRootNode(element: Element): HTMLElement { module('Integration | Component | basic-dropdown-wormhole', function (hooks) { setupRenderingTest(hooks); - hooks.beforeEach(function (this: ExtendedTestContext) { - // Duplicate config to avoid mutating global config - this.originalConfig = JSON.parse( - JSON.stringify(config['ember-basic-dropdown'] || {}), - ) as Record; - }); - hooks.afterEach(function (this: ExtendedTestContext) { - config['ember-basic-dropdown'] = this.originalConfig; + setConfig(defaultBasicDropdownConfig); }); test('Is present', async function (assert) { @@ -39,9 +32,10 @@ module('Integration | Component | basic-dropdown-wormhole', function (hooks) { }); test('Uses custom destination from config if present', async function (assert) { - config['ember-basic-dropdown'] = { - destination: 'custom-wormhole-destination', - }; + setConfig({ + ...defaultBasicDropdownConfig, + destination: 'custom-wormhole-destination' + }); await render(hbs``); From a8e20b977b5db4d0a0768f9b56737b3e13b094fd Mon Sep 17 00:00:00 2001 From: Markus Sanin Date: Sun, 30 Nov 2025 18:09:28 +0100 Subject: [PATCH 2/5] Fix lint --- docs/app/app.ts | 2 +- .../src/components/basic-dropdown-wormhole.gts | 13 +++++++------ .../src/components/basic-dropdown.gts | 17 ++++++++--------- test-app/app/app.ts | 4 ++-- .../components/basic-dropdown-wormhole-test.ts | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/app/app.ts b/docs/app/app.ts index db597763..ec7a2089 100644 --- a/docs/app/app.ts +++ b/docs/app/app.ts @@ -11,7 +11,7 @@ if (macroCondition(isDevelopingApp())) { } setConfig({ - rootElement: config.APP['rootElement'] as string | undefined + rootElement: config.APP['rootElement'] as string | undefined, }); export default class App extends Application { diff --git a/ember-basic-dropdown/src/components/basic-dropdown-wormhole.gts b/ember-basic-dropdown/src/components/basic-dropdown-wormhole.gts index 45242cc9..1b6437ba 100644 --- a/ember-basic-dropdown/src/components/basic-dropdown-wormhole.gts +++ b/ember-basic-dropdown/src/components/basic-dropdown-wormhole.gts @@ -15,12 +15,16 @@ export default class BasicDropdownWormholeComponent extends Component diff --git a/ember-basic-dropdown/src/components/basic-dropdown.gts b/ember-basic-dropdown/src/components/basic-dropdown.gts index fd3a01be..e5930378 100644 --- a/ember-basic-dropdown/src/components/basic-dropdown.gts +++ b/ember-basic-dropdown/src/components/basic-dropdown.gts @@ -401,7 +401,9 @@ export default class BasicDropdown extends Component { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unsafe-call - const configEnvironment = getOwner(this).resolveRegistration('config:environment') as { + const configEnvironment = getOwner(this).resolveRegistration( + 'config:environment', + ) as { APP: { rootElement: string; }; @@ -409,7 +411,9 @@ export default class BasicDropdown extends Component { }; if (configEnvironment['ember-basic-dropdown']) { - const legacyConfigString = JSON.stringify(configEnvironment['ember-basic-dropdown']); + const legacyConfigString = JSON.stringify( + configEnvironment['ember-basic-dropdown'], + ); deprecate( `You have configured \`ember-basic-dropdown\` in \`ember-cli-build.js\`. Remove that configuration and instead use \`import { setConfig } from 'ember-basic-dropdown/config'; setConfig(${legacyConfigString});`, false, @@ -453,9 +457,7 @@ export default class BasicDropdown extends Component { } // check if destination exists in tests: - if ( - config.destination - ) { + if (config.destination) { const destination = config.destination; if (document.getElementById(destination) !== null) { return destination; @@ -475,10 +477,7 @@ export default class BasicDropdown extends Component { ); } - return ( - config.destination || - 'ember-basic-dropdown-wormhole' - ); + return config.destination || 'ember-basic-dropdown-wormhole'; } _getDropdownElement(): HTMLElement | null { diff --git a/test-app/app/app.ts b/test-app/app/app.ts index e467d155..f2db2463 100644 --- a/test-app/app/app.ts +++ b/test-app/app/app.ts @@ -10,8 +10,8 @@ if (macroCondition(isDevelopingApp())) { } export const defaultBasicDropdownConfig: Config = { - rootElement: config.APP['rootElement'] as string | undefined -} + rootElement: config.APP['rootElement'] as string | undefined, +}; setConfig(defaultBasicDropdownConfig); diff --git a/test-app/tests/integration/components/basic-dropdown-wormhole-test.ts b/test-app/tests/integration/components/basic-dropdown-wormhole-test.ts index 2b5202ff..dfbd1a08 100644 --- a/test-app/tests/integration/components/basic-dropdown-wormhole-test.ts +++ b/test-app/tests/integration/components/basic-dropdown-wormhole-test.ts @@ -34,7 +34,7 @@ module('Integration | Component | basic-dropdown-wormhole', function (hooks) { test('Uses custom destination from config if present', async function (assert) { setConfig({ ...defaultBasicDropdownConfig, - destination: 'custom-wormhole-destination' + destination: 'custom-wormhole-destination', }); await render(hbs``); From 9243c879d8e6b233bbf6ffca0dab01e11cdaa8f3 Mon Sep 17 00:00:00 2001 From: Markus Sanin Date: Sun, 30 Nov 2025 18:14:20 +0100 Subject: [PATCH 3/5] Fix shadow dom tests --- test-app/app/instance-initializers/shadow-root.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test-app/app/instance-initializers/shadow-root.ts b/test-app/app/instance-initializers/shadow-root.ts index 205580fe..04104222 100644 --- a/test-app/app/instance-initializers/shadow-root.ts +++ b/test-app/app/instance-initializers/shadow-root.ts @@ -1,4 +1,6 @@ import type ApplicationInstance from '@ember/application/instance'; +import { setConfig } from 'ember-basic-dropdown/config'; +import { defaultBasicDropdownConfig } from 'test-app/app'; import config from 'test-app/config/environment'; // @ts-expect-error Public property 'isFastBoot' of exported class @@ -32,6 +34,11 @@ export function initialize(appInstance: ApplicationInstance) { config.APP['rootElement'] = '#ember-basic-dropdown-wormhole'; appInstance.set('rootElement', rootElement); + + setConfig({ + ...defaultBasicDropdownConfig, + rootElement: '#ember-basic-dropdown-wormhole' + }); } export default { From 81d1790598a23428c3472801965351a346759f4c Mon Sep 17 00:00:00 2001 From: Markus Sanin Date: Sun, 30 Nov 2025 18:16:03 +0100 Subject: [PATCH 4/5] Fix lint --- test-app/app/instance-initializers/shadow-root.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-app/app/instance-initializers/shadow-root.ts b/test-app/app/instance-initializers/shadow-root.ts index 04104222..ec06f9ce 100644 --- a/test-app/app/instance-initializers/shadow-root.ts +++ b/test-app/app/instance-initializers/shadow-root.ts @@ -37,7 +37,7 @@ export function initialize(appInstance: ApplicationInstance) { setConfig({ ...defaultBasicDropdownConfig, - rootElement: '#ember-basic-dropdown-wormhole' + rootElement: '#ember-basic-dropdown-wormhole', }); } From 55a753defb1f795d71119be6ffbd45b9b270d9bd Mon Sep 17 00:00:00 2001 From: Markus Sanin Date: Sun, 30 Nov 2025 18:21:09 +0100 Subject: [PATCH 5/5] Fix test --- test-app/app/instance-initializers/shadow-root.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/test-app/app/instance-initializers/shadow-root.ts b/test-app/app/instance-initializers/shadow-root.ts index ec06f9ce..227c2207 100644 --- a/test-app/app/instance-initializers/shadow-root.ts +++ b/test-app/app/instance-initializers/shadow-root.ts @@ -1,6 +1,5 @@ import type ApplicationInstance from '@ember/application/instance'; import { setConfig } from 'ember-basic-dropdown/config'; -import { defaultBasicDropdownConfig } from 'test-app/app'; import config from 'test-app/config/environment'; // @ts-expect-error Public property 'isFastBoot' of exported class @@ -36,7 +35,6 @@ export function initialize(appInstance: ApplicationInstance) { appInstance.set('rootElement', rootElement); setConfig({ - ...defaultBasicDropdownConfig, rootElement: '#ember-basic-dropdown-wormhole', }); }