Last active
March 25, 2023 22:03
-
-
Save au5ton/91801be50a6b81c80355558e3bb85c0c to your computer and use it in GitHub Desktop.
LitElement my-context-provider sample
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8" /> | |
<title>Vite + Lit + TS</title> | |
<script type="module" src="/src/index.ts"></script> | |
</head> | |
<body> | |
<my-context-provider> | |
<my-inner-element>AAA</my-inner-element> | |
<my-inner-element>BBB</my-inner-element> | |
</my-context-provider> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { provide, createContext } from '@lit-labs/context' | |
import { LitElement, html, css } from 'lit' | |
import { customElement, property } from 'lit/decorators.js' | |
/** | |
* Update these when reusing the file | |
*/ | |
export const CONTEXT_PROVIDER_NAME = 'my-context-provider' | |
export type CONTEXT_DATA_TYPE = MyContextualData; | |
export const CONTEXT_DEFAULT_VALUE: CONTEXT_DATA_TYPE = { name: '' }; | |
export interface MyContextualData { | |
name: string; | |
} | |
declare global { | |
interface HTMLElementTagNameMap { | |
'my-context-provider': ContextProvider | |
} | |
} | |
/// | |
/// | |
/// | |
/// BOILERPLATE CODE BELOW | |
/// BOILERPLATE CODE BELOW | |
/// BOILERPLATE CODE BELOW | |
/// | |
/// | |
/// | |
// #region Generally, nothing here changes. To reuse this Typescript file, you just copy/paste and change the parts above. | |
export const context = createContext<CONTEXT_DATA_TYPE>(Symbol(CONTEXT_PROVIDER_NAME)); | |
/** | |
* Used to send updates from the child to the parent | |
* @param self When called from inside a LitElement, `self` should be `this` | |
* @param detail | |
*/ | |
export function dispatchContextStateChange(self: LitElement, detail: CONTEXT_DATA_TYPE) { | |
const event = new CustomEvent(`${CONTEXT_PROVIDER_NAME}-state-change`, { | |
bubbles: true, | |
composed: true, | |
detail, | |
}); | |
self.dispatchEvent(event); | |
} | |
@customElement(CONTEXT_PROVIDER_NAME) | |
export class ContextProvider extends LitElement { | |
@provide({context: context }) | |
@property({attribute: false}) | |
providedData: CONTEXT_DATA_TYPE = CONTEXT_DEFAULT_VALUE; | |
connectedCallback() { | |
super.connectedCallback() | |
this.shadowRoot?.addEventListener(`${CONTEXT_PROVIDER_NAME}-state-change`, ((event: CustomEvent<CONTEXT_DATA_TYPE>) => { | |
this.providedData = { | |
...this.providedData, | |
...event.detail | |
} | |
}) as EventListener) | |
} | |
render() { | |
return html` | |
<slot></slot> | |
` | |
} | |
static styles = css` | |
:host { | |
display: contents | |
} | |
` | |
} | |
// #endregion |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { consume } from '@lit-labs/context' | |
import { LitElement, css, html } from 'lit' | |
import { customElement, property } from 'lit/decorators.js' | |
import { context, dispatchContextStateChange, MyContextualData } from './my-context-provider' | |
/** | |
* An example element. | |
* | |
* @slot - This element has a slot | |
* @csspart button - The button | |
*/ | |
@customElement('my-inner-element') | |
export class MyInnerElement extends LitElement { | |
@consume({ context: context, subscribe: true }) | |
@property({attribute: false}) | |
public myConsumedData?: MyContextualData; | |
private handleClick() { | |
console.log('myConsumedData:',this.myConsumedData); | |
} | |
private handleChange(event: Event) { | |
const target = event.target as HTMLInputElement; | |
console.log(target.value) | |
dispatchContextStateChange(this, { | |
...this.myConsumedData, | |
name: target.value, | |
}) | |
} | |
render() { | |
return html` | |
<div class="wrap"> | |
<h3><slot></slot></h3> | |
<p>Hello</p> | |
<p> | |
<button @click=${this.handleClick}>print consumed data</button> | |
</p> | |
<p> | |
Consumed data: | |
</p> | |
<p> | |
<input type="text" style="width: 90%" .value=${this.myConsumedData?.name ?? '(undefined)'} @input=${this.handleChange} /> | |
</p> | |
<p> | |
<code>${JSON.stringify(this.myConsumedData)}</code> | |
</p> | |
</div> | |
` | |
} | |
static styles = css` | |
:host { | |
display: block; | |
} | |
.wrap { | |
border: 1px solid blue; | |
} | |
` | |
} | |
declare global { | |
interface HTMLElementTagNameMap { | |
'my-inner-element': MyInnerElement | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment