BREAKING(core): remove unused UpdateStylesMixin & DelegateMixin

This commit is contained in:
Thomas Allmer 2022-08-19 16:32:36 +02:00 committed by Thomas Allmer
parent 3d25b152f3
commit cc294f2023
9 changed files with 5 additions and 913 deletions

View file

@ -0,0 +1,5 @@
---
'@lion/core': minor
---
BREAKING: Remove unused `UpdateStylesMixin` & `DelegateMixin`

View file

@ -77,12 +77,10 @@ export { until } from 'lit/directives/until.js';
export { ScopedElementsMixin } from '@open-wc/scoped-elements';
export { dedupeMixin } from '@open-wc/dedupe-mixin';
// ours
export { DelegateMixin } from './src/DelegateMixin.js';
export { DisabledMixin } from './src/DisabledMixin.js';
export { DisabledWithTabIndexMixin } from './src/DisabledWithTabIndexMixin.js';
export { ScopedStylesController } from './src/ScopedStylesController.js';
export { SlotMixin } from './src/SlotMixin.js';
export { UpdateStylesMixin } from './src/UpdateStylesMixin.js';
export { browserDetection } from './src/browserDetection.js';
export { EventTargetShim } from './src/EventTargetShim.js';
export { uuid } from './src/uuid.js';

View file

@ -68,12 +68,10 @@ export { until } from 'lit/directives/until.js';
export { ScopedElementsMixin } from '@open-wc/scoped-elements';
export { dedupeMixin } from '@open-wc/dedupe-mixin';
// ours
export { DelegateMixin } from './src/DelegateMixin.js';
export { DisabledMixin } from './src/DisabledMixin.js';
export { DisabledWithTabIndexMixin } from './src/DisabledWithTabIndexMixin.js';
export { ScopedStylesController } from './src/ScopedStylesController.js';
export { SlotMixin } from './src/SlotMixin.js';
export { UpdateStylesMixin } from './src/UpdateStylesMixin.js';
export { browserDetection } from './src/browserDetection.js';
export { EventTargetShim } from './src/EventTargetShim.js';
export { uuid } from './src/uuid.js';

View file

@ -1,203 +0,0 @@
/* eslint-disable class-methods-use-this */
import { dedupeMixin } from '@open-wc/dedupe-mixin';
/**
* @typedef {import('../types/DelegateMixinTypes').DelegateMixin} DelegateMixin
*/
/**
* @typedef DelegateEvent
* @property {string} type - Type of event
* @property {(event: Event) => unknown} handler - Event arguments
* @property {boolean | AddEventListenerOptions} [opts]
*/
/**
* @type {DelegateMixin}
* @param {import('@open-wc/dedupe-mixin').Constructor<import('../index').LitElement>} superclass
*/
const DelegateMixinImplementation = superclass =>
// eslint-disable-next-line
// @ts-ignore https://github.com/microsoft/TypeScript/issues/36821#issuecomment-588375051
class extends superclass {
constructor() {
super();
/**
* @type {DelegateEvent[]}
* @private
*/
this.__eventsQueue = [];
/**
* @type {Object.<string,?>}
* @private
*/
this.__propertiesQueue = {};
/** @private */
this.__setupPropertyDelegation();
}
/**
* @returns {{target: Function, events: string[], methods: string[], properties: string[], attributes: string[]}}
*/
get delegations() {
return {
target: () => {},
events: [],
methods: [],
properties: [],
attributes: [],
};
}
connectedCallback() {
super.connectedCallback();
this._connectDelegateMixin();
}
/** @param {import('lit-element').PropertyValues } changedProperties */
updated(changedProperties) {
super.updated(changedProperties);
this._connectDelegateMixin();
}
/**
* @param {string} type
* @param {(event: Event) => unknown} handler
* @param {boolean | AddEventListenerOptions} [opts]
*/
addEventListener(type, handler, opts) {
const delegatedEvents = this.delegations.events;
if (delegatedEvents.indexOf(type) > -1) {
if (this.delegationTarget) {
this.delegationTarget.addEventListener(type, handler, opts);
} else {
this.__eventsQueue.push({ type, handler });
}
} else {
super.addEventListener(type, handler, opts);
}
}
/**
* @param {string} name
* @param {string} value
*/
setAttribute(name, value) {
const attributeNames = this.delegations.attributes;
if (attributeNames.indexOf(name) > -1) {
if (this.delegationTarget) {
this.delegationTarget.setAttribute(name, value);
}
super.removeAttribute(name);
} else {
super.setAttribute(name, value);
}
}
/**
* @param {string} name
*/
removeAttribute(name) {
const attributeNames = this.delegations.attributes;
if (attributeNames.indexOf(name) > -1) {
if (this.delegationTarget) {
this.delegationTarget.removeAttribute(name);
}
}
super.removeAttribute(name);
}
/**
* @protected
*/
_connectDelegateMixin() {
if (this.__connectedDelegateMixin) return;
if (!this.delegationTarget) {
this.delegationTarget = this.delegations.target();
}
if (this.delegationTarget) {
this.__emptyEventListenerQueue();
this.__emptyPropertiesQueue();
this.__initialAttributeDelegation();
this.__connectedDelegateMixin = true;
}
}
/**
* @private
*/
__setupPropertyDelegation() {
const propertyNames = this.delegations.properties.concat(this.delegations.methods);
propertyNames.forEach(propertyName => {
Object.defineProperty(this, propertyName, {
get() {
const target = this.delegationTarget;
if (target) {
if (typeof target[propertyName] === 'function') {
return target[propertyName].bind(target);
}
return target[propertyName];
}
if (this.__propertiesQueue[propertyName]) {
return this.__propertiesQueue[propertyName];
}
// This is the moment the attribute is not delegated (and thus removed) yet.
// and the property is not set, but the attribute is (it serves as a fallback for
// __propertiesQueue).
return this.getAttribute(propertyName);
},
set(newValue) {
if (this.delegationTarget) {
const oldValue = this.delegationTarget[propertyName];
this.delegationTarget[propertyName] = newValue;
// connect with observer system if available
if (typeof this.triggerObserversFor === 'function') {
this.triggerObserversFor(propertyName, newValue, oldValue);
}
} else {
this.__propertiesQueue[propertyName] = newValue;
}
},
});
});
}
/**
* @private
*/
__initialAttributeDelegation() {
const attributeNames = this.delegations.attributes;
attributeNames.forEach(attributeName => {
const attributeValue = this.getAttribute(attributeName);
if (typeof attributeValue === 'string') {
this.delegationTarget.setAttribute(attributeName, attributeValue);
super.removeAttribute(attributeName);
}
});
}
/**
* @private
*/
__emptyEventListenerQueue() {
this.__eventsQueue.forEach(ev => {
this.delegationTarget.addEventListener(ev.type, ev.handler, ev.opts);
});
}
/**
* @private
*/
__emptyPropertiesQueue() {
Object.keys(this.__propertiesQueue).forEach(propName => {
this.delegationTarget[propName] = this.__propertiesQueue[propName];
});
}
};
export const DelegateMixin = dedupeMixin(DelegateMixinImplementation);

View file

@ -1,82 +0,0 @@
/* global ShadyCSS */
import { dedupeMixin } from '@open-wc/dedupe-mixin';
/**
* @typedef {import('../types/UpdateStylesMixinTypes').UpdateStylesMixin} UpdateStylesMixin
* @typedef {import('../types/UpdateStylesMixinTypes').StylesMap} StylesMap
*/
/**
* @type {UpdateStylesMixin}
* @param {import('@open-wc/dedupe-mixin').Constructor<HTMLElement>} superclass
*/
const UpdateStylesMixinImplementation = superclass =>
// eslint-disable-next-line no-shadow
// @ts-ignore https://github.com/microsoft/TypeScript/issues/36821#issuecomment-588375051
class extends superclass {
/**
* @example
* <my-element>
* <style>
* :host {
* color: var(--foo);
* }
* </style>
* </my-element>
*
* $0.updateStyles({'background': 'orange', '--foo': '#fff'})
* Chrome, Firefox: <my-element style="background: orange; --foo: bar;">
* IE: <my-element>
* => to head: <style>color: #fff</style>
*
* @param {StylesMap} updateStyles
*/
updateStyles(updateStyles) {
const styleString = this.getAttribute('style') || this.getAttribute('data-style') || '';
/**
* reducer function
* @param {Object.<string, string>} acc
* @param {string} stylePair
*/
const reducer = (acc, stylePair) => {
/** @type {Array.<string>} */
const parts = stylePair.split(':');
if (parts.length === 2) {
// eslint-disable-next-line prefer-destructuring
acc[parts[0]] = parts[1];
}
return acc;
};
const currentStyles = styleString.split(';').reduce(reducer, {});
const newStyles = { ...currentStyles, ...updateStyles };
let newStylesString = '';
// @ts-ignore not sure how to type ShadyCSS..
if (typeof ShadyCSS === 'object' && !ShadyCSS.nativeShadow) {
// No ShadowDOM => IE, Edge
/** @type {Object.<string, string>} */
const newCssVariablesObj = {};
Object.keys(newStyles).forEach(key => {
if (key.indexOf('--') === -1) {
newStylesString += `${key}:${newStyles[key]};`;
} else {
newCssVariablesObj[key] = newStyles[key];
}
});
this.setAttribute('style', newStylesString);
// @ts-ignore not sure how to type ShadyCSS..
ShadyCSS.styleSubtree(this, newCssVariablesObj);
} else {
// has shadowdom => Chrome, Firefox, Safari
Object.keys(newStyles).forEach(key => {
newStylesString += `${key}: ${newStyles[key]};`;
});
this.setAttribute('style', newStylesString);
}
}
};
export const UpdateStylesMixin = dedupeMixin(UpdateStylesMixinImplementation);

View file

@ -1,449 +0,0 @@
import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing';
import sinon from 'sinon';
import { LitElement } from '../index.js';
import { DelegateMixin } from '../src/DelegateMixin.js';
describe('DelegateMixin', () => {
afterEach(() => {
sinon.restore();
});
it('delegates events', async () => {
const tag = defineCE(
class extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => this.shadowRoot?.getElementById('button1'),
events: ['click'],
};
}
render() {
return html`<button id="button1">with delegation</button>`;
}
},
);
const element = await fixture(`<${tag}></${tag}>`);
const cb = sinon.spy();
element.addEventListener('click', cb);
element.shadowRoot?.getElementById('button1')?.click();
expect(cb.callCount).to.equal(1);
});
it('delegates events before delegation target is attached to DOM', async () => {
const tag = defineCE(
class extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => this.shadowRoot?.getElementById('button1'),
events: ['click'],
};
}
render() {
return html`<button id="button1">with delegation</button>`;
}
},
);
const element = /** @type {LitElement} */ (document.createElement(tag));
const cb = sinon.spy();
element.addEventListener('click', cb);
document.body.appendChild(element);
await element.updateComplete;
element.shadowRoot?.getElementById('button1')?.click();
expect(cb.callCount).to.equal(1);
// cleanup
document.body.removeChild(element);
});
it('delegates if light and shadow dom is used at the same time', async () => {
const tag = defineCE(
class extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => Array.from(this.children).find(child => child.slot === 'button'),
events: ['click'],
methods: ['click'],
};
}
render() {
return html`
<span>Outside</span>
<slot name="button2"></slot>
`;
}
},
);
const element = await fixture(`<${tag}><button slot="button">click me</button></${tag}>`);
const cb = sinon.spy();
element.addEventListener('click', cb);
const childEl = /** @type {HTMLElement} */ (
Array.from(element.children)?.find(child => child.slot === 'button')
);
childEl?.click();
expect(cb.callCount).to.equal(1);
});
it('will still support other events', async () => {
class FooDelegate extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => this.shadowRoot?.getElementById('button1'),
events: ['click'],
};
}
render() {
return html`<button id="button1">with delegation</button>`;
}
foo() {
this.dispatchEvent(new CustomEvent('foo-event', { bubbles: true, composed: true }));
}
}
const tag = defineCE(FooDelegate);
const element = /** @type {FooDelegate} */ (await fixture(`<${tag}></${tag}>`));
const cb = sinon.spy();
element.addEventListener('foo-event', cb);
element.foo();
expect(cb.callCount).to.equal(1);
});
it('will call delegated methods', async () => {
const tag = defineCE(
class extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => this.shadowRoot?.getElementById('button1'),
methods: ['click'],
};
}
render() {
return html`<button id="button1">with delegation</button>`;
}
},
);
const element = /** @type {HTMLElement} */ (await fixture(`<${tag}></${tag}>`));
const cb = sinon.spy();
element.shadowRoot?.getElementById('button1')?.addEventListener('click', cb);
element.click();
expect(cb.callCount).to.equal(1);
});
it('supports arguments for delegated methods', async () => {
class DelegateArgumentSub extends LitElement {
constructor() {
super();
this.foo = { a: 'a', b: 'b' };
}
/**
* @param {?} a
* @param {?} b
*/
setFooAandB(a, b) {
this.foo.a = a;
this.foo.b = b;
}
}
customElements.define('delegate-argument-sub', DelegateArgumentSub);
class DelegateArgumentParent extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => this.shadowRoot?.getElementById('sub'),
methods: ['setFooAandB'],
};
}
render() {
return html`<delegate-argument-sub id="sub"></delegate-argument-sub>`;
}
}
const tag = defineCE(DelegateArgumentParent);
const element = /** @type {DelegateArgumentParent} */ (await fixture(`<${tag}></${tag}>`));
// @ts-ignore because this method, even though it doesn't exist on the parent, gets delegated through delegations to the child, where it does exist!
element.setFooAandB('newA', 'newB');
const sub = /** @type {DelegateArgumentSub} */ (element.shadowRoot?.getElementById('sub'));
expect(sub.foo.a).to.equal('newA');
expect(sub.foo.b).to.equal('newB');
});
it('will set delegated properties', async () => {
class PropDelegate extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => this.shadowRoot?.getElementById('button1'),
properties: ['disabled'],
};
}
render() {
return html`<button id="button1">with delegation</button>`;
}
}
const tag = defineCE(PropDelegate);
const element = /** @type {PropDelegate} */ (await fixture(`<${tag}></${tag}>`));
// @ts-ignore ignoring this one, because disabled is delegated through target so it indeed does not inherently exist on the div element
element.disabled = true;
await element.updateComplete;
/** @typedef {Object.<string,boolean>} Btn */
/** @typedef {Btn & HTMLElement} DelegatedBtn */
const btn = /** @type {DelegatedBtn} */ (element.shadowRoot?.getElementById('button1'));
expect(btn?.disabled).to.equal(true);
expect(btn?.hasAttribute('disabled')).to.equal(true);
});
it('delegates properties before delegation target is attached to DOM', async () => {
const tag = defineCE(
class extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => this.shadowRoot?.getElementById('button1'),
properties: ['disabled'],
};
}
render() {
return html`<button id="button1">with delegation</button>`;
}
},
);
/** @typedef {Object.<string,boolean>} Btn */
/** @typedef {Btn & LitElement} DelegatedEl */
const element = /** @type {DelegatedEl} */ (document.createElement(tag));
element.disabled = true;
document.body.appendChild(element);
await element.updateComplete;
/** @typedef {Btn & HTMLElement} DelegatedBtn */
const btn = /** @type {DelegatedBtn} */ (element.shadowRoot?.getElementById('button1'));
expect(btn?.disabled).to.equal(true);
// cleanup
document.body.removeChild(element);
});
it('will delegate setAttribute', async () => {
const tag = defineCE(
class extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => this.shadowRoot?.getElementById('button1'),
attributes: ['disabled'],
};
}
render() {
return html`<button id="button1">with delegation</button>`;
}
},
);
const element = /** @type {LitElement} */ (await fixture(`<${tag}></${tag}>`));
element.setAttribute('disabled', '');
await element.updateComplete;
expect(element.hasAttribute('disabled')).to.equal(false);
expect(element.shadowRoot?.getElementById('button1')?.hasAttribute('disabled')).to.equal(true);
});
it('will read inital attributes', async () => {
const tag = defineCE(
class extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => this.shadowRoot?.getElementById('button1'),
attributes: ['disabled'],
};
}
render() {
return html`<button id="button1">with delegation</button>`;
}
},
);
const element = await fixture(`<${tag} disabled></${tag}>`);
expect(element.hasAttribute('disabled')).to.equal(false);
expect(element.shadowRoot?.getElementById('button1')?.hasAttribute('disabled')).to.equal(true);
});
it('will delegate removeAttribute', async () => {
const tag = defineCE(
class extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => this.shadowRoot?.getElementById('button1'),
attributes: ['disabled'],
};
}
render() {
return html`<button id="button1">with delegation</button>`;
}
},
);
const element = /** @type {LitElement} */ (await fixture(`<${tag} disabled></${tag}>`));
element.removeAttribute('disabled');
await element.updateComplete;
expect(element.hasAttribute('disabled')).to.equal(false);
expect(element.shadowRoot?.getElementById('button1')?.hasAttribute('disabled')).to.equal(false);
});
it('respects user defined values for delegated attributes and properties', async () => {
class ScheduledElement extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
// this just means itś config is set to the queue when called before connectedCallback
target: () => this.scheduledElement,
attributes: ['type'],
properties: ['type'],
};
}
get scheduledElement() {
return this.querySelector('input');
}
constructor() {
super();
this.type = 'email'; // 1. here we set the delegated prop and it should be scheduled
}
connectedCallback() {
// 2. this is where we add teh delegation target (so after 1)
this.appendChild(document.createElement('input'));
super.connectedCallback(); // let the DelegateMixin do its work
}
}
const tag = defineCE(ScheduledElement);
const tagName = unsafeStatic(tag);
// Here, the Application Developerd tries to set the type via attribute
const elementAttr = /** @type {ScheduledElement} */ (
await fixture(`<${tag} type="radio"></${tag}>`)
);
expect(elementAttr.scheduledElement?.type).to.equal('radio');
// Here, the Application Developer tries to set the type via property
const elementProp = /** @type {ScheduledElement} */ (
await fixture(html`<${tagName} .type=${'radio'}></${tagName}>`)
);
expect(elementProp.scheduledElement?.type).to.equal('radio');
});
it(`uses attribute value as a fallback for delegated property getter
when property not set by user and delegationTarget not ready`, async () => {
class FallbackEl extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => this.delegatedEl,
properties: ['type'],
attributes: ['type'],
};
}
get delegatedEl() {
// returns null, so we can test that "cached" attr is used as fallback
return null;
}
}
const tag = defineCE(FallbackEl);
const element = /** @type {FallbackEl} */ (await fixture(`<${tag} type="radio"></${tag}>`));
expect(element.delegatedEl).to.equal(null);
// @ts-ignore ignoring this one, because type is delegated through target so it indeed does not inherently exist on the div element
expect(element.type).to.equal('radio'); // value retrieved from host instead of delegatedTarget
});
it('works with connectedCallback', async () => {
class ConnectedElement extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => this.querySelector('div'),
properties: ['foo'],
};
}
}
const tag = await defineCE(ConnectedElement);
const element = /** @type {ConnectedElement} */ (await fixture(`<${tag}><div></div></${tag}>`));
// @ts-ignore ignoring this one, because foo is delegated through target so it indeed does not inherently exist on the div element
element.foo = 'new';
// @ts-ignore ignoring this one, because foo is delegated through target so it indeed does not inherently exist on the div element
expect(element.querySelector('div')?.foo).to.equal('new');
});
it('works with shadow dom', async () => {
class A extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => this.shadowRoot?.querySelector('div'),
properties: ['foo'],
};
}
render() {
return html`<div></div>`;
}
}
const tag = await defineCE(A);
const element = await fixture(`<${tag}></${tag}>`);
// @ts-ignore ignoring this one, because foo is delegated through target so it indeed does not inherently exist on the div element
element.foo = 'new';
// @ts-ignore ignoring this one, because foo is delegated through target so it indeed does not inherently exist on the div element
expect(element.shadowRoot?.querySelector('div')?.foo).to.equal('new');
});
it('works with light dom', async () => {
class A extends DelegateMixin(LitElement) {
get delegations() {
return {
...super.delegations,
target: () => this.querySelector('div'),
properties: ['foo'],
};
}
createRenderRoot() {
return this;
}
render() {
return html`<div></div>`;
}
}
const tag = await defineCE(A);
const element = await fixture(`<${tag}></${tag}>`);
// @ts-ignore ignoring this one, because foo is delegated through target so it indeed does not inherently exist on the div element
element.foo = 'new';
// @ts-ignore ignoring this one, because foo is delegated through target so it indeed does not inherently exist on the div element
expect(element.querySelector('div')?.foo).to.equal('new');
});
});

View file

@ -1,80 +0,0 @@
import { defineCE, expect, fixture } from '@open-wc/testing';
import { html } from 'lit/static-html.js';
import { css, LitElement } from '../index.js';
import { UpdateStylesMixin } from '../src/UpdateStylesMixin.js';
describe('UpdateStylesMixin', () => {
it('handles css variables && direct e.g. host css properties correctly', async () => {
class UpdateStylesElement extends UpdateStylesMixin(LitElement) {
static get styles() {
return [
css`
:host {
text-align: right;
--color: rgb(128, 128, 128);
}
h1 {
color: var(--color);
}
`,
];
}
render() {
return html`<h1 id="header">hey</h1>`;
}
}
const tag = defineCE(UpdateStylesElement);
const el = /** @type {UpdateStylesElement} */ (await fixture(`<${tag}></${tag}>`));
const header = /** @type {Element} */ (el.shadowRoot?.getElementById('header'));
expect(window.getComputedStyle(header).color).to.equal('rgb(128, 128, 128)');
expect(window.getComputedStyle(el).textAlign).to.equal('right');
el.updateStyles({
'--color': 'rgb(255, 0, 0)',
'text-align': 'center',
});
await el.updateComplete;
expect(window.getComputedStyle(header).color).to.equal('rgb(255, 0, 0)');
expect(window.getComputedStyle(el).textAlign).to.equal('center');
});
it('preserves existing styles', async () => {
class UpdateStylesElement extends UpdateStylesMixin(LitElement) {
static get styles() {
return [
css`
:host {
--color: rgb(128, 128, 128);
}
h1 {
color: var(--color);
}
`,
];
}
render() {
return html`<h1 id="header">hey</h1>`;
}
}
const tag = defineCE(UpdateStylesElement);
const el = /** @type {UpdateStylesElement} */ (await fixture(`<${tag}></${tag}>`));
const header = /** @type {Element} */ (el.shadowRoot?.getElementById('header'));
expect(window.getComputedStyle(header).color).to.equal('rgb(128, 128, 128)');
el.updateStyles({ '--color': 'rgb(255, 0, 0)' });
expect(window.getComputedStyle(header).color).to.equal('rgb(255, 0, 0)');
el.updateStyles({ 'text-align': 'left' });
const styles = window.getComputedStyle(header);
expect(styles.color).to.equal('rgb(255, 0, 0)');
expect(styles.textAlign).to.equal('left');
});
});

View file

@ -1,58 +0,0 @@
import { Constructor } from '@open-wc/dedupe-mixin';
import { LitElement } from '../index.js';
export type Delegations = {
target: Function;
events: string[];
methods: string[];
properties: string[];
attributes: string[];
};
export declare class DelegateHost {
protected get delegations(): Delegations;
protected _connectDelegateMixin(): void;
private __setupPropertyDelegation(): void;
private __initialAttributeDelegation(): void;
private __emptyEventListenerQueue(): void;
private __emptyPropertiesQueue(): void;
connectedCallback(): void;
updated(changedProperties: import('lit-element').PropertyValues): void;
}
/**
* # DelegateMixin
* Forwards defined events, methods, properties and attributes to the defined target.
*
* @example
* get delegations() {
* return {
* ...super.delegations,
* target: () => this.shadowRoot.getElementById('button1'),
* events: ['click'],
* methods: ['click'],
* properties: ['disabled'],
* attributes: ['disabled'],
* };
* }
*
* render() {
* return html`
* <button id="button1">with delegation</button>
* `;
* }
*/
declare function DelegateMixinImplementation<T extends Constructor<LitElement>>(
superclass: T,
): T &
Constructor<DelegateHost> &
Pick<typeof DelegateHost, keyof typeof DelegateHost> &
Pick<typeof LitElement, keyof typeof LitElement>;
export type DelegateMixin = typeof DelegateMixinImplementation;

View file

@ -1,37 +0,0 @@
import { Constructor } from '@open-wc/dedupe-mixin';
export type StylesMap = {
[key: string]: string;
};
export declare class UpdateStylesHost {
/**
* @example
* <my-element>
* <style>
* :host {
* color: var(--foo);
* }
* </style>
* </my-element>
*
* $0.updateStyles({'background': 'orange', '--foo': '#fff'})
* Chrome, Firefox: <my-element style="background: orange; --foo: bar;">
* IE: <my-element>
* => to head: <style>color: #fff</style>
*
* @param {StylesMap} updateStyles
*/
public updateStyles(updateStyles: StylesMap): void;
}
/**
* # UpdateStylesMixin
*/
declare function UpdateStylesMixinImplementation<T extends Constructor<HTMLElement>>(
superclass: T,
): T &
Constructor<UpdateStylesHost> &
Pick<typeof UpdateStylesHost, keyof typeof UpdateStylesHost> &
Pick<typeof HTMLElement, keyof typeof HTMLElement>;
export type UpdateStylesMixin = typeof UpdateStylesMixinImplementation;