@aurelia/runtime-html
Advanced tools
Comparing version 2.0.1-dev.202402130428 to 2.0.1-dev.202403021005
import { InstanceProvider } from '@aurelia/kernel'; | ||
import type { IContainer, IDisposable } from '@aurelia/kernel'; | ||
import type { ICustomElementController } from './templating/controller'; | ||
import type { IPlatform } from './platform'; | ||
export interface ISinglePageApp { | ||
import type { Constructable, IContainer, IDisposable } from '@aurelia/kernel'; | ||
import type { ICustomElementViewModel, ICustomElementController } from './templating/controller'; | ||
import { IPlatform } from './platform'; | ||
export interface IAppRootConfig<T extends object = object> { | ||
host: HTMLElement; | ||
component: unknown; | ||
component: T | Constructable<T>; | ||
} | ||
export interface IAppRoot extends AppRoot { | ||
export interface IAppRoot<C extends object = object> extends IDisposable { | ||
readonly config: IAppRootConfig<C>; | ||
/** | ||
* The host element of an application | ||
*/ | ||
readonly host: HTMLElement; | ||
/** | ||
* The root container of an application | ||
*/ | ||
readonly container: IContainer; | ||
/** | ||
* The controller of the root custom element of an application | ||
*/ | ||
readonly controller: ICustomElementController<C>; | ||
/** | ||
* The platform of an application for providing globals & DOM APIs | ||
*/ | ||
readonly platform: IPlatform; | ||
activate(): void | Promise<void>; | ||
deactivate(): void | Promise<void>; | ||
} | ||
export declare const IAppRoot: import("@aurelia/kernel").InterfaceSymbol<IAppRoot>; | ||
export declare class AppRoot implements IDisposable { | ||
readonly config: ISinglePageApp; | ||
readonly platform: IPlatform; | ||
export declare const IAppRoot: import("@aurelia/kernel").InterfaceSymbol<IAppRoot<object>>; | ||
export declare class AppRoot<T extends object, K extends ICustomElementViewModel = T extends Constructable<infer R> ? R : T> implements IAppRoot<K> { | ||
readonly config: IAppRootConfig<K>; | ||
readonly container: IContainer; | ||
readonly host: HTMLElement; | ||
controller: ICustomElementController; | ||
constructor(config: ISinglePageApp, platform: IPlatform, container: IContainer, rootProvider: InstanceProvider<IAppRoot>); | ||
readonly platform: IPlatform; | ||
get controller(): ICustomElementController<K>; | ||
constructor(config: IAppRootConfig<K>, container: IContainer, rootProvider: InstanceProvider<IAppRoot>, enhance?: boolean); | ||
activate(): void | Promise<void>; | ||
@@ -20,0 +39,0 @@ deactivate(): void | Promise<void>; |
@@ -1,3 +0,2 @@ | ||
import { IAppRoot, ISinglePageApp } from './app-root'; | ||
import { ICustomElementController, ICustomElementViewModel, IHydratedParentController } from './templating/controller'; | ||
import { IAppRoot } from './app-root'; | ||
import type { Constructable, IContainer, IDisposable } from '@aurelia/kernel'; | ||
@@ -16,7 +15,7 @@ export interface IAurelia extends Aurelia { | ||
register(...params: unknown[]): this; | ||
app(config: ISinglePageApp): Omit<this, 'register' | 'app' | 'enhance'>; | ||
app(config: ISinglePageAppConfig<object>): Omit<this, 'register' | 'app' | 'enhance'>; | ||
/** | ||
* @param parentController - The owning controller of the view created by this enhance call | ||
*/ | ||
enhance<T extends ICustomElementViewModel, K extends ICustomElementViewModel = T extends Constructable<infer I extends ICustomElementViewModel> ? I : T>(config: IEnhancementConfig<T>, parentController?: IHydratedParentController | null): ICustomElementController<K> | Promise<ICustomElementController<K>>; | ||
enhance<T extends object>(config: IEnhancementConfig<T>): IAppRoot<T> | Promise<IAppRoot<T>>; | ||
waitForIdle(): Promise<void>; | ||
@@ -27,2 +26,12 @@ start(root?: IAppRoot | undefined): void | Promise<void>; | ||
} | ||
export interface ISinglePageAppConfig<T = unknown> { | ||
/** | ||
* The host element of the app | ||
*/ | ||
host: HTMLElement; | ||
/** | ||
* The root component of the app | ||
*/ | ||
component: T | Constructable<T>; | ||
} | ||
export interface IEnhancementConfig<T> { | ||
@@ -33,3 +42,3 @@ host: Element; | ||
*/ | ||
component: T; | ||
component: T | Constructable<T>; | ||
/** | ||
@@ -36,0 +45,0 @@ * A predefined container for the enhanced view. |
@@ -32,4 +32,3 @@ import { IServiceLocator, Key } from '@aurelia/kernel'; | ||
get state(): import("../templating/controller").State; | ||
constructor( | ||
/** @internal */ _hydrationContext: IHydrationContext<object>); | ||
constructor(hydrationContext: IHydrationContext<object>); | ||
get(key: Key): any; | ||
@@ -36,0 +35,0 @@ bind(_scope: Scope): void; |
@@ -7,4 +7,9 @@ export { bindable, Bindable, BindableDefinition, type PartialBindableDefinition, coercer, } from './bindable'; | ||
export { ThrottleBindingBehavior, } from './resources/binding-behaviors/throttle'; | ||
export { Aurelia, IAurelia, type IEnhancementConfig, } from './aurelia'; | ||
export { type ISinglePageApp, AppRoot, IAppRoot, } from './app-root'; | ||
export { Aurelia, IAurelia, type IEnhancementConfig, | ||
/** | ||
* @deprecated | ||
* Use `ISinglePageAppConfig` instead | ||
*/ | ||
type ISinglePageAppConfig as ISinglePageApp, type ISinglePageAppConfig, } from './aurelia'; | ||
export { type IAppRootConfig, AppRoot, IAppRoot, } from './app-root'; | ||
export { type TaskSlot, AppTask, IAppTask, type AppTaskCallback, type AppTaskCallbackNoArg, } from './app-task'; | ||
@@ -45,4 +50,3 @@ export { AttrSyntax, IAttributeParser, attributePattern, type AttributePatternDefinition, IAttributePattern, AttributePattern, Interpretation, ISyntaxInterpreter, AtPrefixedTriggerAttributePattern, ColonPrefixedBindAttributePattern, DotSeparatedAttributePattern, RefAttributePattern, } from './resources/attribute-pattern'; | ||
export { AuSlot, } from './resources/custom-elements/au-slot'; | ||
export type { DefinitionType, } from './resources/resources-shared'; | ||
export { capture, containerless, customElement, CustomElement, type CustomElementDecorator, type CustomElementKind, type CustomElementType, CustomElementDefinition, type PartialCustomElementDefinition, useShadowDOM, processContent, } from './resources/custom-element'; | ||
export { capture, containerless, customElement, CustomElement, type InjectableToken, type CustomElementDecorator, type CustomElementKind, type CustomElementType, CustomElementDefinition, type PartialCustomElementDefinition, useShadowDOM, processContent, } from './resources/custom-element'; | ||
export { AuCompose, type IDynamicComponentActivate, } from './resources/custom-elements/au-compose'; | ||
@@ -49,0 +53,0 @@ export { ValueConverter, ValueConverterDefinition, type PartialValueConverterDefinition, type ValueConverterKind, type ValueConverterDecorator, type ValueConverterType, valueConverter, } from './resources/value-converter'; |
@@ -71,3 +71,3 @@ import { Key } from '@aurelia/kernel'; | ||
readonly dependencies: Key[]; | ||
get type(): 'Attribute'; | ||
get type(): 'attribute'; | ||
private constructor(); | ||
@@ -74,0 +74,0 @@ static create<T extends Constructable = Constructable>(nameOrDef: string | PartialCustomAttributeDefinition, Type: CustomAttributeType<T>): CustomAttributeDefinition<T>; |
@@ -1,2 +0,2 @@ | ||
import type { Constructable, IContainer, IResourceKind, ResourceType, PartialResourceDefinition, Key, ResourceDefinition, Injectable } from '@aurelia/kernel'; | ||
import type { Constructable, IContainer, IResourceKind, ResourceType, PartialResourceDefinition, Key, ResourceDefinition } from '@aurelia/kernel'; | ||
import type { BindableDefinition, PartialBindableDefinition } from '../bindable'; | ||
@@ -152,3 +152,3 @@ import type { INode } from '../dom'; | ||
readonly processContent: ProcessContentHook | null; | ||
get type(): 'Element'; | ||
get type(): 'element'; | ||
private constructor(); | ||
@@ -162,3 +162,5 @@ static create(def: PartialCustomElementDefinition, Type?: null): CustomElementDefinition; | ||
} | ||
export type InjectableToken<K = any> = (target: Injectable, property: string | symbol | undefined, index: number) => void; | ||
export type InjectableToken<K = any> = ((target: Constructable, property: string | symbol | undefined, index: number) => void) & { | ||
readonly __resolved__: K | null; | ||
}; | ||
export declare const CustomElement: Readonly<CustomElementKind>; | ||
@@ -165,0 +167,0 @@ type DecoratorFactoryMethod<TClass> = (target: Constructable<TClass>, propertyKey: string, descriptor: PropertyDescriptor) => void; |
@@ -13,6 +13,17 @@ import { Constructable } from '@aurelia/kernel'; | ||
} | ||
type ChangeSource = keyof Pick<AuCompose, 'template' | 'component' | 'model' | 'scopeBehavior' | 'composing' | 'composition'>; | ||
type ChangeSource = keyof Pick<AuCompose, 'template' | 'component' | 'model' | 'scopeBehavior' | 'composing' | 'composition' | 'tag'>; | ||
export declare class AuCompose { | ||
template?: string | Promise<string>; | ||
component?: Constructable | object | Promise<Constructable | object>; | ||
/** | ||
* Determine the component instance used to compose the component. | ||
* | ||
* - When a string is given as a value, it will be used as the name of the custom element to compose. | ||
* If there is no locally or globally registered custom element with that name, an error will be thrown. | ||
* | ||
* - When an object is given as a value, the object will be used as the component instance. | ||
* - When a constructor is given as a value, the constructor will be used to create the component instance. | ||
* - When a null/undefined is given as a value, the component will be composed as a template-only composition with an empty component instance. | ||
* - When a promise is given as a value, the promise will be awaited and the resolved value will be used as the value. | ||
*/ | ||
component?: string | Constructable | object | Promise<string | Constructable | object>; | ||
model?: unknown; | ||
@@ -29,2 +40,8 @@ /** | ||
get composition(): ICompositionController | undefined; | ||
/** | ||
* The tag name of the element to be created for non custom element composition. | ||
* | ||
* `null`/`undefined` means containerless | ||
*/ | ||
tag: string | null | undefined; | ||
attaching(initiator: IHydratedController, _parent: IHydratedController): void | Promise<void>; | ||
@@ -38,10 +55,10 @@ detaching(initiator: IHydratedController): void | Promise<void>; | ||
deactivate(detachInitator?: IHydratedController): void | Promise<void>; | ||
update(model: unknown): void | Promise<void>; | ||
update(model: unknown): unknown; | ||
} | ||
declare class LoadedChangeInfo { | ||
readonly _template: string | undefined; | ||
readonly _component: Constructable | object | undefined; | ||
readonly _component: string | Constructable | object | undefined; | ||
readonly _model: unknown; | ||
readonly _src: ChangeSource | undefined; | ||
constructor(_template: string | undefined, _component: Constructable | object | undefined, _model: unknown, _src: ChangeSource | undefined); | ||
constructor(_template: string | undefined, _component: string | Constructable | object | undefined, _model: unknown, _src: ChangeSource | undefined); | ||
} | ||
@@ -48,0 +65,0 @@ declare class CompositionContext { |
@@ -1,4 +0,2 @@ | ||
export declare const dtElement: "Element"; | ||
export declare const dtAttribute: "Attribute"; | ||
export type DefinitionType = typeof dtElement | typeof dtAttribute; | ||
export {}; | ||
//# sourceMappingURL=resources-shared.d.ts.map |
@@ -1,13 +0,13 @@ | ||
import { Scope, ICoercionConfiguration } from '@aurelia/runtime'; | ||
import { ICoercionConfiguration, Scope } from '@aurelia/runtime'; | ||
import { CustomAttributeDefinition } from '../resources/custom-attribute'; | ||
import { CustomElementDefinition } from '../resources/custom-element'; | ||
import { CustomAttributeDefinition } from '../resources/custom-attribute'; | ||
import type { IContainer, Writable, IDisposable } from '@aurelia/kernel'; | ||
import type { IContainer, IDisposable, Writable } from '@aurelia/kernel'; | ||
import type { IBinding } from '@aurelia/runtime'; | ||
import type { INode, INodeSequence, IRenderLocation } from '../dom'; | ||
import type { IInstruction } from '../renderer'; | ||
import type { AttrSyntax } from '../resources/attribute-pattern'; | ||
import type { PartialCustomElementDefinition } from '../resources/custom-element'; | ||
import type { IAuSlotProjections } from './controller.projection'; | ||
import type { LifecycleHooksLookup } from './lifecycle-hooks'; | ||
import type { INode, INodeSequence, IRenderLocation } from '../dom'; | ||
import type { IViewFactory } from './view'; | ||
import type { IInstruction } from '../renderer'; | ||
import type { PartialCustomElementDefinition } from '../resources/custom-element'; | ||
export declare class Controller<C extends IViewModel = IViewModel> implements IController<C> { | ||
@@ -148,4 +148,2 @@ container: IContainer; | ||
export declare function isCustomElementViewModel(value: unknown): value is ICustomElementViewModel; | ||
declare const vmkCe: "customElement"; | ||
export declare const vmkCa: "customAttribute"; | ||
declare const vmkSynth: "synthetic"; | ||
@@ -152,0 +150,0 @@ export type ViewModelKind = typeof vmkCe | typeof vmkCa | typeof vmkSynth; |
{ | ||
"name": "@aurelia/runtime-html", | ||
"version": "2.0.1-dev.202402130428", | ||
"version": "2.0.1-dev.202403021005", | ||
"main": "dist/cjs/index.cjs", | ||
@@ -56,7 +56,7 @@ "module": "dist/esm/index.mjs", | ||
"dependencies": { | ||
"@aurelia/kernel": "2.0.1-dev.202402130428", | ||
"@aurelia/metadata": "2.0.1-dev.202402130428", | ||
"@aurelia/platform": "2.0.1-dev.202402130428", | ||
"@aurelia/platform-browser": "2.0.1-dev.202402130428", | ||
"@aurelia/runtime": "2.0.1-dev.202402130428" | ||
"@aurelia/kernel": "2.0.1-dev.202403021005", | ||
"@aurelia/metadata": "2.0.1-dev.202403021005", | ||
"@aurelia/platform": "2.0.1-dev.202403021005", | ||
"@aurelia/platform-browser": "2.0.1-dev.202403021005", | ||
"@aurelia/runtime": "2.0.1-dev.202403021005" | ||
}, | ||
@@ -63,0 +63,0 @@ "devDependencies": { |
@@ -0,6 +1,7 @@ | ||
import { BrowserPlatform } from '@aurelia/platform-browser'; | ||
import { InstanceProvider, onResolve, onResolveAll } from '@aurelia/kernel'; | ||
import { IAppTask } from './app-task'; | ||
import { isElementType } from './resources/custom-element'; | ||
import { CustomElementDefinition, generateElementName } from './resources/custom-element'; | ||
import { Controller, IControllerElementHydrationInstruction } from './templating/controller'; | ||
import { createInterface } from './utilities-di'; | ||
import { createInterface, instanceRegistration } from './utilities-di'; | ||
@@ -10,38 +11,71 @@ import type { Constructable, IContainer, IDisposable } from '@aurelia/kernel'; | ||
import type { ICustomElementViewModel, ICustomElementController } from './templating/controller'; | ||
import type { IPlatform } from './platform'; | ||
import { IPlatform } from './platform'; | ||
import { registerHostNode } from './dom'; | ||
import { isFunction } from './utilities'; | ||
import { ErrorNames, createMappedError } from './errors'; | ||
export interface ISinglePageApp { | ||
export interface IAppRootConfig<T extends object = object> { | ||
host: HTMLElement; | ||
component: unknown; | ||
component: T | Constructable<T>; | ||
} | ||
export interface IAppRoot extends AppRoot {} | ||
export interface IAppRoot<C extends object = object> extends IDisposable { | ||
readonly config: IAppRootConfig<C>; | ||
/** | ||
* The host element of an application | ||
*/ | ||
readonly host: HTMLElement; | ||
/** | ||
* The root container of an application | ||
*/ | ||
readonly container: IContainer; | ||
/** | ||
* The controller of the root custom element of an application | ||
*/ | ||
readonly controller: ICustomElementController<C>; | ||
/** | ||
* The platform of an application for providing globals & DOM APIs | ||
*/ | ||
readonly platform: IPlatform; | ||
activate(): void | Promise<void>; | ||
deactivate(): void | Promise<void>; | ||
} | ||
export const IAppRoot = /*@__PURE__*/createInterface<IAppRoot>('IAppRoot'); | ||
export class AppRoot implements IDisposable { | ||
public readonly host: HTMLElement; | ||
export class AppRoot< | ||
T extends object, | ||
K extends ICustomElementViewModel = T extends Constructable<infer R> ? R : T, | ||
> implements IAppRoot<K> { | ||
public controller!: ICustomElementController; | ||
/** @internal */ | ||
private _hydratePromise: Promise<void> | void = void 0; | ||
/** @internal */ | ||
private _controller!: ICustomElementController<K>; | ||
public readonly host: HTMLElement; | ||
public readonly platform: IPlatform; | ||
public get controller() { | ||
return this._controller; | ||
} | ||
public constructor( | ||
public readonly config: ISinglePageApp, | ||
public readonly platform: IPlatform, | ||
public readonly config: IAppRootConfig<K>, | ||
public readonly container: IContainer, | ||
rootProvider: InstanceProvider<IAppRoot>, | ||
enhance?: boolean | ||
) { | ||
this.host = config.host; | ||
const host = this.host = config.host; | ||
rootProvider.prepare(this); | ||
registerHostNode(container, platform, config.host); | ||
registerHostNode(container, this.platform = this._createPlatform(container, host), host); | ||
this._hydratePromise = onResolve(this._runAppTasks('creating'), () => { | ||
const childCtn = enhance ? container : container.createChild(); | ||
const component = config.component as Constructable | ICustomElementViewModel; | ||
const childCtn = container.createChild(); | ||
let instance: object; | ||
if (isElementType(component)) { | ||
instance = this.container.get(component); | ||
if (isFunction(component)) { | ||
instance = childCtn.invoke(component); | ||
instanceRegistration(component, instance); | ||
} else { | ||
@@ -52,8 +86,14 @@ instance = config.component as ICustomElementViewModel; | ||
const hydrationInst: IControllerElementHydrationInstruction = { hydrate: false, projections: null }; | ||
const controller = (this.controller = Controller.$el( | ||
const definition = enhance | ||
? CustomElementDefinition.create({ name: generateElementName(), template: this.host, enhance: true }) | ||
// leave the work of figuring out the definition to the controller | ||
// there's proper error messages in case of failure inside the $el() call | ||
: void 0; | ||
const controller = (this._controller = Controller.$el<K>( | ||
childCtn, | ||
instance, | ||
this.host, | ||
instance as K, | ||
host, | ||
hydrationInst, | ||
)) as Controller; | ||
definition | ||
)) as Controller<K>; | ||
@@ -74,3 +114,3 @@ controller._hydrateCustomElement(hydrationInst, /* root does not have hydration context */null); | ||
return onResolve(this._runAppTasks('activating'), () => { | ||
return onResolve(this.controller.activate(this.controller, null, void 0), () => { | ||
return onResolve(this._controller.activate(this._controller, null, void 0), () => { | ||
return this._runAppTasks('activated'); | ||
@@ -84,3 +124,3 @@ }); | ||
return onResolve(this._runAppTasks('deactivating'), () => { | ||
return onResolve(this.controller.deactivate(this.controller, null), () => { | ||
return onResolve(this._controller.deactivate(this._controller, null), () => { | ||
return this._runAppTasks('deactivated'); | ||
@@ -101,5 +141,20 @@ }); | ||
/** @internal */ | ||
private _createPlatform(container: IContainer, host: HTMLElement): IPlatform { | ||
let p: IPlatform; | ||
if (!container.has(IPlatform, false)) { | ||
if (host.ownerDocument.defaultView === null) { | ||
throw createMappedError(ErrorNames.invalid_platform_impl); | ||
} | ||
p = new BrowserPlatform(host.ownerDocument.defaultView); | ||
container.register(instanceRegistration(IPlatform, p)); | ||
} else { | ||
p = container.get(IPlatform); | ||
} | ||
return p; | ||
} | ||
public dispose(): void { | ||
this.controller?.dispose(); | ||
this._controller?.dispose(); | ||
} | ||
} |
import { DI, InstanceProvider, onResolve } from '@aurelia/kernel'; | ||
import { BrowserPlatform } from '@aurelia/platform-browser'; | ||
import { AppRoot, IAppRoot, ISinglePageApp } from './app-root'; | ||
import { IEventTarget, registerHostNode } from './dom'; | ||
import { IPlatform } from './platform'; | ||
import { CustomElementDefinition, generateElementName } from './resources/custom-element'; | ||
import { Controller, ICustomElementController, ICustomElementViewModel, IHydratedParentController } from './templating/controller'; | ||
import { isFunction, isPromise } from './utilities'; | ||
import { createInterface, instanceRegistration, registerResolver } from './utilities-di'; | ||
import { AppRoot, IAppRoot } from './app-root'; | ||
import { isPromise } from './utilities'; | ||
import { createInterface, registerResolver } from './utilities-di'; | ||
@@ -71,4 +66,4 @@ import type { | ||
public app(config: ISinglePageApp): Omit<this, 'register' | 'app' | 'enhance'> { | ||
this.next = new AppRoot(config, this._initPlatform(config.host), this.container, this._rootProvider); | ||
public app(config: ISinglePageAppConfig<object>): Omit<this, 'register' | 'app' | 'enhance'> { | ||
this.next = new AppRoot(config, this.container, this._rootProvider); | ||
return this; | ||
@@ -80,28 +75,10 @@ } | ||
*/ | ||
public enhance<T extends ICustomElementViewModel, K extends ICustomElementViewModel = T extends Constructable<infer I extends ICustomElementViewModel> ? I : T>(config: IEnhancementConfig<T>, parentController?: IHydratedParentController | null): ICustomElementController<K> | Promise<ICustomElementController<K>> { | ||
const ctn = config.container ?? this.container.createChild(); | ||
const host = config.host as HTMLElement; | ||
const p = this._initPlatform(host); | ||
const comp = config.component as unknown as K; | ||
let bc: ICustomElementViewModel & K; | ||
if (isFunction(comp)) { | ||
registerHostNode(ctn, p, host); | ||
bc = ctn.invoke(comp as unknown as Constructable<ICustomElementViewModel & K>); | ||
} else { | ||
bc = comp; | ||
} | ||
registerResolver(ctn, IEventTarget, new InstanceProvider('IEventTarget', host)); | ||
parentController = parentController ?? null; | ||
const view = Controller.$el( | ||
ctn, | ||
bc, | ||
host, | ||
null, | ||
CustomElementDefinition.create({ name: generateElementName(), template: host, enhance: true }), | ||
); | ||
return onResolve( | ||
view.activate(view, parentController), | ||
() => view | ||
); | ||
public enhance<T extends object>(config: IEnhancementConfig<T>): IAppRoot<T> | Promise<IAppRoot<T>> { | ||
const appRoot = new AppRoot( | ||
{ host: config.host as HTMLElement, component: config.component }, | ||
config.container ?? this.container.createChild(), | ||
new InstanceProvider('IAppRoot'), | ||
true | ||
) as IAppRoot<T>; | ||
return onResolve(appRoot.activate(), () => appRoot); | ||
} | ||
@@ -117,17 +94,2 @@ | ||
/** @internal */ | ||
private _initPlatform(host: HTMLElement): IPlatform { | ||
let p: IPlatform; | ||
if (!this.container.has(IPlatform, false)) { | ||
if (host.ownerDocument.defaultView === null) { | ||
throw createMappedError(ErrorNames.invalid_platform_impl); | ||
} | ||
p = new BrowserPlatform(host.ownerDocument.defaultView); | ||
this.container.register(instanceRegistration(IPlatform, p)); | ||
} else { | ||
p = this.container.get(IPlatform); | ||
} | ||
return p; | ||
} | ||
/** @internal */ | ||
private _startPromise: Promise<void> | void = void 0; | ||
@@ -196,2 +158,13 @@ public start(root: IAppRoot | undefined = this.next): void | Promise<void> { | ||
export interface ISinglePageAppConfig<T = unknown> { | ||
/** | ||
* The host element of the app | ||
*/ | ||
host: HTMLElement; | ||
/** | ||
* The root component of the app | ||
*/ | ||
component: T | Constructable<T>; | ||
} | ||
export interface IEnhancementConfig<T> { | ||
@@ -202,3 +175,3 @@ host: Element; | ||
*/ | ||
component: T; | ||
component: T | Constructable<T>; | ||
/** | ||
@@ -205,0 +178,0 @@ * A predefined container for the enhanced view. |
@@ -105,8 +105,8 @@ import { IServiceLocator, Key, emptyArray } from '@aurelia/kernel'; | ||
/** @internal */ private readonly _innerBindings: IBinding[] = []; | ||
/** @internal */ private readonly _hydrationContext: IHydrationContext<object>; | ||
public constructor( | ||
/** @internal */ private readonly _hydrationContext: IHydrationContext<object>, | ||
hydrationContext: IHydrationContext<object>, | ||
) { | ||
this.$controller = _hydrationContext.controller; | ||
this.locator = this.$controller.container; | ||
this.locator = (this.$controller = (this._hydrationContext = hydrationContext).controller).container; | ||
} | ||
@@ -113,0 +113,0 @@ |
@@ -18,2 +18,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ | ||
value_converter_def_not_found = 152, | ||
element_existed = 153, | ||
attribute_existed = 154, | ||
value_converter_existed = 155, | ||
binding_behavior_existed = 156, | ||
binding_command_existed = 157, | ||
@@ -93,4 +98,3 @@ controller_cached_not_found = 500, | ||
au_compose_invalid_scope_behavior = 805, | ||
// originally not supported | ||
// au_compose_containerless = 806, | ||
au_compose_component_name_not_found = 806, | ||
au_compose_invalid_run = 807, | ||
@@ -127,2 +131,7 @@ au_compose_duplicate_deactivate = 808, | ||
[ErrorNames.value_converter_def_not_found]: `No value converter definition found for type {{0:name}}`, | ||
[ErrorNames.element_existed]: `Element {{0}} has already been registered.`, | ||
[ErrorNames.attribute_existed]: `Attribute {{0}} has already been registered.`, | ||
[ErrorNames.value_converter_existed]: `Value converter {{0}} has already been registered.`, | ||
[ErrorNames.binding_behavior_existed]: `Binding behavior {{0}} has already been registered.`, | ||
[ErrorNames.binding_command_existed]: `Binding command {{0}} has already been registered.`, | ||
@@ -177,3 +186,3 @@ [ErrorNames.controller_cached_not_found]: `There is no cached controller for the provided ViewModel: {{0}}`, | ||
[ErrorNames.aurelia_instance_existed_in_container]: `An instance of Aurelia is already registered with the container or an ancestor of it.`, | ||
[ErrorNames.invalid_platform_impl]: `Failed to initialize the platform object. The host element's ownerDocument does not have a defaultView`, | ||
[ErrorNames.invalid_platform_impl]: `Failed to initialize the platform object. The host element's ownerDocument does not have a defaultView, did you create the host from a DOMParser and forget to call adoptNode()?`, | ||
[ErrorNames.no_composition_root]: `Aurelia.start() was called without a composition root`, | ||
@@ -207,3 +216,3 @@ [ErrorNames.invalid_dispose_call]: `The aurelia instance must be fully stopped before it can be disposed`, | ||
// originally not supported | ||
// [ErrorNames.au_compose_containerless]: `Containerless custom element {{0:name}} is not supported by <au-compose />`, | ||
[ErrorNames.au_compose_component_name_not_found]: `<au-compose /> couldn't find a custom element with name "{{0}}", did you forget to register it locally or globally?`, | ||
[ErrorNames.au_compose_invalid_run]: `Composition has already been activated/deactivated. Id: {{0:controller}}`, | ||
@@ -210,0 +219,0 @@ [ErrorNames.au_compose_duplicate_deactivate]: `Composition has already been deactivated.`, |
@@ -40,5 +40,11 @@ export { | ||
type IEnhancementConfig, | ||
/** | ||
* @deprecated | ||
* Use `ISinglePageAppConfig` instead | ||
*/ | ||
type ISinglePageAppConfig as ISinglePageApp, | ||
type ISinglePageAppConfig, | ||
} from './aurelia'; | ||
export { | ||
type ISinglePageApp, | ||
type IAppRootConfig, | ||
AppRoot, | ||
@@ -277,5 +283,2 @@ IAppRoot, | ||
} from './resources/custom-elements/au-slot'; | ||
export type { | ||
DefinitionType, | ||
} from './resources/resources-shared'; | ||
@@ -287,2 +290,3 @@ export { | ||
CustomElement, | ||
type InjectableToken, | ||
type CustomElementDecorator, | ||
@@ -289,0 +293,0 @@ type CustomElementKind, |
import { firstDefined, mergeArrays, ResourceType } from '@aurelia/kernel'; | ||
import { BindingBehaviorInstance } from '@aurelia/runtime'; | ||
import { isFunction, isString, objectFreeze } from '../utilities'; | ||
import { aliasRegistration, registerAliases, singletonRegistration } from '../utilities-di'; | ||
import { aliasRegistration, singletonRegistration } from '../utilities-di'; | ||
import { appendResourceKey, defineMetadata, getAnnotationKeyFor, getOwnMetadata, getResourceKeyFor, hasOwnMetadata } from '../utilities-metadata'; | ||
@@ -67,5 +67,12 @@ | ||
const { Type, key, aliases } = this; | ||
singletonRegistration(key, Type).register(container); | ||
aliasRegistration(key, Type).register(container); | ||
registerAliases(aliases, BindingBehavior, key, container); | ||
if (!container.has(key, false)) { | ||
container.register( | ||
singletonRegistration(key, Type), | ||
aliasRegistration(key, Type), | ||
...aliases.map(alias => aliasRegistration(Type, BindingBehavior.keyFrom(alias))), | ||
); | ||
} /* istanbul ignore next */ else if (__DEV__) { | ||
// eslint-disable-next-line no-console | ||
console.warn(`[DEV:aurelia] ${createMappedError(ErrorNames.binding_behavior_existed)}`); | ||
} | ||
} | ||
@@ -91,3 +98,2 @@ } | ||
defineMetadata(bbBaseName, definition, definition.Type); | ||
defineMetadata(bbBaseName, definition, definition); | ||
appendResourceKey(Type, bbBaseName); | ||
@@ -94,0 +100,0 @@ |
@@ -16,3 +16,3 @@ import { camelCase, mergeArrays, firstDefined, emptyArray } from '@aurelia/kernel'; | ||
import { etIsFunction, etIsIterator, etIsProperty, isString, objectFreeze } from '../utilities'; | ||
import { aliasRegistration, registerAliases, singletonRegistration } from '../utilities-di'; | ||
import { aliasRegistration, singletonRegistration } from '../utilities-di'; | ||
@@ -33,2 +33,3 @@ import type { | ||
import { dtElement } from './resources-shared'; | ||
import { ErrorNames, createMappedError } from '../errors'; | ||
@@ -126,5 +127,12 @@ export const ctNone = 'None' as const; | ||
const { Type, key, aliases } = this; | ||
singletonRegistration(key, Type).register(container); | ||
aliasRegistration(key, Type).register(container); | ||
registerAliases(aliases, BindingCommand, key, container); | ||
if (!container.has(key, false)) { | ||
container.register( | ||
singletonRegistration(key, Type), | ||
aliasRegistration(key, Type), | ||
...aliases.map(alias => aliasRegistration(key, BindingCommand.keyFrom(alias))), | ||
); | ||
} /* istanbul ignore next */ else if (__DEV__) { | ||
// eslint-disable-next-line no-console | ||
console.warn(`[DEV:aurelia] ${createMappedError(ErrorNames.binding_command_existed)}`); | ||
} | ||
} | ||
@@ -150,3 +158,2 @@ } | ||
defineMetadata(cmdBaseName, definition, definition.Type); | ||
defineMetadata(cmdBaseName, definition, definition); | ||
appendResourceKey(Type, cmdBaseName); | ||
@@ -153,0 +160,0 @@ |
@@ -7,3 +7,3 @@ import { mergeArrays, firstDefined, Key } from '@aurelia/kernel'; | ||
import { isFunction, isString, objectFreeze } from '../utilities'; | ||
import { aliasRegistration, registerAliases, transientRegistration } from '../utilities-di'; | ||
import { aliasRegistration, transientRegistration } from '../utilities-di'; | ||
import { type BindingMode, toView } from '../binding/interfaces-bindings'; | ||
@@ -102,3 +102,3 @@ | ||
// a simple marker to distinguish between Custom Element definition & Custom attribute definition | ||
public get type(): 'Attribute' { return dtAttribute; } | ||
public get type(): 'attribute' { return dtAttribute; } | ||
@@ -148,5 +148,12 @@ private constructor( | ||
const { Type, key, aliases } = this; | ||
transientRegistration(key, Type).register(container); | ||
aliasRegistration(key, Type).register(container); | ||
registerAliases(aliases, CustomAttribute, key, container); | ||
if (!container.has(key, false)) { | ||
container.register( | ||
transientRegistration(key, Type), | ||
aliasRegistration(key, Type), | ||
...aliases.map(alias => aliasRegistration(Type, CustomAttribute.keyFrom(alias))) | ||
); | ||
} /* istanbul ignore next */ else if (__DEV__) { | ||
// eslint-disable-next-line no-console | ||
console.warn(`[DEV:aurelia] ${createMappedError(ErrorNames.attribute_existed)}`); | ||
} | ||
} | ||
@@ -184,3 +191,2 @@ | ||
defineMetadata(caBaseName, definition, definition.Type); | ||
defineMetadata(caBaseName, definition, definition); | ||
appendResourceKey(Type, caBaseName); | ||
@@ -187,0 +193,0 @@ |
@@ -15,3 +15,3 @@ import { | ||
import { def, isFunction, isString, objectAssign, objectFreeze } from '../utilities'; | ||
import { aliasRegistration, registerAliases, transientRegistration } from '../utilities-di'; | ||
import { aliasRegistration, transientRegistration } from '../utilities-di'; | ||
@@ -26,3 +26,2 @@ import type { | ||
ResourceDefinition, | ||
Injectable, | ||
IResolver, | ||
@@ -202,3 +201,3 @@ Writable, | ||
export class CustomElementDefinition<C extends Constructable = Constructable> implements ResourceDefinition<C, ICustomElementViewModel, PartialCustomElementDefinition> { | ||
public get type(): 'Element' { return dtElement; } | ||
public get type(): 'element' { return dtElement; } | ||
private constructor( | ||
@@ -370,6 +369,12 @@ public readonly Type: CustomElementType<C>, | ||
const { Type, key, aliases } = this; | ||
// todo: warn if alreay has key | ||
if (!container.has(key, false)) { | ||
transientRegistration(key, Type).register(container); | ||
aliasRegistration(key, Type).register(container); | ||
registerAliases(aliases, CustomElement, key, container); | ||
container.register( | ||
transientRegistration(key, Type), | ||
aliasRegistration(key, Type), | ||
...aliases.map(alias => aliasRegistration(Type, CustomElement.keyFrom(alias))) | ||
); | ||
} /* istanbul ignore next */ else if (__DEV__) { | ||
// eslint-disable-next-line no-console | ||
console.warn(`[DEV:aurelia] ${createMappedError(ErrorNames.element_existed)}`); | ||
} | ||
@@ -383,5 +388,7 @@ } | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars | ||
export type InjectableToken<K = any> = (target: Injectable, property: string | symbol | undefined, index: number) => void; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export type InjectableToken<K = any> = ((target: Constructable, property: string | symbol | undefined, index: number) => void) & { | ||
readonly __resolved__: K | null; | ||
}; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
type InternalInjectableToken<K = any> = InjectableToken<K> & { | ||
@@ -428,3 +435,2 @@ register?(container: IContainer): IResolver<K>; | ||
defineMetadata(elementBaseName, definition, definition.Type); | ||
defineMetadata(elementBaseName, definition, definition); | ||
appendResourceKey(definition.Type, elementBaseName); | ||
@@ -519,20 +525,18 @@ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const $injectable: InternalInjectableToken<K> = function (target, property, index): any { | ||
const $injectable = function (target, property, index): any { | ||
const annotationParamtypes = DI.getOrCreateAnnotationParamTypes(target); | ||
annotationParamtypes[index] = $injectable; | ||
return target; | ||
}; | ||
} as InternalInjectableToken<K>; | ||
$injectable.register = function (_container) { | ||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions | ||
return { | ||
resolve(container, requestor) { | ||
if (requestor.has($injectable, true)) { | ||
return requestor.get($injectable); | ||
} else { | ||
return null; | ||
} | ||
}, | ||
} as IResolver; | ||
}; | ||
$injectable.register = (): IResolver => ({ | ||
$isResolver: true, | ||
resolve(container, requestor) { | ||
if (requestor.has($injectable, true)) { | ||
return requestor.get($injectable); | ||
} else { | ||
return null; | ||
} | ||
} | ||
}); | ||
@@ -559,3 +563,3 @@ return $injectable; | ||
// looking similarly from the outside (when inspected via debugger, etc). | ||
const Type = class { } as CustomElementType<Constructable<P>>; | ||
const Type = class Anonymous { } as CustomElementType<Constructable<P>>; | ||
@@ -562,0 +566,0 @@ // Define the name property so that Type.name can be used by end users / plugin authors if they really need to, |
@@ -1,8 +0,8 @@ | ||
import { Constructable, IContainer, InstanceProvider, emptyArray, onResolve, resolve, transient } from '@aurelia/kernel'; | ||
import { Constructable, IContainer, InstanceProvider, MaybePromise, emptyArray, onResolve, resolve, transient } from '@aurelia/kernel'; | ||
import { IExpressionParser, IObserverLocator, Scope } from '@aurelia/runtime'; | ||
import { bindable } from '../../bindable'; | ||
import { INode, IRenderLocation, convertToRenderLocation, isRenderLocation, registerHostNode } from '../../dom'; | ||
import { INode, IRenderLocation, convertToRenderLocation, registerHostNode } from '../../dom'; | ||
import { IPlatform } from '../../platform'; | ||
import { HydrateElementInstruction, IInstruction, ITemplateCompiler } from '../../renderer'; | ||
import { Controller, HydrationContext, IController, ICustomElementController, IHydratedController, IHydrationContext, ISyntheticView } from '../../templating/controller'; | ||
import { Controller, HydrationContext, IController, ICustomElementController, IHydratedController, IHydrationContext, ISyntheticView, vmkCe } from '../../templating/controller'; | ||
import { IRendering } from '../../templating/rendering'; | ||
@@ -28,4 +28,3 @@ import { isFunction, isPromise } from '../../utilities'; | ||
type MaybePromise<T> = T | Promise<T>; | ||
type ChangeSource = keyof Pick<AuCompose, 'template' | 'component' | 'model' | 'scopeBehavior' | 'composing' | 'composition'>; | ||
type ChangeSource = keyof Pick<AuCompose, 'template' | 'component' | 'model' | 'scopeBehavior' | 'composing' | 'composition' | 'tag'>; | ||
@@ -41,5 +40,15 @@ // Desired usage: | ||
/* determine the component instance used to compose the component */ | ||
/** | ||
* Determine the component instance used to compose the component. | ||
* | ||
* - When a string is given as a value, it will be used as the name of the custom element to compose. | ||
* If there is no locally or globally registered custom element with that name, an error will be thrown. | ||
* | ||
* - When an object is given as a value, the object will be used as the component instance. | ||
* - When a constructor is given as a value, the constructor will be used to create the component instance. | ||
* - When a null/undefined is given as a value, the component will be composed as a template-only composition with an empty component instance. | ||
* - When a promise is given as a value, the promise will be awaited and the resolved value will be used as the value. | ||
*/ | ||
@bindable | ||
public component?: Constructable | object | Promise<Constructable | object>; | ||
public component?: string | Constructable | object | Promise<string | Constructable | object>; | ||
@@ -68,5 +77,2 @@ /* the model used to pass to activate lifecycle of the component */ | ||
/** @internal */ | ||
public readonly $controller!: ICustomElementController<AuCompose>; | ||
/** @internal */ | ||
private _composing?: Promise<void> | void; | ||
@@ -89,5 +95,14 @@ @bindable({ | ||
/** | ||
* The tag name of the element to be created for non custom element composition. | ||
* | ||
* `null`/`undefined` means containerless | ||
*/ | ||
@bindable | ||
public tag: string | null | undefined = null; | ||
/** @internal */ public readonly $controller!: ICustomElementController<AuCompose>; | ||
/** @internal */ private readonly _container = resolve(IContainer); | ||
/** @internal */ private readonly parent = resolve(IController) as ISyntheticView | ICustomElementController; | ||
/** @internal */ private readonly host = resolve(INode) as HTMLElement; | ||
/** @internal */ private readonly _host = resolve(INode) as HTMLElement; | ||
/** @internal */ private readonly _location = resolve(IRenderLocation); | ||
@@ -126,6 +141,13 @@ /** @internal */ private readonly _platform = resolve(IPlatform); | ||
if (name === 'model' && this._composition != null) { | ||
// eslint-disable-next-line | ||
this._composition.update(this.model); | ||
return; | ||
} | ||
// tag change does not affect existing custom element composition | ||
if (name === 'tag' && this._composition?.controller.vmKind === vmkCe) { | ||
if (__DEV__) { | ||
console.warn('[DEV:aurelia] Changing tag name of a custom element composition is ignored.'); // eslint-disable-line | ||
} | ||
return; | ||
} | ||
this._composing = onResolve(this._composing, () => | ||
@@ -192,30 +214,57 @@ onResolve( | ||
private compose(context: CompositionContext): MaybePromise<ICompositionController> { | ||
let comp: IDynamicComponentActivate<unknown>; | ||
// todo: when both component and template are empty | ||
// should it throw or try it best to proceed? | ||
// current: proceed | ||
const { _template: template, _component: component, _model: model } = context.change; | ||
const { _container: container, host, $controller, _location: loc, _instruction } = this; | ||
const vmDef = this.getDef(component); | ||
const { | ||
_template: template, | ||
_component: component, | ||
_model: model | ||
} = context.change; | ||
const { | ||
_container: container, | ||
$controller, | ||
_location: loc, | ||
_instruction | ||
} = this; | ||
const vmDef = this._getDefinition(this._hydrationContext.controller.container, component); | ||
const childCtn: IContainer = container.createChild(); | ||
let compositionHost: HTMLElement | IRenderLocation; | ||
if (vmDef !== null) { | ||
compositionHost = this._platform.document.createElement(vmDef.name); | ||
if (loc == null) { | ||
host.appendChild(compositionHost); | ||
} else { | ||
loc.parentNode!.insertBefore(compositionHost, loc); | ||
} | ||
comp = this._getComp(childCtn, component, compositionHost); | ||
const compositionHost = this._platform.document.createElement(vmDef == null ? this.tag ?? 'div' : vmDef.name); | ||
loc.parentNode!.insertBefore(compositionHost, loc); | ||
let compositionLocation: IRenderLocation | null; | ||
if (vmDef == null) { | ||
compositionLocation = this.tag == null ? convertToRenderLocation(compositionHost) : null; | ||
} else { | ||
compositionHost = loc ?? host; | ||
comp = this._getComp(childCtn, component, compositionHost); | ||
compositionLocation = vmDef.containerless ? convertToRenderLocation(compositionHost) : null; | ||
} | ||
const removeCompositionHost = () => { | ||
compositionHost.remove(); | ||
if (compositionLocation != null) { | ||
let curr = compositionLocation.$start!.nextSibling; | ||
let next: ChildNode | null = null; | ||
while (curr !== null && curr !== compositionLocation) { | ||
next = curr.nextSibling; | ||
curr.remove(); | ||
curr = next; | ||
} | ||
compositionLocation.$start?.remove(); | ||
compositionLocation.remove(); | ||
} | ||
}; | ||
const comp = this._createComponentInstance( | ||
childCtn, | ||
typeof component === 'string' ? vmDef!.Type : component, | ||
compositionHost, | ||
compositionLocation | ||
); | ||
const compose: () => ICompositionController = () => { | ||
const aucomposeCapturedAttrs = _instruction.captures! ?? emptyArray; | ||
// custom element based composition | ||
if (vmDef !== null) { | ||
const composeCapturedAttrs = _instruction.captures! ?? emptyArray; | ||
const capture = vmDef.capture; | ||
const [capturedBindingAttrs, transferedToHostBindingAttrs] = composeCapturedAttrs | ||
const [capturedBindingAttrs, transferedToHostBindingAttrs] = aucomposeCapturedAttrs | ||
.reduce((attrGroups: [AttrSyntax[], AttrSyntax[]], attr) => { | ||
@@ -229,7 +278,6 @@ const shouldCapture = !(attr.target in vmDef.bindables) | ||
const location = vmDef.containerless ? convertToRenderLocation(compositionHost) : null; | ||
const controller = Controller.$el( | ||
childCtn, | ||
comp, | ||
compositionHost as HTMLElement, | ||
compositionHost, | ||
{ | ||
@@ -240,36 +288,4 @@ projections: _instruction.projections, | ||
vmDef, | ||
location | ||
compositionLocation | ||
); | ||
const transferHydrationContext = new HydrationContext( | ||
$controller, | ||
{ projections: null, captures: transferedToHostBindingAttrs}, | ||
this._hydrationContext.parent | ||
); | ||
const removeCompositionHost = () => { | ||
if (location == null) { | ||
(compositionHost as HTMLElement).remove(); | ||
} else { | ||
let curr = location.$start!.nextSibling; | ||
let next: ChildNode | null = null; | ||
while (curr !== null && curr !== location) { | ||
next = curr.nextSibling; | ||
curr.remove(); | ||
curr = next; | ||
} | ||
location.$start?.remove(); | ||
location.remove(); | ||
} | ||
}; | ||
const bindings = SpreadBinding.create( | ||
transferHydrationContext, | ||
compositionHost as HTMLElement, | ||
vmDef, | ||
this._rendering, | ||
this._compiler, | ||
this._platform, | ||
this._exprParser, | ||
this._observerLocator, | ||
); | ||
// Theoretically these bindings aren't bindings of the composed custom element | ||
@@ -279,3 +295,3 @@ // Though they are meant to be activated (bound)/ deactivated (unbound) together | ||
// custom element manage these bindings | ||
bindings.forEach(b => controller.addBinding(b)); | ||
this._createSpreadBindings(compositionHost, vmDef, transferedToHostBindingAttrs).forEach(b => controller.addBinding(b)); | ||
@@ -292,15 +308,6 @@ return new CompositionController( | ||
// but it's ignored in the caller anyway | ||
(model) => comp.activate?.(model) as MaybePromise<void>, | ||
(model) => comp.activate?.(model), | ||
context, | ||
); | ||
} else { | ||
if (__DEV__) { | ||
const captures = this._instruction.captures ?? []; | ||
if (captures.length > 0) { | ||
// eslint-disable-next-line no-console | ||
console.warn(`[au-compose]: Ignored bindings ${captures.map(({ rawName, rawValue }) => `${rawName}="${rawValue}"`).join(", ")}` | ||
+ ' in composition without a custom element definition as component.' | ||
); | ||
} | ||
} | ||
const targetDef = CustomElementDefinition.create({ | ||
@@ -319,6 +326,9 @@ name: CustomElement.generateName(), | ||
if (isRenderLocation(compositionHost)) { | ||
controller.setLocation(compositionHost); | ||
controller.setHost(compositionHost); | ||
if (compositionLocation == null) { | ||
// only spread the bindings if there is an actual host | ||
// otherwise we may accidentally do unnecessary work | ||
this._createSpreadBindings(compositionHost, targetDef, aucomposeCapturedAttrs).forEach(b => controller.addBinding(b)); | ||
} else { | ||
controller.setHost(compositionHost); | ||
controller.setLocation(compositionLocation); | ||
} | ||
@@ -332,6 +342,9 @@ | ||
// as they all share the same host/render location | ||
(detachInitiator) => controller.deactivate(detachInitiator ?? controller, $controller), | ||
(detachInitiator) => onResolve( | ||
controller.deactivate(detachInitiator ?? controller, $controller), | ||
removeCompositionHost | ||
), | ||
// casting is technically incorrect | ||
// but it's ignored in the caller anyway | ||
(model) => comp.activate?.(model) as MaybePromise<void>, | ||
(model) => comp.activate?.(model), | ||
context, | ||
@@ -351,3 +364,8 @@ ); | ||
/** @internal */ | ||
private _getComp(container: IContainer, comp: Constructable | object | undefined, host: HTMLElement | IRenderLocation): IDynamicComponentActivate<unknown> { | ||
private _createComponentInstance( | ||
container: IContainer, | ||
comp: Constructable | object | undefined, | ||
host: HTMLElement | IRenderLocation, | ||
location: IRenderLocation | null, | ||
): IDynamicComponentActivate<unknown> { | ||
if (comp == null) { | ||
@@ -361,8 +379,7 @@ return new EmptyComponent(); | ||
const p = this._platform; | ||
const isLocation = isRenderLocation(host); | ||
registerHostNode(container, p, isLocation ? null : host); | ||
registerHostNode(container, p, host); | ||
registerResolver( | ||
container, | ||
IRenderLocation, | ||
new InstanceProvider('IRenderLocation', isLocation ? host : null) | ||
new InstanceProvider('IRenderLocation', location) | ||
); | ||
@@ -377,3 +394,11 @@ | ||
/** @internal */ | ||
private getDef(component?: object | Constructable) { | ||
private _getDefinition(container: IContainer, component?: string | object | Constructable) { | ||
if (typeof component === 'string') { | ||
const def = container.find(CustomElement, component); | ||
if (def == null) { | ||
throw createMappedError(ErrorNames.au_compose_component_name_not_found, component); | ||
} | ||
return def; | ||
} | ||
const Ctor = (isFunction(component) | ||
@@ -386,2 +411,21 @@ ? component | ||
} | ||
/** @internal */ | ||
private _createSpreadBindings(host: HTMLElement, def: CustomElementDefinition, capturedAttrs: AttrSyntax[]) { | ||
const transferHydrationContext = new HydrationContext( | ||
this.$controller, | ||
{ projections: null, captures: capturedAttrs }, | ||
this._hydrationContext.parent | ||
); | ||
return SpreadBinding.create( | ||
transferHydrationContext, | ||
host, | ||
def, | ||
this._rendering, | ||
this._compiler, | ||
this._platform, | ||
this._exprParser, | ||
this._observerLocator, | ||
); | ||
} | ||
} | ||
@@ -392,2 +436,3 @@ | ||
capture: true, | ||
containerless: true, | ||
})(AuCompose); | ||
@@ -407,3 +452,3 @@ | ||
deactivate(detachInitator?: IHydratedController): void | Promise<void>; | ||
update(model: unknown): void | Promise<void>; | ||
update(model: unknown): unknown; | ||
} | ||
@@ -431,3 +476,3 @@ | ||
public readonly _template: MaybePromise<string> | undefined, | ||
public readonly _component: MaybePromise<Constructable | object> | undefined, | ||
public readonly _component: MaybePromise<string | Constructable | object> | undefined, | ||
public readonly _model: unknown, | ||
@@ -453,3 +498,3 @@ public readonly _src: ChangeSource | undefined, | ||
public readonly _template: string | undefined, | ||
public readonly _component: Constructable | object | undefined, | ||
public readonly _component: string | Constructable | object | undefined, | ||
public readonly _model: unknown, | ||
@@ -474,3 +519,3 @@ public readonly _src: ChangeSource | undefined, | ||
private readonly stop: (detachInitator?: IHydratedController) => void | Promise<void>, | ||
public readonly update: (model: unknown) => void | Promise<void>, | ||
public readonly update: (model: unknown) => unknown, | ||
public readonly context: CompositionContext, | ||
@@ -477,0 +522,0 @@ ) { |
@@ -1,3 +0,2 @@ | ||
export const dtElement = 'Element' as const; | ||
export const dtAttribute = 'Attribute' as const; | ||
export type DefinitionType = typeof dtElement | typeof dtAttribute; | ||
/** @internal */ export const dtElement = 'element'; | ||
/** @internal */ export const dtAttribute = 'attribute'; |
import { | ||
Registration, | ||
mergeArrays, | ||
firstDefined, | ||
} from '@aurelia/kernel'; | ||
import { registerAliases } from '../utilities-di'; | ||
import { aliasRegistration, singletonRegistration } from '../utilities-di'; | ||
import { isFunction, isString, objectFreeze } from '../utilities'; | ||
@@ -78,5 +77,12 @@ import { appendResourceKey, defineMetadata, getAnnotationKeyFor, getOwnMetadata, getResourceKeyFor, hasOwnMetadata } from '../utilities-metadata'; | ||
const { Type, key, aliases } = this; | ||
Registration.singleton(key, Type).register(container); | ||
Registration.aliasTo(key, Type).register(container); | ||
registerAliases(aliases, ValueConverter, key, container); | ||
if (!container.has(key, false)) { | ||
container.register( | ||
singletonRegistration(key, Type), | ||
aliasRegistration(key, Type), | ||
...aliases.map(alias => aliasRegistration(Type, ValueConverter.keyFrom(alias))) | ||
); | ||
} /* istanbul ignore next */ else if(__DEV__) { | ||
// eslint-disable-next-line no-console | ||
console.warn(`[DEV:aurelia] ${createMappedError(ErrorNames.value_converter_existed)}`); | ||
} | ||
} | ||
@@ -100,3 +106,2 @@ } | ||
defineMetadata(vcBaseName, definition, definition.Type); | ||
defineMetadata(vcBaseName, definition, definition); | ||
appendResourceKey(Type, vcBaseName); | ||
@@ -103,0 +108,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
4840133
230
87202
+ Added@aurelia/kernel@2.0.1-dev.202403021005(transitive)
+ Added@aurelia/metadata@2.0.1-dev.202403021005(transitive)
+ Added@aurelia/platform@2.0.1-dev.202403021005(transitive)
+ Added@aurelia/platform-browser@2.0.1-dev.202403021005(transitive)
+ Added@aurelia/runtime@2.0.1-dev.202403021005(transitive)
- Removed@aurelia/kernel@2.0.1-dev.202402130428(transitive)
- Removed@aurelia/metadata@2.0.1-dev.202402130428(transitive)
- Removed@aurelia/platform@2.0.1-dev.202402130428(transitive)
- Removed@aurelia/platform-browser@2.0.1-dev.202402130428(transitive)
- Removed@aurelia/runtime@2.0.1-dev.202402130428(transitive)