Last active
April 4, 2024 15:15
-
-
Save oscarmarina/2d62708527350755089d47fce8d10551 to your computer and use it in GitHub Desktop.
Lit playground context-consume-provide
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 { ReactiveController, ReactiveControllerHost } from 'lit'; | |
import { | |
createContext, | |
ContextProvider, | |
ContextConsumer, | |
Context, | |
ContextType, | |
} from '@lit/context'; | |
export class ContextMeta< | |
TMeta extends Context<unknown, unknown>, | |
HostElement extends ReactiveControllerHost & HTMLElement | |
> implements ReactiveController | |
{ | |
private host: HostElement; | |
private context: TMeta; | |
private initialValue?: ContextType<TMeta>; | |
private callback?: (v: ContextType<TMeta>, dispose?: () => void) => void; | |
private _contextMetaProvider: ContextProvider<TMeta, HostElement>; | |
private _contextMetaConsumer!: ContextConsumer<TMeta, HostElement>; | |
constructor( | |
host: HostElement, | |
{ | |
context, | |
initialValue, | |
callback, | |
}: { | |
context: string; | |
initialValue?: ContextType<TMeta>; | |
callback?: (v: ContextType<TMeta>, dispose?: () => void) => void; | |
} | |
) { | |
this.context = createContext<TMeta>(Symbol.for(context)) as TMeta; | |
this.initialValue = initialValue; | |
this.callback = callback; | |
this.host = host; | |
this._contextMetaProvider = new ContextProvider(this.host, { | |
context: this.context, | |
initialValue: this.initialValue, | |
}); | |
this.host.addController?.(this); | |
} | |
get value() { | |
return this._contextMetaConsumer?.value; | |
} | |
setValue(v: ContextType<TMeta>, force = false) { | |
this._contextMetaProvider?.setValue?.(v, force); | |
} | |
async hostConnected() { | |
await this.host.updateComplete; | |
this._contextMetaConsumer = new ContextConsumer(this.host, { | |
context: this.context, | |
subscribe: true, | |
callback: this.callback, | |
}); | |
} | |
} |
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" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<title>context-consume-provide</title> | |
<style> | |
:root { | |
font-family: sans-serif; | |
} | |
</style> | |
</head> | |
<body> | |
<p> | |
Example inspired by: | |
<a href="https://react.dev/learn/passing-data-deeply-with-context" target="_blank" | |
>https://react.dev/learn/passing-data-deeply-with-context</a | |
> | |
</p> | |
<p> | |
Orginal example from lit.dev: | |
<a href="https://lit.dev/playground/#sample=examples/context-consume-provide" target="_blank" | |
>https://lit.dev/playground/#sample=examples/context-consume-provide</a | |
> | |
</p> | |
<my-app></my-app> | |
<script type="module" src="./my-app.js"></script> | |
</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 { html, LitElement } from 'lit'; | |
import './my-section.js'; | |
import './my-heading.js'; | |
export type Level = { level: number; color: string }; | |
export class MyApp extends LitElement { | |
render() { | |
// <my-section> serves as both context provider and consumer. It provides a | |
// level value that is 1 greater than what's provided to it. This allows | |
// nested <my-section> to provide a different value based on its depth. | |
// <my-heading> adjusts what heading tag to use and the color based on the | |
// level context. | |
return html` | |
<my-section id="root-1"> | |
<my-heading>Heading level 1</my-heading> | |
<my-section id="1"> | |
<my-heading>Heading level 2</my-heading> | |
</my-section> | |
<my-section id="2"> | |
<my-heading>Heading level 2</my-heading> | |
<my-section id="2.1"> | |
<my-heading>Heading level 3</my-heading> | |
</my-section> | |
<my-section id="2.2"> | |
<my-heading>Heading level 3</my-heading> | |
<my-section id="2.3"> | |
<my-heading>Heading level 4</my-heading> | |
</my-section> | |
</my-section> | |
</my-section> | |
<my-section id="3"> | |
<my-heading>Heading level 2</my-heading> | |
<my-section id="3.1"> | |
<my-heading>Heading level 3</my-heading> | |
<my-section id="3.2"> | |
<my-heading>Heading level 4</my-heading> | |
</my-section> | |
<my-section id="3.3"> | |
<my-heading>Heading level 4</my-heading> | |
</my-section> | |
</my-section> | |
</my-section> | |
</my-section> | |
<hr> | |
<my-section id="root-2"> | |
<my-heading>Heading level 1</my-heading> | |
<my-section id="1"> | |
<my-heading>Heading level 2</my-heading> | |
<my-section id="1.1"> | |
<my-heading>Heading level 3</my-heading> | |
<my-section id="1.2"> | |
<my-heading>Heading level 4</my-heading> | |
<my-section id="1.3"> | |
<my-heading>Heading level 5</my-heading> | |
</my-section> | |
</my-section> | |
</my-section> | |
</my-section> | |
<my-section id="2"> | |
<my-heading>Heading level 2</my-heading> | |
<my-section id="2.1"> | |
<my-heading>Heading level 3</my-heading> | |
<my-section id="2.3"> | |
<my-heading>Heading level 4</my-heading> | |
</my-section> | |
</my-section> | |
</my-section> | |
</my-section> | |
`; | |
} | |
}; | |
customElements.define('my-app', MyApp); |
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 { LitElement } from 'lit'; | |
import { html, literal, unsafeStatic } from 'lit/static-html.js'; | |
import { styleMap } from 'lit/directives/style-map.js'; | |
import { ContextMeta } from './context-meta.js'; | |
import { type Level } from './my-app.js'; | |
export class MyHeading extends LitElement { | |
_level? = new ContextMeta(this, { context: 'level' }); | |
get _tag() { | |
const level = (this._level?.value as Level)?.level; | |
if (typeof level === 'number' && level >= 0 && level <= 5) { | |
return unsafeStatic(`h${level}`); | |
} else { | |
return literal`p`; | |
} | |
} | |
render() { | |
return html` | |
<${this._tag} style=${styleMap({ | |
color: (this._level?.value as Level)?.color, | |
})}> | |
<slot></slot> | |
</${this._tag}>`; | |
} | |
} | |
customElements.define('my-heading', MyHeading); |
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 { html, css, LitElement } from 'lit'; | |
import { ContextMeta } from './context-meta.js'; | |
import { type Level } from './my-app.js'; | |
const COLORS = ['indianred', 'blue', 'orange', 'green', 'purple']; | |
export class MySection extends LitElement { | |
private _consumer = new ContextMeta(this, { | |
context: 'level', | |
initialValue: { level: 1, color: COLORS[0] }, | |
callback: (v) => { | |
const { level } = v as Level; | |
this._consumer.setValue({ | |
level: level + 1, | |
color: COLORS[(level + 1) % COLORS.length], | |
}); | |
}, | |
}); | |
static styles = css` | |
:host { | |
display: block; | |
text-align: center; | |
} | |
:host([hidden]) { | |
display: none; | |
} | |
`; | |
render() { | |
return html`<section><slot></slot></section>`; | |
} | |
} | |
customElements.define('my-section', MySection); |
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
{ | |
"scripts": { | |
"start": "npx @web/dev-server --node-resolve --port 6174 --open" | |
}, | |
"dependencies": { | |
"lit": "^3.0.0", | |
"@lit/context": "^1.1.0", | |
"@lit/reactive-element": "^2.0.0", | |
"lit-element": "^4.0.0", | |
"lit-html": "^3.0.0" | |
} | |
} |
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
{ | |
"files": { | |
"index.html": { | |
"position": 0 | |
}, | |
"my-app.ts": { | |
"position": 1 | |
}, | |
"my-heading.ts": { | |
"position": 2 | |
}, | |
"my-section.ts": { | |
"position": 3 | |
}, | |
"context-meta.ts": { | |
"position": 4 | |
}, | |
"package.json": { | |
"position": 5, | |
"hidden": true | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment