blob: 5e0137321df261e32e6c68b5da9a8fa929ac45ab [file] [log] [blame]
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {css, html, LitElement, TemplateResult} from 'lit';
import {customElement, property, query} from 'lit/decorators.js';
import {DependencyToken, provide} from './dependency';
/**
* Example usage:
*
* const providerElement = await fixture<DIProviderElement>(
* wrapInProvider(
* html`<my-element-to-test></my-element-to-test>`,
* myModelToken,
* myModel,
* )
* );
* const element = providerElement.element as MyElementToTest;
*
* For injecting multiple tokens, make nested calls to `wrapInProvider` such as:
*
* wrapInProvider(wrapInProvider(html`...`, token1, value1), token2, value2);
*/
export function wrapInProvider<T>(
template: TemplateResult,
token: DependencyToken<T>,
value: T
) {
return html`
<di-provider-element .token=${token} .value=${value}
>${template}</di-provider-element
>
`;
}
/**
* Use `.element` to get the wrapped element for assertions.
*/
@customElement('di-provider-element')
export class DIProviderElement extends LitElement {
@property({type: Object})
token?: DependencyToken<unknown>;
@property({type: Object})
value?: unknown;
get element() {
return this.slotElement.assignedElements()[0];
}
private isProvided = false;
@query('slot')
private slotElement!: HTMLSlotElement;
static override get styles() {
return css`
:host() {
display: contents;
}
`;
}
/** Only calls `provide` even after reconnection. */
override connectedCallback(): void {
super.connectedCallback();
if (!this.token || this.isProvided) return;
this.isProvided = true;
provide(this, this.token, () => this.value);
}
override render() {
return html`<slot></slot>`;
}
}