Skip to content

Commit 97cee3a

Browse files
Merge pull request #1628 from NullVoxPopuli/guides-updates
Guides Updates
2 parents 31953cd + cd0f552 commit 97cee3a

File tree

12 files changed

+242
-23
lines changed

12 files changed

+242
-23
lines changed

apps/tutorial/app/components/prose/index.gts

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ export const resetScroll = modifier((element, [prose]) => {
1717
export const Prose: TOC<{ Element: HTMLDivElement }> = <template>
1818
{{#let (service "docs") as |docs|}}
1919
<style>
20-
.ember-primitives__sticky-footer__footer { position: sticky; bottom: -32px; }
20+
.ember-primitives__sticky-footer__footer { position: sticky; bottom: -32px; } .call-to-play {
21+
filter: drop-shadow(0px 2px 2px rgba(0,0,0,0.5)); border: 3px dashed var(--horizon-lavender);
22+
padding: 0.75rem; text-align: right; border-radius: 0.25rem; background: var(--horizon-blue);
23+
color: black; transform: skewX(-15deg); width: calc(100% - 6rem); margin-left: auto;
24+
margin-right: 0.8rem; font-weight: 500; font-family: system-ui; font-size: 1.125rem; }
2125
</style>
2226
<StickyFooter
2327
class="grid gap-4 overflow-auto w-fit w-full"

apps/tutorial/app/components/selection.gts

+4-1
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,11 @@ export class Selection extends Component {
5050
class="w-full h-full px-4 absolute z-1 sr-hidden pointer-events-none grid gap-3 grid-flow-col items-center justify-start"
5151
>
5252
<FaIcon @icon="bars" />
53-
<span>{{this.humanSelected}}</span>
53+
<span class="limber__selected">{{this.humanSelected}}</span>
5454
</span>
55+
<style>
56+
.limber__selected { text-wrap: nowrap; text-overflow: ellipsis; overflow: hidden; }
57+
</style>
5558

5659
<select
5760
name="tutorial"

apps/tutorial/public/docs/2-reactivity/10-synchronizing-external-state/prose.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ function logInput(...args) {
1616
</template>
1717
```
1818

19-
Most importantly, there are some things we should do with calling functions:
19+
Most importantly, there are some things we should keep in mind when calling functions:
2020
- We don't want to `return` a value, else that value will render - this includes marking the function as `async`, which inherently returns a `Promise`
2121
- `@tracked` data may not be mutated / set in these functions because setting `@tracked` data causes other parts of the UI to re-render, and because functions auto-track, they would detect the change to that tracked-data, and then re-run, setting the data again, causing an infinite rendering loop.
22+
- Functions may often serve a similar purpose to getters as used in class-components: for deriving data.
2223

2324
[docs-log]: https://api.emberjs.com/ember/release/classes/Ember.Templates.helpers/methods/log?anchor=log
2425

apps/tutorial/public/docs/6-component-patterns/1-class-component/answer.gjs

+8
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@ import { on } from '@ember/modifier';
55
export default class Demo extends Component {
66
<template>
77
{{this.value}}<br>
8+
{{this.doubled}}<br>
89
<button {{on 'click' this.increment}}>increment</button>
910
</template>
1011

12+
// root state
1113
@tracked value = 0;
1214

15+
// derived state
16+
get doubled() {
17+
return this.value * 2;
18+
}
19+
20+
// action
1321
increment = () => this.value++;
1422
}

apps/tutorial/public/docs/6-component-patterns/1-class-component/prose.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ export default class Demo extends Component {
1515
}
1616
```
1717

18-
In the editor, try adding a button that increments the `value` when clicked.
18+
<p class="call-to-play">
19+
In the editor, try adding a button that increments the <code>value</code> when clicked.
20+
</p>
1921

2022
It may end up looking something like this:
2123
```gjs
@@ -26,11 +28,19 @@ import { on } from '@ember/modifier';
2628
export default class Demo extends Component {
2729
<template>
2830
{{this.value}}<br>
31+
{{this.doubled}}<br>
2932
<button {{on 'click' this.increment}}>increment</button>
3033
</template>
3134
35+
// root state
3236
@tracked value = 0;
3337
38+
// derived state
39+
get doubled() {
40+
return this.value * 2;
41+
}
42+
43+
// action
3444
increment = () => this.value++;
3545
}
3646
```
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1-
<template>
2-
This tutorial chapter needs to be written!
1+
const MyComponent = <template>
2+
before
3+
<hr>
4+
{{yield}}
5+
<hr>
6+
after
7+
</template>;
38

4-
It could be written by you!, if you want &lt;3
9+
<template>
10+
<MyComponent>
11+
Example block content passed to
12+
<code>MyComponent</code>.
13+
</MyComponent>
514
</template>
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
<template>
2-
This tutorial chapter needs to be written!
1+
const MyComponent = <template>
2+
3+
</template>;
34

4-
It could be written by you!, if you want &lt;3
5+
<template>
6+
<MyComponent />
57
</template>
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,42 @@
1-
This tutorial chapter needs to be written!
1+
Components, like native HTML elements, may receive block content.
22

3-
It could be written by you!, if you want &lt;3
3+
So far, you've seen component invocation like
4+
```hbs
5+
<MyComponent />
6+
```
7+
8+
This is a "blockless" or "void" invocation, meaning that no nested text or HTML is passed.
9+
10+
We can pass a block of content, by having a closing tag:
11+
```hbs
12+
<MyComponent></MyComponent>
13+
```
14+
15+
This invocation still passes the a block (named `:default`), but it's empty.
16+
17+
To make the `:default` block more useful, we'll want to add some text or HTML
18+
between the opening `<MyComponent>` tag and the closing `</MyComponent>` tag.
19+
20+
For example:
21+
```hbs
22+
<MyComponent>
23+
block<span>content</span> here.<br>
24+
25+
This is also called the "default black".
26+
</MyComponent>
27+
```
28+
29+
All valid HTML is valid within a component or component block.
30+
31+
In order for `<MyComponent>` to be capable of receiving a block, we must place a `{{yield}}` within the component definition:
32+
```gjs
33+
const MyComponent = <template>
34+
{{yield}}
35+
</template>;
36+
```
37+
38+
This `{{yield}}` is a shorthand for the longer, named version, `{{yield to="default"}}`, which we'll explore in the next chapter.
39+
40+
<p class="call-to-play">
41+
Try to create your own <code>:default</code> block-receiving component in the playground area.
42+
</p>
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,44 @@
1-
<template>
2-
This tutorial chapter needs to be written!
1+
const MyComponent = <template>
2+
<div class='layout'>
3+
<header>
4+
{{yield to="header"}}
5+
</header>
6+
7+
<main>
8+
{{yield to="body"}}
9+
</main>
10+
11+
<footer>
12+
{{yield to="footer"}}
13+
</footer>
14+
</div>
315

4-
It could be written by you!, if you want &lt;3
16+
<style>
17+
.layout {
18+
display: grid;
19+
grid-template-rows: 40px 1fr 40px;
20+
gap: 0.5rem;
21+
/* accounting for default REPL padding */
22+
height: calc(100dvh - 3rem);
23+
24+
header, main, footer {
25+
border: 1px solid;
26+
padding: 0.25rem;
27+
}
28+
}
29+
</style>
30+
</template>;
31+
32+
<template>
33+
<MyComponent>
34+
<:header>
35+
header content here
36+
</:header>
37+
<:body>
38+
body content here
39+
</:body>
40+
<:footer>
41+
footer content there
42+
</:footer>
43+
</MyComponent>
544
</template>
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
<template>
2-
This tutorial chapter needs to be written!
1+
const MyComponent = <template>
2+
3+
</template>;
34

4-
It could be written by you!, if you want &lt;3
5+
<template>
6+
<MyComponent>
7+
</MyComponent>
58
</template>
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,105 @@
1-
This tutorial chapter needs to be written!
1+
Components, _unlike_ native HTML elements, but similar to WebComponents, can have multiple zones or regions for differently named block contents.
22

3-
It could be written by you!, if you want &lt;3
3+
In the previous chapter, we learned that the default space between an opening and closing tag is the `:default` block.
4+
5+
Here, we may pass multiple blocks via `<:namedBlock>` notation,
6+
```hbs
7+
<MyComponent>
8+
<:header>some heading</:header>
9+
10+
<:body>
11+
main content
12+
</:body>
13+
14+
<:footer>footer content</:footer>
15+
</MyComponent>
16+
```
17+
18+
`<:namedBlock>` notation can be identified by the preceeding `:` character in both the opening and closing tag.
19+
20+
Inside `MyComponent`, we need to allow each of these blocks to be used via `{{yield to="blockName"}}`
21+
22+
```gjs
23+
const MyComponent = <template>
24+
<header>{{yield to="header"}}</header>
25+
26+
<main>
27+
{{yield to="body"}}
28+
</main>
29+
30+
<footer>{{yield to="footer"}}</footer>
31+
</template>;
32+
```
33+
34+
<p class="call-to-play">Practice using named blocks within the playground area</p>.
35+
36+
Take note, there _are_ some constraints when it comes to invoking components with named blocks to help with conceptual consistency:
37+
- _the order of named blocks regions does not matter._
38+
```glimmer
39+
<MyComponent>
40+
<:header>some heading</:header>
41+
<:body>body content here</:body>
42+
</MyComponent>
43+
```
44+
is the same as
45+
```glimmer
46+
<MyComponent>
47+
<:body>body content here</:body>
48+
<:header>some heading</:header>
49+
</MyComponent>
50+
```
51+
This is because the placement of a block is determined by `<MyComponent>`, not the caller. This makes named blocks a good tool for design systems.
52+
- _free-form content may not exist outside of named-blocked invocation._
53+
For example, this is invalid:
54+
```glimmer
55+
<MyComponent>
56+
content here
57+
<:body>body content here</:body>
58+
</MyComponent>
59+
```
60+
This is because, syntactically, content directly within the `<MyComponent>` and `</MyComponent>` belongs to the `:default` block, which is the same as defining
61+
```glimmer
62+
<MyComponent>
63+
<:default>
64+
content here
65+
</:default>
66+
<:body>body content here</:body>
67+
</MyComponent>
68+
```
69+
- _named blocks may not contain named blocks from the same parent component._
70+
for example, this is invaild
71+
```gjs
72+
const Demo = <template>
73+
<MyComponent>
74+
<:body>
75+
body content here
76+
<:header>some heading</:header>
77+
</:body>
78+
</MyComponent>
79+
</template>
80+
```
81+
This is invalid because the block content is **owned by the invoker*, so `<:header>` doesn't actually exist in the above component because there is no `{{yield to="header"}}` in `<Demo>`. You'll receive a build-time error similar to:
82+
```
83+
Unexpected named block inside <:body> named block:
84+
named blocks cannot contain nested named blocks:
85+
```
86+
_even_ if you try to defined `{{yield to="header"}}`
87+
```gjs
88+
const Demo = <template>
89+
{{yield to="header"}}
90+
<MyComponent>
91+
<:body>
92+
body content here
93+
<:header>some heading</:header>
94+
</:body>
95+
</MyComponent>
96+
</template>
97+
```
98+
- _a component cannot pass content its own block._
99+
For example, trying to pass content to the `:header` named block:
100+
```gjs
101+
const Demo = <template>
102+
{{yield to="header"}}
103+
<:header>some heading</:header>
104+
</template>
105+
```

package.json

+2-3
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@
66
"dev": "node ./dev/index.js",
77
"prepare": "pnpm build",
88
"release": "changeset publish",
9-
"build": "turbo build --filter=limber^... --filter=tutorial^... --output-logs errors-only",
9+
"build": "turbo build --filter=limber^... --filter=tutorial^...",
1010
"lint:fix": "turbo _:lint:fix --output-logs errors-only",
1111
"lint": "turbo _:lint --output-logs errors-only",
12-
"start": "pnpm build && concurrently 'npm:start:*' --prefix-colors cyan,white,yellow,blue --restart-tries -1",
12+
"start": "pnpm build && concurrently 'npm:start:tutorial' 'npm:start:repl' 'npm:start:styles' --names 'tutarial,repl,tailwind'",
1313
"start:tutorial": "pnpm --filter=tutorial start",
1414
"start:repl": "pnpm --filter=limber start",
15-
"start:limber-ui": "pnpm --filter=limber-ui start",
1615
"start:styles": "pnpm --filter=limber-styles start"
1716
},
1817
"engines": {

0 commit comments

Comments
 (0)