remove single purpose mixins
This commit is contained in:
@@ -1,111 +0,0 @@
|
||||
import type { HTMLElementConstructor } from '../../models';
|
||||
import { UmbContextConsumer } from './context-consumer';
|
||||
|
||||
export declare class UmbContextConsumerInterface {
|
||||
consumeContext(alias: string, callback: (_instance: any) => void): void;
|
||||
consumeAllContexts(contextAliases: string[], callback: (_instances: ResolvedContexts) => void): void;
|
||||
whenAvailableOrChanged(contextAliases: string[], callback?: () => void): void;
|
||||
}
|
||||
|
||||
// TODO: can we use this aliases to generate the key of this type
|
||||
interface ResolvedContexts {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* This mixin enables the component to consume contexts.
|
||||
* This is done by calling the `consumeContext` method.
|
||||
*
|
||||
* @param {Object} superClass - superclass to be extended.
|
||||
* @mixin
|
||||
*/
|
||||
export const UmbContextConsumerMixin = <T extends HTMLElementConstructor>(superClass: T) => {
|
||||
class UmbContextConsumerClass extends superClass {
|
||||
// all context requesters in the element
|
||||
_consumers: Map<string, UmbContextConsumer[]> = new Map();
|
||||
// all successfully resolved context requests
|
||||
_resolved: Map<string, any> = new Map();
|
||||
|
||||
_attached = false;
|
||||
|
||||
/**
|
||||
* Setup a subscription for a context. The callback is called when the context is resolved.
|
||||
* @param {string} alias
|
||||
* @param {method} callback Callback method called when context is resolved.
|
||||
*/
|
||||
consumeContext(alias: string, callback: (_instance: any) => void): void {
|
||||
this._createContextConsumers([alias], (resolvedContexts) => {
|
||||
callback(resolvedContexts[alias]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup a subscription for multiple contexts. The callback is called when all contexts are resolved.
|
||||
* @param {string} aliases
|
||||
* @param {method} callback Callback method called when all contexts are resolved.
|
||||
*/
|
||||
consumeAllContexts(_contextAliases: Array<string>, callback: (_instances: ResolvedContexts) => void) {
|
||||
this._createContextConsumers(_contextAliases, (resolvedContexts) => {
|
||||
callback?.(resolvedContexts);
|
||||
});
|
||||
}
|
||||
|
||||
private _createContextConsumers(aliases: Array<string>, resolvedCallback: (_instances: ResolvedContexts) => void) {
|
||||
aliases.forEach((alias) => {
|
||||
const consumer = new UmbContextConsumer(this, alias, (_instance: any) => {
|
||||
this._resolved.set(alias, _instance);
|
||||
|
||||
const result: ResolvedContexts = {};
|
||||
|
||||
//check if all contexts are resolved
|
||||
const resolvedContexts = aliases.map((alias) => (result[alias] = this._resolved.get(alias)));
|
||||
const allResolved = resolvedContexts.every((context) => context !== undefined);
|
||||
|
||||
if (allResolved) {
|
||||
resolvedCallback(result);
|
||||
}
|
||||
});
|
||||
|
||||
if (this._consumers.has(alias)) {
|
||||
const consumers = this._consumers.get(alias);
|
||||
consumers?.push(consumer);
|
||||
} else {
|
||||
this._consumers.set(alias, [consumer]);
|
||||
}
|
||||
|
||||
if (this._attached) {
|
||||
consumer.hostConnected();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: remove requester..
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback?.();
|
||||
this._attached = true;
|
||||
this._consumers.forEach((consumers) => consumers.forEach((consumer) => consumer.hostConnected()));
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback?.();
|
||||
this._attached = false;
|
||||
this._consumers.forEach((consumers) => consumers.forEach((consumer) => consumer.hostDisconnected()));
|
||||
this._resolved.clear();
|
||||
}
|
||||
|
||||
// might return a object, so you can unsubscribe.
|
||||
whenAvailableOrChanged(_contextAliases: string[]) {
|
||||
// TODO: To be done.
|
||||
}
|
||||
}
|
||||
|
||||
return UmbContextConsumerClass as unknown as HTMLElementConstructor<UmbContextConsumerInterface> & T;
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface HTMLElement {
|
||||
connectedCallback(): void;
|
||||
disconnectedCallback(): void;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
import { html, LitElement } from 'lit';
|
||||
import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import { UmbContextProviderMixin } from './context-provider.mixin';
|
||||
import { UmbLitElement } from '@umbraco-cms/element';
|
||||
|
||||
@customElement('umb-context-provider')
|
||||
export class UmbContextProviderElement extends UmbContextProviderMixin(LitElement) {
|
||||
export class UmbContextProviderElement extends UmbLitElement {
|
||||
/**
|
||||
* The value to provide to the context.
|
||||
* @required
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import { expect, fixture, html } from '@open-wc/testing';
|
||||
import { UmbContextProvider } from './context-provider';
|
||||
import { UmbContextProviderMixin } from './context-provider.mixin';
|
||||
|
||||
class MyClass {
|
||||
prop: string;
|
||||
|
||||
constructor(text: string) {
|
||||
this.prop = text;
|
||||
}
|
||||
}
|
||||
|
||||
class MyTestProviderElement extends UmbContextProviderMixin(HTMLElement) {
|
||||
constructor() {
|
||||
super();
|
||||
this.provideContext('my-test-context-1', new MyClass('context value 1'));
|
||||
this.provideContext('my-test-context-2', new MyClass('context value 2'));
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('my-test-provider-element', MyTestProviderElement);
|
||||
|
||||
describe('UmbContextProviderMixin', async () => {
|
||||
let element: MyTestProviderElement;
|
||||
let _providers: Map<string, UmbContextProvider>;
|
||||
|
||||
beforeEach(async () => {
|
||||
element = await fixture(html`<my-test-provider-element></my-test-provider-element>`);
|
||||
_providers = (element as any)['_providers'];
|
||||
});
|
||||
|
||||
it('sets all providers to element', () => {
|
||||
expect(_providers.has('my-test-context-1')).to.be.true;
|
||||
expect(_providers.has('my-test-context-2')).to.be.true;
|
||||
});
|
||||
|
||||
it('can not set context with same key as already existing context', () => {
|
||||
const provider = _providers.get('my-test-context-1');
|
||||
expect(provider).to.not.be.undefined;
|
||||
if (!provider) return;
|
||||
expect((provider['_instance'] as MyClass).prop).to.eq('context value 1');
|
||||
element.provideContext('my-test-context-1', new MyClass('new context value 1'));
|
||||
expect((provider['_instance'] as MyClass).prop).to.eq('context value 1');
|
||||
});
|
||||
});
|
||||
@@ -1,52 +0,0 @@
|
||||
import type { HTMLElementConstructor } from '../../models';
|
||||
import { UmbContextProvider } from './context-provider';
|
||||
|
||||
export declare class UmbContextProviderMixinInterface {
|
||||
provideContext(alias: string, instance: unknown): void;
|
||||
}
|
||||
|
||||
export const UmbContextProviderMixin = <T extends HTMLElementConstructor>(superClass: T) => {
|
||||
class UmbContextProviderClass extends superClass {
|
||||
_providers: Map<string, UmbContextProvider> = new Map();
|
||||
|
||||
_attached = false;
|
||||
|
||||
provideContext(alias: string, instance: unknown) {
|
||||
// TODO: Consider if its right to re-publish the context?
|
||||
const existingProvider = this._providers.get(alias);
|
||||
if (existingProvider) {
|
||||
existingProvider.hostDisconnected();
|
||||
}
|
||||
|
||||
const provider = new UmbContextProvider(this, alias, instance);
|
||||
this._providers.set(alias, provider);
|
||||
// TODO: if already connected then attach the new one.
|
||||
if (this._attached) {
|
||||
provider.hostConnected();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: unprovide method to enforce a detach?
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback?.();
|
||||
this._attached = true;
|
||||
this._providers.forEach((provider) => provider.hostConnected());
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback?.();
|
||||
this._attached = false;
|
||||
this._providers.forEach((provider) => provider.hostDisconnected());
|
||||
}
|
||||
}
|
||||
|
||||
return UmbContextProviderClass as unknown as HTMLElementConstructor<UmbContextProviderMixinInterface> & T;
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface HTMLElement {
|
||||
connectedCallback(): void;
|
||||
disconnectedCallback(): void;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user