remove single purpose mixins

This commit is contained in:
Niels Lyngsø
2023-01-04 10:41:40 +01:00
parent 0128d37097
commit 2cb3bde4c8
4 changed files with 3 additions and 212 deletions

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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');
});
});

View File

@@ -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;
}
}