diff --git a/packages/boxel-icons/package.json b/packages/boxel-icons/package.json index 2bb0e7a2833..3f9ea499194 100644 --- a/packages/boxel-icons/package.json +++ b/packages/boxel-icons/package.json @@ -46,11 +46,12 @@ "@babel/runtime": "catalog:", "@cardstack/eslint-plugin-boxel": "workspace:*", "@cardstack/local-types": "workspace:*", - "@lucide/lab": "^0.1.2", - "@tabler/icons": "^3.19.0", "@embroider/addon-dev": "^5.0.0", - "@embroider/macros": "^1.16.5", + "@embroider/macros": "^1.20.5", + "@glint/ember-tsc": "catalog:", + "@lucide/lab": "^0.1.2", "@rollup/plugin-babel": "catalog:", + "@tabler/icons": "^3.19.0", "@tsconfig/ember": "3.0.1", "@typescript-eslint/eslint-plugin": "catalog:", "@typescript-eslint/parser": "catalog:", @@ -71,8 +72,7 @@ "prettier-plugin-ember-template-tag": "catalog:", "rollup": "catalog:", "rollup-plugin-copy": "catalog:", - "svgo": "catalog:", - "@glint/ember-tsc": "catalog:" + "svgo": "catalog:" }, "peerDependencies": { "@ember/string": "catalog:", diff --git a/packages/boxel-ui/babel.config.mjs b/packages/boxel-ui/babel.config.mjs index 8c5926f6790..564b2ccfbda 100644 --- a/packages/boxel-ui/babel.config.mjs +++ b/packages/boxel-ui/babel.config.mjs @@ -1,10 +1,9 @@ import { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { - babelCompatSupport, - templateCompatSupport, -} from '@embroider/compat/babel'; +import { buildMacros } from '@embroider/macros/babel'; + +const macros = buildMacros(); /** * This babel config drives the vite dev/test pipeline (see vite.config.mjs). @@ -26,13 +25,8 @@ export default { [ 'babel-plugin-ember-template-compilation', { - enableLegacyModules: [ - 'ember-cli-htmlbars', - 'ember-cli-htmlbars-inline-precompile', - 'htmlbars-inline-precompile', - ], transforms: [ - ...templateCompatSupport(), + ...macros.templateMacros, 'glimmer-scoped-css/ast-transform', ], }, @@ -55,7 +49,7 @@ export default { regenerator: false, }, ], - ...babelCompatSupport(), + ...macros.babelMacros, ], generatorOpts: { diff --git a/packages/boxel-ui/config/environment.js b/packages/boxel-ui/config/environment.js deleted file mode 100644 index b8ea757323e..00000000000 --- a/packages/boxel-ui/config/environment.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -// Consumed by the compat test pipeline (see ember-cli-build.js); the addon -// itself has no runtime environment config. -module.exports = function (environment) { - const ENV = { - modulePrefix: 'boxel-ui-tests', - environment, - rootURL: '/', - locationType: 'history', - APP: {}, - }; - if (environment === 'test') { - ENV.locationType = 'none'; - ENV.APP.LOG_ACTIVE_GENERATION = false; - ENV.APP.LOG_VIEW_LOOKUPS = false; - ENV.APP.rootElement = '#ember-testing'; - ENV.APP.autoboot = false; - } - return ENV; -}; diff --git a/packages/boxel-ui/docs-app/package.json b/packages/boxel-ui/docs-app/package.json index 50b111aa826..663f0909891 100644 --- a/packages/boxel-ui/docs-app/package.json +++ b/packages/boxel-ui/docs-app/package.json @@ -40,7 +40,7 @@ "@embroider/config-meta-loader": "^1.0.0", "@embroider/core": "^4.4.7", "@embroider/legacy-inspector-support": "^0.1.3", - "@embroider/macros": "^1.16.5", + "@embroider/macros": "^1.20.5", "@embroider/test-setup": "^4.0.0", "@embroider/vite": "^1.7.2", "@glimmer/component": "catalog:", diff --git a/packages/boxel-ui/ember-cli-build.js b/packages/boxel-ui/ember-cli-build.js deleted file mode 100644 index 58f7e811524..00000000000 --- a/packages/boxel-ui/ember-cli-build.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; -const EmberApp = require('ember-cli/lib/broccoli/ember-app'); -const { compatBuild } = require('@embroider/compat'); - -// This exists solely so the vite test pipeline (see vite.config.mjs) can run -// classicEmberSupport(): several dependencies still ship loose-mode -// templates that need the compat resolver. Publishing does not use it — see -// rollup.config.mjs. -module.exports = async function (defaults) { - const { buildOnce } = await import('@embroider/vite'); - - const app = new EmberApp(defaults, {}); - - return compatBuild(app, buildOnce, {}); -}; diff --git a/packages/boxel-ui/package.json b/packages/boxel-ui/package.json index 0b9bec2304e..e10299bb102 100644 --- a/packages/boxel-ui/package.json +++ b/packages/boxel-ui/package.json @@ -46,7 +46,7 @@ "decorator-transforms": "catalog:", "dompurify": "catalog:", "ember-animated": "catalog:", - "ember-basic-dropdown": "8.0.4", + "ember-basic-dropdown": "^9.0.0", "ember-concurrency": "catalog:", "ember-concurrency-ts": "catalog:", "ember-css-url": "^1.0.0", @@ -54,9 +54,9 @@ "ember-focus-trap": "^1.0.1", "ember-freestyle": "catalog:", "ember-modifier": "^4.1.0", - "ember-power-calendar": "^1.2.0", - "ember-power-calendar-moment": "^1.0.2", - "ember-power-select": "^8.0.0", + "ember-power-calendar": "^2.0.0", + "ember-power-calendar-moment": "^1.0.4", + "ember-power-select": "^9.0.0", "ember-resize-modifier": "^0.7.1", "ember-sortable": "^5.3.1", "ember-velcro": "^2.1.3", @@ -77,13 +77,11 @@ "@babel/runtime": "catalog:", "@cardstack/eslint-plugin-boxel": "workspace:*", "@cardstack/local-types": "workspace:*", - "@ember/optional-features": "^2.0.0", "@ember/test-helpers": "catalog:", "@embroider/addon-dev": "^8.0.0", - "@embroider/compat": "^4.1.17", "@embroider/config-meta-loader": "^1.0.0", "@embroider/core": "^4.4.7", - "@embroider/macros": "~1.16.5", + "@embroider/macros": "^1.20.5", "@embroider/vite": "^1.7.2", "@eslint/js": "^9.17.0", "@glimmer/component": "catalog:", @@ -97,9 +95,6 @@ "babel-plugin-ember-template-compilation": "catalog:", "concurrently": "catalog:", "ember-a11y-testing": "^8.0.0", - "ember-cli": "^5.4.1", - "ember-cli-babel": "^8.2.0", - "ember-cli-htmlbars": "^6.3.0", "ember-qunit": "catalog:", "ember-source": "catalog:", "ember-strict-application-resolver": "^0.1.0", diff --git a/packages/boxel-ui/src/components/dropdown/index.gts b/packages/boxel-ui/src/components/dropdown/index.gts index 88cb004be09..f29e52f356a 100644 --- a/packages/boxel-ui/src/components/dropdown/index.gts +++ b/packages/boxel-ui/src/components/dropdown/index.gts @@ -4,9 +4,8 @@ import { action } from '@ember/object'; import { guidFor } from '@ember/object/internals'; import type Owner from '@ember/owner'; import Component from '@glimmer/component'; -import BasicDropdown, { - type Dropdown, -} from 'ember-basic-dropdown/components/basic-dropdown'; +import BasicDropdown from 'ember-basic-dropdown/components/basic-dropdown'; +import type { Dropdown } from 'ember-basic-dropdown/types'; import focusTrap from 'ember-focus-trap/modifiers/focus-trap'; import { type FunctionBasedModifier, @@ -185,8 +184,10 @@ class BoxelDropdown extends Component { this.themeObserver = null; } - @action registerAPI(publicAPI: DropdownAPI) { - this.args.registerAPI?.(publicAPI); + @action registerAPI(publicAPI: DropdownAPI | null) { + if (publicAPI) { + this.args.registerAPI?.(publicAPI); + } } @action onMouseLeave(dropdown?: Dropdown) { diff --git a/packages/boxel-ui/src/components/multi-select/after-options.gts b/packages/boxel-ui/src/components/multi-select/after-options.gts index adc8b037d83..4ca0c287c9a 100644 --- a/packages/boxel-ui/src/components/multi-select/after-options.gts +++ b/packages/boxel-ui/src/components/multi-select/after-options.gts @@ -1,7 +1,7 @@ import { on } from '@ember/modifier'; import { action } from '@ember/object'; import Component from '@glimmer/component'; -import type { Select } from 'ember-power-select/components/power-select'; +import type { Select } from 'ember-power-select/types'; import BoxelButton from '../button/index.gts'; diff --git a/packages/boxel-ui/src/components/multi-select/index.gts b/packages/boxel-ui/src/components/multi-select/index.gts index 01a0f5dc52d..772c2bef179 100644 --- a/packages/boxel-ui/src/components/multi-select/index.gts +++ b/packages/boxel-ui/src/components/multi-select/index.gts @@ -2,49 +2,48 @@ import 'ember-power-select/styles'; import Component from '@glimmer/component'; import type { ComponentLike } from '@glint/template'; -import type { - PowerSelectArgs, - Select, -} from 'ember-power-select/components/power-select'; +import type { PowerSelectArgs } from 'ember-power-select/components/power-select'; import PowerSelect from 'ember-power-select/components/power-select'; import BeforeOptions from 'ember-power-select/components/power-select/before-options'; +import type { + Option, + PowerSelectAfterOptionsSignature, + PowerSelectSelectedItemSignature, + Select, +} from 'ember-power-select/types'; import { cn, not } from '../../helpers.gts'; import { BoxelAfterOptionsComponent } from './after-options.gts'; -import BoxelSelectedItem, { - type SelectedItemSignature, -} from './selected-item.gts'; -import BoxelMultiSelectDefaultTrigger, { - type TriggerComponentSignature, -} from './trigger.gts'; -export interface BoxelMultiSelectArgs extends PowerSelectArgs { - afterOptionsComponent?: ComponentLike; - ariaLabel?: string; - beforeOptionsComponent?: ComponentLike; - closeOnSelect?: boolean; - destination?: string; - disabled?: boolean; - dropdownClass?: string; - extra?: any; - matchTriggerWidth?: boolean; - onBlur?: (select: Select, e: Event) => boolean | undefined; - onClose?: (select: Select, e: Event) => boolean | undefined; - onOpen?: (select: Select, e: Event) => boolean | undefined; - options: ItemT[]; - placeholder?: string; - renderInPlace?: boolean; - searchEnabled?: boolean; - searchField?: string; - selected: ItemT[]; - selectedItemComponent?: ComponentLike>; - triggerComponent?: ComponentLike>; +const DefaultAfterOptions = + BoxelAfterOptionsComponent as unknown as ComponentLike< + PowerSelectAfterOptionsSignature + >; +import BoxelSelectedItem from './selected-item.gts'; + +// The default subcomponents are generic classes whose inferred ComponentLike +// shapes glint cannot match against power-select's expected unions; their +// signatures are structurally compatible (verified by the suite), so pin +// them to the expected member types once here. +const DefaultSelectedItem = BoxelSelectedItem as unknown as ComponentLike< + PowerSelectSelectedItemSignature +>; +import BoxelMultiSelectDefaultTrigger from './trigger.gts'; + +// Everything else is inherited from ember-power-select's own args; +// options/selected are re-declared only to make them required. +export interface BoxelMultiSelectArgs extends PowerSelectArgs< + ItemT, + true +> { + options: NonNullable['options']>; + selected: NonNullable['selected']>; } export interface Signature { Args: BoxelMultiSelectArgs; Blocks: { - default: [any, Select]; + default: [Option, Select]; }; Element: HTMLElement; } @@ -100,8 +99,8 @@ export class BoxelMultiSelectBasic extends Component> { @afterOptionsComponent={{@afterOptionsComponent}} @beforeOptionsComponent={{if @beforeOptionsComponent - (component @beforeOptionsComponent) - (component BeforeOptions) + @beforeOptionsComponent + BeforeOptions }} ...attributes as |option select| @@ -216,11 +215,11 @@ export default class BoxelMultiSelect extends Component< @selectedItemComponent={{if @selectedItemComponent @selectedItemComponent - (component BoxelSelectedItem) + DefaultSelectedItem }} - @triggerComponent={{component BoxelMultiSelectDefaultTrigger}} - @beforeOptionsComponent={{component BeforeOptions}} - @afterOptionsComponent={{component BoxelAfterOptionsComponent}} + @triggerComponent={{BoxelMultiSelectDefaultTrigger}} + @beforeOptionsComponent={{BeforeOptions}} + @afterOptionsComponent={{DefaultAfterOptions}} ...attributes as |option select| > diff --git a/packages/boxel-ui/src/components/multi-select/selected-item.gts b/packages/boxel-ui/src/components/multi-select/selected-item.gts index 62d3b371929..d69897bd2fd 100644 --- a/packages/boxel-ui/src/components/multi-select/selected-item.gts +++ b/packages/boxel-ui/src/components/multi-select/selected-item.gts @@ -2,34 +2,35 @@ import { fn } from '@ember/helper'; import { on } from '@ember/modifier'; import { action } from '@ember/object'; import Component from '@glimmer/component'; -import type { Select } from 'ember-power-select/components/power-select'; +import type { Option, Select } from 'ember-power-select/types'; import IconX from '../../icons/icon-x.gts'; import Pill from '../pill/index.gts'; -// Inside the trigger component, the selected item component is called within in ember-power-select -// It only passes option, select -// We follow the same convention when defining our own selected item component +// Invoked per selected item by the trigger; the arg names follow +// ember-power-select's own selected-item contract (@selected, @select) so +// custom components typed against either signature are interchangeable. export interface SelectedItemSignature { Args: { - option: any; - select: Select & { + extra?: unknown; + select: Select & { actions: { - remove: (item: ItemT) => void; + remove?: (item: Option) => void; }; }; + selected: Option; }; Blocks: { - default: [ItemT, Select]; + default: [Option, Select]; }; - Element: HTMLDivElement; + Element: HTMLElement; } export default class BoxelSelectedItem extends Component< SelectedItemSignature > { @action - remove(item: ItemT, event: MouseEvent) { + remove(item: Option, event: MouseEvent) { // Do not remove these event methods // This is to ensure that the close/click event from selected item does not bubble up to the trigger // and cause the dropdown to close @@ -46,14 +47,14 @@ export default class BoxelSelectedItem extends Component<
<:default> - {{yield @option @select}} + {{yield @selected @select}} <:iconRight> {{! TODO: Replace with icon button }}