Skip to content

Commit 4035bd6

Browse files
authored
[playground] New context example with element that both consumes and provides (#1315)
1 parent 6c7b3f9 commit 4035bd6

File tree

9 files changed

+208
-42
lines changed

9 files changed

+208
-42
lines changed

package-lock.json

Lines changed: 5 additions & 41 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/lit-dev-content/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@
197197
"@lit-labs/motion": "^1.0.1",
198198
"@lit-labs/react": "^1.0.8",
199199
"@lit-labs/task": "^3.0.2",
200-
"@lit/context": "^1.0.0 || 1.0.0-pre.0",
200+
"@lit/context": "^1.1.0",
201201
"@lit/localize": "^0.10.0",
202202
"@lit/react": "^1.0.0 || 1.0.0-pre.0",
203203
"@lit/task": "^1.0.0 || 1.0.0-pre.0",
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script type="module" src="./my-app.js"></script>
2+
<style>
3+
:root {
4+
font-family: sans-serif;
5+
}
6+
</style>
7+
<p>
8+
Example inspired by:
9+
<a
10+
href="https://react.dev/learn/passing-data-deeply-with-context"
11+
target="_blank"
12+
>https://react.dev/learn/passing-data-deeply-with-context</a
13+
>
14+
</p>
15+
<my-app></my-app>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import {createContext} from '@lit/context';
2+
3+
export type Level = {level: number; color: string};
4+
5+
export const levelContext = createContext<Level>(Symbol('level'));
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import {html, LitElement} from 'lit';
2+
import {customElement} from 'lit/decorators.js';
3+
import './my-section.js';
4+
import './my-heading.js';
5+
6+
@customElement('my-app')
7+
export class MyApp extends LitElement {
8+
render() {
9+
// <my-section> serves as both context provider and consumer. It provides a
10+
// level value that is 1 greater than what's provided to it. This allows
11+
// nested <my-section> to provide a different value based on its depth.
12+
13+
// <my-heading> adjusts what heading tag to use and the color based on the
14+
// level context.
15+
return html`
16+
<my-section>
17+
<my-heading>Heading level 1</my-heading>
18+
<my-section>
19+
<my-heading>Heading level 2</my-heading>
20+
</my-section>
21+
<my-section>
22+
<my-heading>Heading level 2</my-heading>
23+
<my-section>
24+
<my-heading>Heading level 3</my-heading>
25+
</my-section>
26+
<my-section>
27+
<my-heading>Heading level 3</my-heading>
28+
<my-section>
29+
<my-heading>Heading level 4</my-heading>
30+
</my-section>
31+
</my-section>
32+
</my-section>
33+
<my-section>
34+
<my-heading>Heading level 2</my-heading>
35+
<my-section>
36+
<my-heading>Heading level 3</my-heading>
37+
<my-section>
38+
<my-heading>Heading level 4</my-heading>
39+
</my-section>
40+
<my-section>
41+
<my-heading>Heading level 4</my-heading>
42+
</my-section>
43+
</my-section>
44+
</my-section>
45+
</my-section>
46+
<my-section>
47+
<my-heading>Heading level 1</my-heading>
48+
<my-section>
49+
<my-heading>Heading level 2</my-heading>
50+
<my-section>
51+
<my-heading>Heading level 3</my-heading>
52+
<my-section>
53+
<my-heading>Heading level 4</my-heading>
54+
<my-section>
55+
<my-heading>Heading level 5</my-heading>
56+
</my-section>
57+
</my-section>
58+
</my-section>
59+
</my-section>
60+
<my-section>
61+
<my-heading>Heading level 2</my-heading>
62+
<my-section>
63+
<my-heading>Heading level 3</my-heading>
64+
<my-section>
65+
<my-heading>Heading level 4</my-heading>
66+
</my-section>
67+
</my-section>
68+
</my-section>
69+
</my-section>
70+
`;
71+
}
72+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {LitElement} from 'lit';
2+
import {html, literal} from 'lit/static-html.js';
3+
import {styleMap} from 'lit/directives/style-map.js';
4+
import {ContextConsumer} from '@lit/context';
5+
import {levelContext} from './level-context.js';
6+
7+
export class MyHeading extends LitElement {
8+
_levelContext = new ContextConsumer(this, {context: levelContext});
9+
10+
get _tag() {
11+
const level = this._levelContext.value?.level;
12+
if (typeof level === 'number' && level >= 0 && level <= 5) {
13+
return unsafeStatic(`h${level + 1}`);
14+
} else {
15+
return literal`p`;
16+
}
17+
}
18+
19+
render() {
20+
return html`
21+
<${this._tag}
22+
style=${styleMap({color: this._levelContext.value?.color})}
23+
>
24+
<slot></slot>
25+
</${this._tag}>`;
26+
}
27+
}
28+
customElements.define('my-heading', MyHeading);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import {LitElement} from 'lit';
2+
import {html, literal, unsafeStatic} from 'lit/static-html.js';
3+
import {customElement} from 'lit/decorators.js';
4+
import {styleMap} from 'lit/directives/style-map.js';
5+
import {consume} from '@lit/context';
6+
import {levelContext, type Level} from './level-context.js';
7+
8+
@customElement('my-heading')
9+
export class MyHeading extends LitElement {
10+
// Consume the level and color from parent provider
11+
@consume({context: levelContext})
12+
private _level?: Level;
13+
14+
private get _tag() {
15+
const level = this._level?.level;
16+
if (typeof level === 'number' && level >= 0 && level <= 5) {
17+
return unsafeStatic(`h${level + 1}`);
18+
} else {
19+
return literal`p`;
20+
}
21+
}
22+
23+
render() {
24+
return html`
25+
<${this._tag} style=${styleMap({color: this._level?.color})}>
26+
<slot></slot>
27+
</${this._tag}>`;
28+
}
29+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import {html, css, LitElement} from 'lit';
2+
import {customElement} from 'lit/decorators.js';
3+
import {ContextProvider, ContextConsumer} from '@lit/context';
4+
import {levelContext} from './level-context.js';
5+
6+
const COLORS = ['blue', 'orange', 'green', 'purple'];
7+
8+
@customElement('my-section')
9+
export class MySection extends LitElement {
10+
// Serve as a context provider with an initial level 1 and the color for that
11+
// level
12+
private _provider = new ContextProvider(this, {
13+
context: levelContext,
14+
initialValue: {level: 0, color: COLORS[0]},
15+
});
16+
17+
// Consumes level context from a parent provider. If a parent provider is
18+
// found, update own provider level to be 1 greater than provided value and
19+
// its corresponding color.
20+
private _consumer = new ContextConsumer(this, {
21+
context: levelContext,
22+
callback: ({level}) => {
23+
this._provider.setValue({
24+
level: level + 1,
25+
color: COLORS[(level + 1) % COLORS.length],
26+
});
27+
},
28+
});
29+
30+
render() {
31+
return html`<section><slot></slot></section>`;
32+
}
33+
34+
static styles = css`
35+
:host {
36+
display: block;
37+
text-align: center;
38+
}
39+
`;
40+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"extends": "/samples/base.json",
3+
"title": "Context Consume and Provide",
4+
"description": "Showcase an element both consuming and providing the same context.",
5+
"section": "Managing Data",
6+
"files": {
7+
"my-app.ts": {},
8+
"my-section.ts": {},
9+
"my-heading.ts": {},
10+
"level-context.ts": {},
11+
"index.html": {}
12+
}
13+
}

0 commit comments

Comments
 (0)