Skip to content

Commit ac03dab

Browse files
committed
revert changes to v1 docs
1 parent 5c7c6b0 commit ac03dab

File tree

5 files changed

+94
-202
lines changed

5 files changed

+94
-202
lines changed

docs/_guide/attrs.md

Lines changed: 57 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -9,139 +9,86 @@ Components may sometimes manage state, or configuration. We encourage the use of
99

1010
As Catalyst elements are really just Web Components, they have the `hasAttribute`, `getAttribute`, `setAttribute`, `toggleAttribute`, and `removeAttribute` set of methods available, as well as [`dataset`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/dataset), but these can be a little tedious to use; requiring null checking code with each call.
1111

12-
Catalyst includes the `@attr` decorator which provides nice syntax sugar to simplify, standardise, and encourage use of attributes. `@attr` has the following benefits over the basic `*Attribute` methods:
13-
14-
- It dasherizes a property name, making it safe for HTML serialization without conflicting with [built-in global attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes). This works the same as the class name, so for example `@attr pathName` will be `path-name` in HTML, `@attr srcURL` will be `src-url` in HTML.
15-
- An `@attr` property automatically casts based on the initial value - if the initial value is a `string`, `boolean`, or `number` - it will never be `null` or `undefined`. No more null checking!
16-
- It is automatically synced with the HTML attribute. This means setting the class property will update the HTML attribute, and setting the HTML attribute will update the class property!
17-
- Assigning a value in the class description will make that value the _default_ value so if the HTML attribute isn't set, or is set but later removed the _default_ value will apply.
18-
19-
This behaves similarly to existing HTML elements where the class field is synced with the html attribute, for example the `<input>` element's `type` field:
20-
21-
```ts
22-
const input = document.createElement('input')
23-
console.assert(input.type === 'text') // default value
24-
console.assert(input.hasAttribute('type') === false) // no attribute to override
25-
input.setAttribute('type', 'number')
26-
console.assert(input.type === 'number') // overrides based on attribute
27-
input.removeAttribute('type')
28-
console.assert(input.type === 'text') // back to default value
29-
```
12+
Catalyst includes the `@attr` decorator, which provides nice syntax sugar to simplify, standardise, and encourage use of attributes. `@attr` has the following benefits over the basic `*Attribute` methods:
3013

31-
{% capture callout %}
32-
An important part of `@attr`s is that they _must_ comprise of two words, so that they get a dash when serialised to HTML. This is intentional, to avoid conflicting with [built-in global attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes). To see how JavaScript property names convert to HTML dasherized names, try typing the name of an `@attr` below:
33-
{% endcapture %}{% include callout.md %}
14+
- It maps whatever the property name is to `data-*`, [similar to how `dataset` does](https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/dataset#name_conversion), but with more intuitive naming (e.g. `URL` maps to `data-url` not `data--u-r-l`).
15+
- An `@attr` property is limited to `string`, `boolean`, or `number`, it will never be `null` or `undefined` - instead it has an "empty" value. No more null checking!
16+
- The attribute name is automatically [observed, meaning `attributeChangedCallback` will fire when it changes](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks).
17+
- Assigning a value in the class description will make that value the _default_ value, so when the element is connected that value is set (unless the element has the attribute defined already).
3418

35-
<form>
36-
<label>
37-
<h4>I want my `@attr` to be named...</h4>
38-
<input class="js-attr-dasherize-test mb-4">
39-
</label>
40-
<div hidden class="js-attr-dasherize-bad text-red">
41-
{{ octx }} An attr name must be two words, so that the HTML version includes a dash!
42-
</div>
43-
<div hidden class="js-attr-dasherize-good text-green">
44-
{{ octick }} This will be <code></code> in HTML.
45-
</div>
46-
<script type="module">
47-
import {mustDasherize} from 'https://unpkg.com/@github/catalyst/lib/index.js'
48-
document.querySelector('.js-attr-dasherize-test').addEventListener('input', () => {
49-
let name = event.target.value
50-
const goodEl = document.querySelector('.js-attr-dasherize-good')
51-
const badEl = document.querySelector('.js-attr-dasherize-bad')
52-
if (name === '') {
53-
goodEl.hidden = true
54-
badEl.hidden = true
55-
return
56-
}
57-
let pass = true
58-
try {
59-
name = mustDasherize(name)
60-
} catch (e) {
61-
pass = false
62-
}
63-
goodEl.querySelector('code').textContent = name
64-
goodEl.hidden = !pass
65-
badEl.hidden = pass
66-
})
67-
</script>
68-
</form>
69-
70-
To use the `@attr` decorator, attach it to a class field, and it will get/set the value of the matching dasherized HTML attribute.
19+
To use the `@attr` decorator, attach it to a class field, and it will get/set the value of the matching `data-*` attribute.
7120

7221
### Example
7322

7423
<!-- annotations
75-
attr fooBar: Maps to get/setAttribute('foo-bar')
24+
attr foo: Maps to get/setAttribute('datafoo')
7625
-->
7726

7827
```js
7928
import { controller, attr } from "@github/catalyst"
8029

8130
@controller
8231
class HelloWorldElement extends HTMLElement {
83-
@attr fooBar = 'hello'
32+
@attr foo = 'hello'
8433
}
8534
```
8635

87-
This is somewhat equivalent to:
36+
This is the equivalent to:
8837

8938
```js
9039
import { controller } from "@github/catalyst"
9140

9241
@controller
9342
class HelloWorldElement extends HTMLElement {
94-
get fooBar(): string {
95-
return this.getAttribute('foo-bar') || ''
43+
get foo(): string {
44+
return this.getAttribute('data-foo') || ''
9645
}
9746

98-
set fooBar(value: string): void {
99-
return this.setAttribute('foo-bar', value)
47+
set foo(value: string): void {
48+
return this.setAttribute('data-foo', value)
10049
}
10150

10251
connectedCallback() {
103-
if (!this.hasAttribute('foo-bar')) this.fooBar = 'Hello'
52+
if (!this.hasAttribute('data-foo')) this.foo = 'Hello'
10453
}
10554

55+
static observedAttributes = ['data-foo']
10656
}
10757
```
10858

10959
### Attribute Types
11060

111-
The _type_ of an attribute is automatically inferred based on the type it is first set to. This means once a value is initially set it cannot change type; if it is set a `string` it will never be anything but a `string`. An attribute can only be one of either a `string`, `number`, or `boolean`. The types have small differences in how they behave in the DOM.
61+
The _type_ of an attribute is automatically inferred based on the type it is first set to. This means once a value is set it cannot change type; if it is set a `string` it will never be anything but a `string`. An attribute can only be one of either a `string`, `number`, or `boolean`. The types have small differences in how they behave in the DOM.
11262

11363
Below is a handy reference for the small differences, this is all explained in more detail below that.
11464

115-
| Type | When `get` is called | When `set` is called |
116-
|:----------|----------------------|:---------------------|
117-
| `string` | `getAttribute` | `setAttribute` |
118-
| `number` | `getAttribute` | `setAttribute` |
119-
| `boolean` | `hasAttribute` | `toggleAttribute` |
65+
| Type | "Empty" value | When `get` is called | When `set` is called |
66+
|:----------|:--------------|----------------------|:---------------------|
67+
| `string` | `''` | `getAttribute` | `setAttribute` |
68+
| `number` | `0` | `getAttribute` | `setAttribute` |
69+
| `boolean` | `false` | `hasAttribute` | `toggleAttribute` |
12070

12171
#### String Attributes
12272

123-
If an attribute is first set to a `string`, then it can only ever be a `string` during the lifetime of an element. The property will revert to the initial value if the attribute doesn't exist, and trying to set it to something that isn't a string will turn it into one before assignment.
73+
If an attribute is first set to a `string`, then it can only ever be a `string` during the lifetime of an element. The property will return an empty string (`''`) if the attribute doesn't exist, and trying to set it to something that isn't a string will turn it into one before assignment.
12474

12575
<!-- annotations
126-
attr foo: Maps to get/setAttribute('foo-bar')
76+
attr foo: Maps to get/setAttribute('data-foo')
12777
-->
12878

12979
```js
13080
import { controller, attr } from "@github/catalyst"
13181

13282
@controller
13383
class HelloWorldElement extends HTMLElement {
134-
@attr fooBar = 'Hello'
84+
@attr foo = 'Hello'
13585

13686
connectedCallback() {
137-
console.assert(this.fooBar === 'Hello')
138-
this.fooBar = 'Goodbye'
139-
console.assert(this.fooBar === 'Goodbye'')
140-
console.assert(this.getAttribute('foo-bar') === 'Goodbye')
141-
142-
this.removeAttribute('foo-bar')
143-
// If the attribute doesn't exist, it'll output the initial value!
144-
console.assert(this.fooBar === 'Hello')
87+
console.assert(this.foo === 'Hello')
88+
this.foo = null // TypeScript won't like this!
89+
console.assert(this.foo === 'null')
90+
delete this.dataset.foo // Removes the attribute
91+
console.assert(this.foo === '') // If the attribute doesn't exist, its an empty string!
14592
}
14693
}
14794
```
@@ -159,40 +106,39 @@ import { controller, attr } from "@github/catalyst"
159106

160107
@controller
161108
class HelloWorldElement extends HTMLElement {
162-
@attr fooBar = false
109+
@attr foo = false
163110

164111
connectedCallback() {
165-
console.assert(this.hasAttribute('foo-bar') === false)
166-
this.fooBar = true
167-
console.assert(this.hasAttribute('foo-bar') === true)
168-
this.setAttribute('foo-bar', 'this value doesnt matter!')
169-
console.assert(this.fooBar === true)
112+
console.assert(this.hasAttribute('data-foo') === false)
113+
this.foo = true
114+
console.assert(this.hasAttribute('data-foo') === true)
115+
this.setAttribute('data-foo', 'this value doesnt matter!')
116+
console.assert(this.foo === true)
170117
}
171118
}
172119
```
173120

174121
#### Number Attributes
175122

176-
If an attribute is first set to a number, then it can only ever be a number during the lifetime of an element. This is sort of like the [`maxlength` attribute on inputs](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/maxlength). The property will return the initial value if the attribute doesn't exist, and will be coerced to `Number` if it does - this means it is _possible_ to get back `NaN`. Negative numbers and floats are also valid.
123+
If an attribute is first set to a number, then it can only ever be a number during the lifetime of an element. This is sort of like the [`maxlength` attribute on inputs](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/maxlength). The property will return `0` if the attribute doesn't exist, and will be coerced to `Number` if it does - this means it is _possible_ to get back `NaN`. Negative numbers and floats are also valid.
177124

178125
<!-- annotations
179-
attr foo: Maps to get/setAttribute('foo-bar')
126+
attr foo: Maps to get/setAttribute('data-foo')
180127
-->
181128

182129
```js
183130
import { controller, attr } from "@github/catalyst"
184131

185132
@controller
186133
class HelloWorldElement extends HTMLElement {
187-
@attr fooBar = 1
134+
@attr foo = 1
188135

189136
connectedCallback() {
190-
this.fooBar = 2
191-
console.assert(this.getAttribute('foo-bar') === '2')
192-
this.setAttribute('foo-bar', 'not a number')
193-
console.assert(Number.isNaN(this.fooBar))
194-
this.fooBar = -3.14
195-
console.assert(this.getAttribute('foo-bar') === '-3.14')
137+
console.assert(this.getAttribute('data-foo') === '1')
138+
this.setAttribute('data-foo', 'not a number')
139+
console.assert(Number.isNaN(this.foo))
140+
this.foo = -3.14
141+
console.assert(this.getAttribute('data-foo') === '-3.14')
196142
}
197143
}
198144
```
@@ -202,7 +148,7 @@ class HelloWorldElement extends HTMLElement {
202148
When an element gets connected to the DOM, the attr is initialized. During this phase Catalyst will determine if the default value should be applied. The default value is defined in the class property. The basic rules are as such:
203149

204150
- If the class property has a value, that is the _default_
205-
- When connected, if the element _does not_ have a matching attribute, the _default is_ applied.
151+
- When connected, if the element _does not_ have a matching attribute, the default _is_ applied.
206152
- When connected, if the element _does_ have a matching attribute, the default _is not_ applied, the property will be assigned to the value of the attribute instead.
207153

208154
{% capture callout %}
@@ -219,9 +165,9 @@ attr name: Maps to get/setAttribute('data-name')
219165
import { controller, attr } from "@github/catalyst"
220166
@controller
221167
class HelloWorldElement extends HTMLElement {
222-
@attr dataName = 'World'
168+
@attr name = 'World'
223169
connectedCallback() {
224-
this.textContent = `Hello ${this.dataName}`
170+
this.textContent = `Hello ${this.name}`
225171
}
226172
}
227173
```
@@ -241,45 +187,24 @@ data-name ".*": Will set the value of `name`
241187
// This will render `Hello `
242188
```
243189

244-
### Advanced usage
245-
246-
#### Determining when an @attr changes value
247-
248-
To be notified when an `@attr` changes value, you can use the decorator over
249-
"setter" method instead, and the method will be called with the new value
250-
whenever it is re-assigned, either through HTML or JavaScript:
251-
252-
```typescript
253-
import { controller, attr } from "@github/catalyst"
254-
@controller
255-
class HelloWorldElement extends HTMLElement {
256-
257-
@attr get dataName() {
258-
return 'World' // Used to get the intial value
259-
}
260-
// Called whenever `name` changes
261-
set dataName(newValue: string) {
262-
this.textContent = `Hello ${newValue}`
263-
}
264-
}
265-
```
266-
267190
### What about without Decorators?
268191

269-
If you're not using decorators, then the `@attr` decorator has an escape hatch: You can define a static class field using the `[attr.static]` computed property, as an array of key names. Like so:
192+
If you're not using decorators, then you won't be able to use the `@attr` decorator, but there is still a way to achieve the same result. Under the hood `@attr` simply tags a field, but `initializeAttrs` and `defineObservedAttributes` do all of the logic.
193+
194+
Calling `initializeAttrs` in your connected callback, with the list of properties you'd like to initialize, and calling `defineObservedAttributes` with the class, can achieve the same result as `@attr`. The class fields can still be defined in your class, and they'll be overridden as described above. For example:
270195

271196
```js
272-
import {controller, attr} from '@github/catalyst'
197+
import {initializeAttrs, defineObservedAttributes} from '@github/catalyst'
273198

274-
controller(
275199
class HelloWorldElement extends HTMLElement {
276-
// Same as @attr fooBar
277-
[attr.static] = ['fooBar']
200+
foo = 1
201+
202+
connectedCallback() {
203+
initializeAttrs(this, ['foo'])
204+
}
278205

279-
// Field can still be defined
280-
fooBar = 1
281206
}
282-
)
207+
defineObservedAttributes(HelloWorldElement, ['foo'])
283208
```
284209

285210
This example is functionally identical to:
@@ -289,6 +214,6 @@ import {controller, attr} from '@github/catalyst'
289214

290215
@controller
291216
class HelloWorldElement extends HTMLElement {
292-
@attr fooBar = 1
217+
@attr foo = 1
293218
}
294219
```

docs/_guide/conventions.md

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,13 @@ subtitle: Common naming and patterns
77

88
Catalyst strives for convention over code. Here are a few conventions we recommend when writing Catalyst code:
99

10-
### Suffix your controllers consistently, for symmetry
10+
### Use `Element` to suffix your controller class
1111

12-
Catalyst components can be suffixed with `Element`, `Component` or `Controller`. We think elements should behave as closely to the built-ins as possible, so we like to use `Element` (existing elements do this, for example `HTMLDivElement`, `SVGElement`). If you're using a server side comoponent framework such as [ViewComponent](https://viewcomponent.org/), it's probably better to suffix `Component` for symmetry with that framework.
12+
Built in HTML elements all extend from the `HTMLElement` constructor, and are all suffixed with `Element` (for example `HTMLElement`, `SVGElement`, `HTMLInputElement` and so on). Catalyst components should be no different, they should behave as closely to the built-ins as possible.
1313

1414
```typescript
1515
@controller
16-
class UserListElement extends HTMLElement {} // `<user-list />`
17-
```
18-
19-
```typescript
20-
@controller
21-
class UserListComponent extends HTMLElement {} // `<user-list />`
16+
class UserListElement extends HTMLElement {}
2217
```
2318

2419
### The best class-names are two word descriptions

docs/_guide/rendering.md

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ Remember to _always_ make your JavaScript progressively enhanced, where possible
1313

1414
By leveraging the native [`ShadowDOM`](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) feature, Catalyst components can render complex sub-trees, fully encapsulated from the rest of the page.
1515

16-
[Actions]({{ site.baseurl }}/guide/actions) and [Targets]({{ site.baseurl }}/guide/targets) all work within an elements ShadowRoot.
16+
Catalyst will automatically look for elements that match the `template[data-shadowroot]` selector, within your controller. If it finds one as a direct-child of your controller, it will use that to create a shadowRoot.
1717

18-
You can also leverage the [declarative shadow DOM](https://web.dev/declarative-shadow-dom/) and render a template inline to your HTML, which will automatically be attached (this may require a polyfill for browsers which are yet to support this feature).
18+
Catalyst Controllers will search for a direct child of `template[data-shadowroot]` and load its contents as the `shadowRoot` of the element. [Actions]({{ site.baseurl }}/guide/actions) and [Targets]({{ site.baseurl }}/guide/targets) all work within an elements ShadowRoot.
1919

2020
### Example
2121

2222
```html
2323
<hello-world>
24-
<template shadowroot="open">
24+
<template data-shadowroot>
2525
<p>
2626
Hello <span data-target="hello-world.nameEl">World</span>
2727
</p>
@@ -43,34 +43,12 @@ class HelloWorldElement extends HTMLElement {
4343
}
4444
```
4545

46+
Providing the `<template data-shadowroot>` element as a direct child of the `hello-world` element tells Catalyst to render the templates contents automatically, and so all `HelloWorldElements` with this template will be rendered with the contents.
47+
4648
{% capture callout %}
47-
Remember that _all_ instances of your controller _must_ add the `<template shadowroot>` HTML. If an instance does not have the `<template data-shadowroot>` as a direct child, then the shadow DOM won't be rendered for it!
49+
Remember that _all_ instances of your controller _must_ add the `<template data-shadowroot>` HTML. If an instance does not have the `<template data-shadowroot>` as a direct child, then the shadow DOM won't be rendered for it!
4850
{% endcapture %}{% include callout.md %}
4951

50-
51-
It is also possible to attach a shadowRoot to your element during the `connectedCallback`, like so:
52-
53-
```typescript
54-
import { controller, target } from "@github/catalyst"
55-
56-
@controller
57-
class HelloWorldElement extends HTMLElement {
58-
@target nameEl: HTMLElement
59-
get name() {
60-
return this.nameEl.textContent
61-
}
62-
set name(value: string) {
63-
this.nameEl.textContent = value
64-
}
65-
66-
connectedCallback() {
67-
this.attachShadow({ mode: 'open' }).innerHTML = `<p>
68-
Hello <span data-target="hello-world.nameEl">World</span>
69-
</p>`
70-
}
71-
}
72-
```
73-
7452
### Updating a Template element using JS templates
7553

7654
Sometimes you wont have a template that is server rendered, and instead want to make a template using JS. Catalyst does not support this out of the box, but it is possible to use another library: `@github/jtml`. This library can be used to write declarative templates using JS. Let's re-work the above example using `@github/jtml`:

0 commit comments

Comments
 (0)