diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts index 57c754f35d..e3b82c2da9 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.test.ts @@ -1,5 +1,6 @@ import { expect, oneEvent } from '@open-wc/testing'; import { UmbContextProvider } from '../provide/context-provider.js'; +import { UmbContextToken } from '../token/context-token.js'; import { UmbContextConsumer } from './context-consumer.js'; import { UmbContextRequestEventImplementation, umbContextRequestEventType } from './context-request.event.js'; @@ -111,10 +112,14 @@ describe('UmbContextConsumer with discriminator test', () => { it('discriminator determines the instance type', async () => { - const localConsumer = new UmbContextConsumer(document.body, testContextAlias, (instance: A) => { console.log(instance)}, discriminator); + const localConsumer = new UmbContextConsumer( + document.body, + new UmbContextToken(testContextAlias, discriminator), + (instance: A) => { console.log(instance)} + ); localConsumer.hostConnected(); - // This bit of code is just to make sure the type is correct. + // This bit of code is not really a test but it serves as a TypeScript type test, making sure the given type is matches the one given from the Discriminator method. type TestType = Exclude<(typeof localConsumer.instance), undefined> extends A ? true : never; const test: TestType = true; expect(test).to.be.true; @@ -131,14 +136,13 @@ describe('UmbContextConsumer with discriminator test', () => { const localConsumer = new UmbContextConsumer( element, - testContextAlias, + new UmbContextToken(testContextAlias, discriminator), (_instance) => { expect(_instance.prop).to.eq('value from provider'); done(); localConsumer.hostDisconnected(); provider.hostDisconnected(); - }, - discriminator + } ); localConsumer.hostConnected(); }); @@ -152,11 +156,10 @@ describe('UmbContextConsumer with discriminator test', () => { const localConsumer = new UmbContextConsumer( element, - testContextAlias, + new UmbContextToken(testContextAlias, badDiscriminator), (_instance) => { expect(_instance.prop).to.eq('this must not happen!'); - }, - badDiscriminator + } ); localConsumer.hostConnected(); diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts index ec3ef625d3..f671be1a38 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/consume/context-consumer.ts @@ -1,4 +1,4 @@ -import { UmbContextToken } from '../token/context-token.js'; +import { UmbContextDiscriminator, UmbContextToken } from '../token/context-token.js'; import { isUmbContextProvideEventType, //isUmbContextUnprovidedEventType, @@ -7,25 +7,23 @@ import { } from '../provide/context-provide.event.js'; import { UmbContextRequestEventImplementation, UmbContextCallback } from './context-request.event.js'; -export type UmbContextDiscriminator = (instance: T) => instance is DiscriminatorResult; - /** * @export * @class UmbContextConsumer */ -export class UmbContextConsumer { - #callback?: UmbContextCallback; - #promise?: Promise; - #promiseResolver?: (instance: D) => void; +export class UmbContextConsumer { + #callback?: UmbContextCallback; + #promise?: Promise; + #promiseResolver?: (instance: DiscriminatedType) => void; - #instance?: D; + #instance?: DiscriminatedType; get instance() { return this.#instance; } #contextAlias: string; - #discriminator?: UmbContextDiscriminator; + #discriminator?: UmbContextDiscriminator; /** * Creates an instance of UmbContextConsumer. @@ -36,13 +34,12 @@ export class UmbContextConsumer { */ constructor( protected hostElement: EventTarget, - contextAlias: string | UmbContextToken, - callback?: UmbContextCallback, - discriminator?: UmbContextDiscriminator + contextAlias: string | UmbContextToken, + callback?: UmbContextCallback ) { this.#contextAlias = contextAlias.toString(); this.#callback = callback; - this.#discriminator = discriminator; + this.#discriminator = (contextAlias as any).getDiscriminator?.(); } @@ -51,7 +48,7 @@ export class UmbContextConsumer { The reason for such would be to have some who are more specific than others. For example, some might just need the current workspace-context, others might need the closest handling a certain entityType. As I'm writing this is not relevant, but I wanted to keep the idea as we have had some circumstance that might be solved with this approach. */ - protected _onResponse = (instance: T) => { + protected _onResponse = (instance: BaseType) => { if (this.#instance === instance) { return; } @@ -61,11 +58,11 @@ export class UmbContextConsumer { this.setInstance(instance); } } else { - this.setInstance(instance as D); + this.setInstance(instance as DiscriminatedType); } }; - protected setInstance(instance: D) { + protected setInstance(instance: DiscriminatedType) { this.#instance = instance; this.#callback?.(instance); if (instance !== undefined) { @@ -77,7 +74,7 @@ export class UmbContextConsumer { public asPromise() { return ( this.#promise ?? - (this.#promise = new Promise((resolve) => { + (this.#promise = new Promise((resolve) => { this.#instance ? resolve(this.#instance) : (this.#promiseResolver = resolve); })) ); diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/token/context-token.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/token/context-token.ts index 7ad36b1b4e..826d1ca066 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/token/context-token.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/token/context-token.ts @@ -1,4 +1,9 @@ -export class UmbContextToken { + +export type UmbContextDiscriminator = (instance: BaseType) => instance is DiscriminatorResult; + +export class UmbContextToken { + + #discriminator: UmbContextDiscriminator | undefined; /** * Get the type of the token * @@ -8,15 +13,18 @@ export class UmbContextToken { * @example `typeof MyToken.TYPE` * @returns undefined */ - readonly TYPE: T = undefined as never; + readonly TYPE: DiscriminatedType = undefined as never; /** - * @param alias Unique identifier for the token, - * @param _desc Description for the token, - * used only for debugging purposes, - * it should but does not need to be unique + * @param alias Unique identifier for the token */ - constructor(protected alias: string, protected _desc?: string) {} + constructor(protected alias: string, discriminator?: UmbContextDiscriminator) { + this.#discriminator = discriminator; + } + + getDiscriminator(): UmbContextDiscriminator | undefined { + return this.#discriminator; + } /** * This method must always return the unique alias of the token since that @@ -27,4 +35,6 @@ export class UmbContextToken { toString(): string { return this.alias; } + + }