@microsoft/fast-element 2.0.0-beta.9 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +1 -1
- package/CHANGELOG.json +497 -0
- package/CHANGELOG.md +172 -1
- package/README.md +1 -9
- package/api-extractor.context.json +14 -0
- package/api-extractor.di.json +14 -0
- package/dist/context/context.api.json +1068 -0
- package/dist/di/di.api.json +4929 -0
- package/dist/dts/binding/binding.d.ts +49 -0
- package/dist/dts/binding/normalize.d.ts +9 -0
- package/dist/dts/binding/one-time.d.ts +11 -0
- package/dist/dts/binding/one-way.d.ts +20 -0
- package/dist/dts/{templating/binding-signal.d.ts → binding/signal.d.ts} +19 -4
- package/dist/dts/{templating/binding-two-way.d.ts → binding/two-way.d.ts} +9 -5
- package/dist/dts/components/attributes.d.ts +6 -0
- package/dist/dts/components/element-controller.d.ts +104 -8
- package/dist/dts/components/element-hydration.d.ts +2 -0
- package/dist/dts/components/fast-definitions.d.ts +6 -0
- package/dist/dts/components/hydration.d.ts +56 -0
- package/dist/dts/components/install-hydration.d.ts +1 -0
- package/dist/dts/context.d.ts +29 -15
- package/dist/dts/di/di.d.ts +0 -5
- package/dist/dts/dom-policy.d.ts +83 -0
- package/dist/dts/dom.d.ts +100 -0
- package/dist/dts/hydration/target-builder.d.ts +63 -0
- package/dist/dts/index.d.ts +33 -26
- package/dist/dts/index.rollup.d.ts +0 -1
- package/dist/dts/index.rollup.debug.d.ts +0 -1
- package/dist/dts/interfaces.d.ts +32 -82
- package/dist/dts/metadata.d.ts +6 -5
- package/dist/dts/observation/arrays.d.ts +1 -1
- package/dist/dts/observation/observable.bench.d.ts +18 -0
- package/dist/dts/observation/observable.d.ts +5 -5
- package/dist/dts/pending-task.d.ts +19 -7
- package/dist/dts/platform.d.ts +11 -2
- package/dist/dts/polyfills.d.ts +0 -8
- package/dist/dts/styles/css-binding-directive.d.ts +60 -0
- package/dist/dts/styles/css.d.ts +9 -7
- package/dist/dts/styles/element-styles.d.ts +1 -14
- package/dist/dts/styles/host.d.ts +2 -5
- package/dist/dts/styles/style-strategy.d.ts +42 -0
- package/dist/dts/templating/compiler.d.ts +11 -13
- package/dist/dts/templating/{binding.d.ts → html-binding-directive.d.ts} +21 -41
- package/dist/dts/templating/html-directive.d.ts +44 -140
- package/dist/dts/templating/install-hydratable-view-templates.d.ts +1 -0
- package/dist/dts/templating/node-observation.d.ts +11 -1
- package/dist/dts/templating/ref.d.ts +4 -0
- package/dist/dts/templating/render.bench.d.ts +3 -0
- package/dist/dts/templating/render.d.ts +49 -9
- package/dist/dts/templating/repeat-basic-reverse.bench.d.ts +3 -0
- package/dist/dts/templating/repeat-basic-shift.bench.d.ts +3 -0
- package/dist/dts/templating/repeat.d.ts +31 -9
- package/dist/dts/templating/template.d.ts +97 -12
- package/dist/dts/templating/view.d.ts +146 -29
- package/dist/dts/templating/when-basic.bench.d.ts +3 -0
- package/dist/dts/templating/when-conditional.bench.d.ts +3 -0
- package/dist/dts/templating/when-switch.bench.d.ts +3 -0
- package/dist/dts/templating/when.d.ts +3 -1
- package/dist/dts/testing/fakes.d.ts +12 -1
- package/dist/dts/tsdoc-metadata.json +1 -1
- package/dist/dts/utilities.d.ts +55 -1
- package/dist/esm/binding/binding.js +18 -0
- package/dist/esm/binding/normalize.js +17 -0
- package/dist/esm/binding/one-time.js +21 -0
- package/dist/esm/binding/one-way.js +30 -0
- package/dist/esm/{templating/binding-signal.js → binding/signal.js} +22 -6
- package/dist/esm/{templating/binding-two-way.js → binding/two-way.js} +18 -12
- package/dist/esm/components/attributes.js +16 -1
- package/dist/esm/components/element-controller.js +319 -49
- package/dist/esm/components/element-hydration.js +2 -0
- package/dist/esm/components/fast-definitions.js +12 -4
- package/dist/esm/components/fast-element.js +3 -1
- package/dist/esm/components/hydration.js +104 -0
- package/dist/esm/components/install-hydration.js +3 -0
- package/dist/esm/context.js +26 -4
- package/dist/esm/debug.js +8 -2
- package/dist/esm/di/di.js +9 -12
- package/dist/esm/dom-policy.js +345 -0
- package/dist/esm/dom.js +101 -0
- package/dist/esm/hydration/target-builder.js +175 -0
- package/dist/esm/index.js +34 -25
- package/dist/esm/index.rollup.debug.js +3 -1
- package/dist/esm/index.rollup.js +3 -1
- package/dist/esm/interfaces.js +51 -3
- package/dist/esm/metadata.js +11 -8
- package/dist/esm/observation/arrays.js +1 -1
- package/dist/esm/observation/observable.bench.js +79 -0
- package/dist/esm/observation/observable.js +20 -15
- package/dist/esm/observation/update-queue.js +2 -2
- package/dist/esm/pending-task.js +13 -1
- package/dist/esm/platform.js +12 -2
- package/dist/esm/polyfills.js +3 -61
- package/dist/esm/styles/css-binding-directive.js +76 -0
- package/dist/esm/styles/css.js +14 -7
- package/dist/esm/styles/element-styles.js +0 -33
- package/dist/esm/styles/style-strategy.js +1 -0
- package/dist/esm/templating/children.js +8 -4
- package/dist/esm/templating/compiler.js +37 -44
- package/dist/esm/templating/html-binding-directive.js +218 -0
- package/dist/esm/templating/html-directive.js +25 -152
- package/dist/esm/templating/install-hydratable-view-templates.js +17 -0
- package/dist/esm/templating/node-observation.js +14 -8
- package/dist/esm/templating/ref.js +1 -1
- package/dist/esm/templating/render.bench.js +56 -0
- package/dist/esm/templating/render.js +74 -30
- package/dist/esm/templating/repeat-basic-reverse.bench.js +43 -0
- package/dist/esm/templating/repeat-basic-shift.bench.js +43 -0
- package/dist/esm/templating/repeat.js +116 -17
- package/dist/esm/templating/template.js +135 -60
- package/dist/esm/templating/view.js +254 -34
- package/dist/esm/templating/when-basic.bench.js +36 -0
- package/dist/esm/templating/when-conditional.bench.js +39 -0
- package/dist/esm/templating/when-switch.bench.js +68 -0
- package/dist/esm/templating/when.js +12 -5
- package/dist/esm/testing/fakes.js +32 -1
- package/dist/esm/testing/fixture.js +1 -1
- package/dist/esm/utilities.js +97 -1
- package/dist/fast-element.api.json +9788 -5666
- package/dist/fast-element.d.ts +813 -2392
- package/dist/fast-element.debug.js +2785 -969
- package/dist/fast-element.debug.min.js +3 -1
- package/dist/fast-element.js +2638 -828
- package/dist/fast-element.min.js +3 -1
- package/dist/fast-element.untrimmed.d.ts +661 -313
- package/docs/{api-report.md → api-report.api.md} +238 -151
- package/docs/context/api-report.api.md +69 -0
- package/docs/di/api-report.api.md +315 -0
- package/karma.conf.cjs +2 -1
- package/package.json +59 -47
- package/scripts/run-api-extractor.js +51 -0
- package/scripts/run-benchmarks.js +46 -0
- package/tensile.config.js +12 -0
- package/dist/dts/templating/dom.d.ts +0 -41
- package/dist/esm/templating/binding.js +0 -282
- package/dist/esm/templating/dom.js +0 -49
- package/docs/guide/declaring-templates.md +0 -230
- package/docs/guide/defining-elements.md +0 -214
- package/docs/guide/leveraging-css.md +0 -253
- package/docs/guide/next-steps.md +0 -13
- package/docs/guide/observables-and-state.md +0 -213
- package/docs/guide/using-directives.md +0 -576
- package/docs/guide/working-with-shadow-dom.md +0 -296
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: defining-elements
|
|
3
|
-
title: Defining Elements
|
|
4
|
-
sidebar_label: Defining Elements
|
|
5
|
-
custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-element/docs/guide/defining-elements.md
|
|
6
|
-
description: To define a custom element, begin by creating a class that extends FASTElement and decorate it with the @customElement decorator, providing the element name.
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Basic elements
|
|
10
|
-
|
|
11
|
-
To define a custom element, begin by creating a class that extends `FASTElement` and decorate it with the `@customElement` decorator, providing the element name.
|
|
12
|
-
|
|
13
|
-
**Example: A Basic `FASTElement` Definition**
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
import { FASTElement, customElement } from '@microsoft/fast-element';
|
|
17
|
-
|
|
18
|
-
@customElement('name-tag')
|
|
19
|
-
export class NameTag extends FASTElement {
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
With this in place, you can now use your `name-tag` element anywhere in HTML with the following markup:
|
|
25
|
-
|
|
26
|
-
**Example: Using a Web Component**
|
|
27
|
-
|
|
28
|
-
```html
|
|
29
|
-
<name-tag></name-tag>
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
:::important
|
|
33
|
-
Web Component names must contain a `-` in order to prevent future conflicts with built-in elements and to namespace components from different libraries. For more information on the basics of Web Components [see this set of articles](https://developers.google.com/web/fundamentals/web-components).
|
|
34
|
-
:::
|
|
35
|
-
|
|
36
|
-
:::note
|
|
37
|
-
HTML has a few special tags known as "self-closing tags". Common examples include `<input>` and `<img>`. However, most HTML elements and **all** web components must have an explicit closing tag.
|
|
38
|
-
:::
|
|
39
|
-
|
|
40
|
-
We've got a basic Web Component in place, but it doesn't do much. So, let's add an attribute and make it render something.
|
|
41
|
-
|
|
42
|
-
**Example: Adding Attributes to a `FASTElement`**
|
|
43
|
-
|
|
44
|
-
```ts
|
|
45
|
-
import { FASTElement, customElement, attr } from '@microsoft/fast-element';
|
|
46
|
-
|
|
47
|
-
@customElement('name-tag')
|
|
48
|
-
export class NameTag extends FASTElement {
|
|
49
|
-
@attr greeting: string = 'Hello';
|
|
50
|
-
|
|
51
|
-
// optional method
|
|
52
|
-
greetingChanged() {
|
|
53
|
-
...
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
To add attributes to your HTML element, create properties decorated by the `@attr` decorator. All attributes defined this way will be automatically registered with the platform so that they can be updated through the browser's native `setAttribute` API as well as the property. You can optionally add a method with the naming convention *propertyName*Changed to your class (e.g. `greeting` and `greetingChanged()`), and this method will be called whenever your property changes, whether it changes through the property or the attribute API.
|
|
59
|
-
|
|
60
|
-
:::note
|
|
61
|
-
All properties decorated with `@attr` are also *observable*. See [observables and state](./observables-and-state.md) for information about how observables enable efficient rendering.
|
|
62
|
-
:::
|
|
63
|
-
|
|
64
|
-
By default, anything extending from `FASTElement` will automatically have a `ShadowRoot` attached in order to enable encapsulated rendering.
|
|
65
|
-
|
|
66
|
-
To see it in action, you can use the same HTML as above, or change the default `greeting` with the following:
|
|
67
|
-
|
|
68
|
-
**Example: Using a Web Component with Attributes**
|
|
69
|
-
|
|
70
|
-
```html
|
|
71
|
-
<name-tag greeting="Hola"></name-tag>
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## Customizing attributes
|
|
75
|
-
|
|
76
|
-
By default, any attribute created with `@attr` will perform no explicit type coercion other than when it reflects its value to the HTML DOM via the `setAttribute` API. However, you can convert DOM attribute string values to and from arbitrary types as well as control the `mode` that is used to reflect property values to the DOM. There are three modes available through the `mode` property of the attribute configuration:
|
|
77
|
-
|
|
78
|
-
* `reflect` - The *default* mode that is used if none is specified. This reflects property changes to the DOM. If a `converter` is supplied, it will invoke the converter before calling the `setAttribute` DOM API.
|
|
79
|
-
* `boolean` - This mode causes your attribute to function using the HTML boolean attribute behavior. When your attribute is present in the DOM or equal to its own name, the value will be true. When the attribute is absent from the DOM, the value of the property will be false. Setting the property will also update the DOM by adding/removing the attribute.
|
|
80
|
-
* `fromView` - This mode skips reflecting the value of the property back to the HTML attribute, but does receive updates when changed through `setAttribute`.
|
|
81
|
-
|
|
82
|
-
In addition to setting the `mode`, you can also supply a custom `ValueConverter` by setting the `converter` property of the attribute configuration. The converter must implement the following interface:
|
|
83
|
-
|
|
84
|
-
```ts
|
|
85
|
-
interface ValueConverter {
|
|
86
|
-
toView(value: any): string;
|
|
87
|
-
fromView(value: string): any;
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
Here's how it works:
|
|
92
|
-
|
|
93
|
-
* When the DOM attribute value changes, the converter's `fromView` method will be called, allowing custom code to coerce the value to the proper type expected by the property.
|
|
94
|
-
* When the property value changes, the converter's `fromView` method will also be called, ensuring that the type is correct. After this, the `mode` will be determined. If the mode is set to `reflect` then the converter's `toView` method will be called to allow the type to be formatted before writing to the attribute using `setAttribute`.
|
|
95
|
-
|
|
96
|
-
:::important
|
|
97
|
-
When the `mode` is set to `boolean`, a built-in `booleanConverter` is automatically used to ensure type correctness so that the manual configuration of the converter is not needed in this common scenario.
|
|
98
|
-
:::
|
|
99
|
-
|
|
100
|
-
**Example: An Attribute in Reflect Mode with No Special Conversion**
|
|
101
|
-
|
|
102
|
-
```ts
|
|
103
|
-
import { FASTElement, customElement, attr } from '@microsoft/fast-element';
|
|
104
|
-
|
|
105
|
-
@customElement('name-tag')
|
|
106
|
-
export class NameTag extends FASTElement {
|
|
107
|
-
@attr greeting: string = 'Hello';
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
**Example: An Attribute in Boolean Mode with Boolean Conversion**
|
|
112
|
-
|
|
113
|
-
```ts
|
|
114
|
-
import { FASTElement, customElement, attr } from '@microsoft/fast-element';
|
|
115
|
-
|
|
116
|
-
@customElement('my-checkbox')
|
|
117
|
-
export class MyCheckbox extends FASTElement {
|
|
118
|
-
@attr({ mode: 'boolean' }) disabled: boolean = false;
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
**Example: An Attribute in Reflect Mode with Custom Conversion**
|
|
123
|
-
|
|
124
|
-
```ts
|
|
125
|
-
import { FASTElement, customElement, attr, ValueConverter } from '@microsoft/fast-element';
|
|
126
|
-
|
|
127
|
-
const numberConverter: ValueConverter = {
|
|
128
|
-
toView(value: any): string {
|
|
129
|
-
// convert numbers to strings
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
fromView(value: string): any {
|
|
133
|
-
// convert strings to numbers
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
@customElement('my-counter')
|
|
138
|
-
export class MyCounter extends FASTElement {
|
|
139
|
-
@attr({ converter: numberConverter }) count: number = 0;
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## The element lifecycle
|
|
144
|
-
|
|
145
|
-
All Web Components support a series of lifecycle events that you can tap into to execute custom code at specific points in time. `FASTElement` implements several of these callbacks automatically in order to enable features of its templating engine (described in [declaring templates](./declaring-templates.md)). However, you can override them to provide your own code. Here's an example of how you would execute custom code when your element is inserted into the DOM.
|
|
146
|
-
|
|
147
|
-
**Example: Tapping into the Custom Element Lifecycle**
|
|
148
|
-
|
|
149
|
-
```ts
|
|
150
|
-
import { FASTElement, customElement, attr } from '@microsoft/fast-element';
|
|
151
|
-
|
|
152
|
-
@customElement('name-tag')
|
|
153
|
-
export class NameTag extends FASTElement {
|
|
154
|
-
@attr greeting: string = 'Hello';
|
|
155
|
-
|
|
156
|
-
greetingChanged() {
|
|
157
|
-
this.shadowRoot!.innerHTML = this.greeting;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
connectedCallback() {
|
|
161
|
-
super.connectedCallback();
|
|
162
|
-
console.log('name-tag is now connected to the DOM');
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
The full list of available lifecycle callbacks is:
|
|
168
|
-
|
|
169
|
-
| Callback | Description |
|
|
170
|
-
| ------------- |-------------|
|
|
171
|
-
| constructor | Runs when the element is created or upgraded. `FASTElement` will attach the shadow DOM at this time. |
|
|
172
|
-
| connectedCallback | Runs when the element is inserted into the DOM. On first connect, `FASTElement` hydrates the HTML template, connects template bindings, and adds the styles. |
|
|
173
|
-
| disconnectedCallback | Runs when the element is removed from the DOM. `FASTElement` will remove template bindings and clean up resources at this time. |
|
|
174
|
-
| attributeChangedCallback(attrName, oldVal, newVal) | Runs any time one of the element's custom attributes changes. `FASTElement` uses this to sync the attribute with its property. When the property updates, a render update is also queued, if there was a template dependency. |
|
|
175
|
-
| adoptedCallback | Runs if the element was moved from its current `document` into a new `document` via a call to the `adoptNode(...)` API. |
|
|
176
|
-
|
|
177
|
-
## Working without decorators
|
|
178
|
-
|
|
179
|
-
The examples above and those throughout our documentation leverage TypeScript, and in particular, the decorators feature of the language. Decorators are an upcoming feature planned for a future version of JavaScript, but their design is not yet finished. While the syntax for decorator usage is not likely to change in the final version of the feature, some of our community members may feel uncomfortable using this feature at this stage. Additionally, since decorators are transpiled into code that uses helper functions (both in TypeScript and Babel) the compiled output will be larger than the equivalent non-decorator code.
|
|
180
|
-
|
|
181
|
-
While there are size implications of using decorators prior to full language support, they do present the most declarative and readable form of the API, and we recommend their use for the average project. To strike a balance between declarative readability and size, we recommend that TypeScript be used in combination with the `"importHelpers": true` compiler option. When this option is set, instead of generating helper functions for decorators into every file, TypeScript will import a set of shared helpers published in the `tslib` package.
|
|
182
|
-
|
|
183
|
-
For those that require the smallest possible builds, FAST Elements can be completely defined in Vanilla JS, without using decorators, by leveraging a static `definition` field on your class. The `definition` field only needs to present the same configuration as the `@customElement` decorator. Here's an example that shows the use of the `definition` field along with a manual call to `define` the element:
|
|
184
|
-
|
|
185
|
-
```js
|
|
186
|
-
import { FASTElement, html, css } from '@microsoft/fast-element';
|
|
187
|
-
|
|
188
|
-
const template = html`...`;
|
|
189
|
-
const styles = css`...`;
|
|
190
|
-
const converter = { ... };
|
|
191
|
-
|
|
192
|
-
export class MyElement extends FASTElement {
|
|
193
|
-
static definition = {
|
|
194
|
-
name: 'my-element',
|
|
195
|
-
template,
|
|
196
|
-
styles,
|
|
197
|
-
attributes: [
|
|
198
|
-
'value', // same attr/prop
|
|
199
|
-
{ attribute: 'some-attr', property: 'someAttr' }, // different attr/prop
|
|
200
|
-
{ property: 'count', converter } // derive attr; add converter
|
|
201
|
-
]
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
value = '';
|
|
205
|
-
someAttr = '';
|
|
206
|
-
count = 0;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
FASTElement.define(MyElement);
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
:::note
|
|
213
|
-
The `definition` can also be separated from the class and passed into the `define` call directly if desired. Here's what that would look like: `FASTElement.define(MyElement, myDefinition);`
|
|
214
|
-
:::
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: leveraging-css
|
|
3
|
-
title: Leveraging CSS
|
|
4
|
-
sidebar_label: Leveraging CSS
|
|
5
|
-
custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-element/docs/guide/leveraging-css.md
|
|
6
|
-
description: Similar to HTML, FASTElement provides a css tagged template helper to allow creating and re-using CSS.
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Basic styles
|
|
10
|
-
|
|
11
|
-
The final piece of our component story is CSS. Similar to HTML, `FASTElement` provides a `css` tagged template helper to allow creating and re-using CSS. Let's add some CSS for our `name-tag` component.
|
|
12
|
-
|
|
13
|
-
**Example: Adding CSS to a `FASTElement`**
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
import { html, css, customElement, attr, FASTElement } from "@microsoft/fast-element";
|
|
17
|
-
|
|
18
|
-
const template = html<NameTag>`
|
|
19
|
-
<div class="header">
|
|
20
|
-
<slot name="avatar"></slot>
|
|
21
|
-
<h3>${x => x.greeting.toUpperCase()}</h3>
|
|
22
|
-
<h4>my name is</h4>
|
|
23
|
-
</div>
|
|
24
|
-
|
|
25
|
-
<div class="body">
|
|
26
|
-
<slot></slot>
|
|
27
|
-
</div>
|
|
28
|
-
|
|
29
|
-
<div class="footer"></div>
|
|
30
|
-
`;
|
|
31
|
-
|
|
32
|
-
const styles = css`
|
|
33
|
-
:host {
|
|
34
|
-
display: inline-block;
|
|
35
|
-
contain: content;
|
|
36
|
-
color: white;
|
|
37
|
-
background: var(--fill-color);
|
|
38
|
-
border-radius: var(--border-radius);
|
|
39
|
-
min-width: 325px;
|
|
40
|
-
text-align: center;
|
|
41
|
-
box-shadow: 0 0 calc(var(--depth) * 1px) rgba(0,0,0,.5);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
:host([hidden]) {
|
|
45
|
-
display: none;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
.header {
|
|
49
|
-
margin: 16px 0;
|
|
50
|
-
position: relative;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
h3 {
|
|
54
|
-
font-weight: bold;
|
|
55
|
-
font-family: 'Source Sans Pro';
|
|
56
|
-
letter-spacing: 4px;
|
|
57
|
-
font-size: 32px;
|
|
58
|
-
margin: 0;
|
|
59
|
-
padding: 0;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
h4 {
|
|
63
|
-
font-family: sans-serif;
|
|
64
|
-
font-size: 18px;
|
|
65
|
-
margin: 0;
|
|
66
|
-
padding: 0;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.body {
|
|
70
|
-
background: white;
|
|
71
|
-
color: black;
|
|
72
|
-
padding: 32px 8px;
|
|
73
|
-
font-size: 42px;
|
|
74
|
-
font-family: cursive;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.footer {
|
|
78
|
-
height: 16px;
|
|
79
|
-
background: var(--fill-color);
|
|
80
|
-
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
|
81
|
-
}
|
|
82
|
-
`;
|
|
83
|
-
|
|
84
|
-
@customElement({
|
|
85
|
-
name: 'name-tag',
|
|
86
|
-
template,
|
|
87
|
-
styles
|
|
88
|
-
})
|
|
89
|
-
export class NameTag extends FASTElement {
|
|
90
|
-
@attr greeting: string = 'Hello';
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
Using the `css` helper, we're able to create `ElementStyles`. We configure this with the element through the `styles` option of the decorator. Internally, `FASTElement` will leverage [Constructable Stylesheet Objects](https://wicg.github.io/construct-stylesheets/) and `ShadowRoot#adoptedStyleSheets` to efficiently re-use CSS across components. This means that even if we have 1k instances of our `name-tag` component, they will all share a single instance of the associated styles, allowing for reduced memory allocation and improved performance. Because the styles are associated with the `ShadowRoot`, they will also be encapsulated. This ensures that your styles don't affect other elements and other element styles don't affect your element.
|
|
95
|
-
|
|
96
|
-
:::note
|
|
97
|
-
We've used [CSS Custom Properties](https://developer.mozilla.org/en-US/docs/Web/CSS/--*) throughout our CSS as well as [CSS Calc](https://developer.mozilla.org/en-US/docs/Web/CSS/calc) in order to enable our component to be styled in basic ways by consumers. Additionally, consider adding [CSS Shadow Parts](https://developer.mozilla.org/en-US/docs/Web/CSS/::part) to your template, to enable even more powerful customization.
|
|
98
|
-
:::
|
|
99
|
-
|
|
100
|
-
## Composing styles
|
|
101
|
-
|
|
102
|
-
One of the nice features of `ElementStyles` is that it can be composed with other styles. Imagine that we had a CSS normalize that we wanted to use in our `name-tag` component. We could compose that into our styles like this:
|
|
103
|
-
|
|
104
|
-
**Example: Composing CSS Registries**
|
|
105
|
-
|
|
106
|
-
```ts
|
|
107
|
-
import { normalize } from './normalize';
|
|
108
|
-
|
|
109
|
-
const styles = css`
|
|
110
|
-
${normalize}
|
|
111
|
-
:host {
|
|
112
|
-
display: inline-block;
|
|
113
|
-
contain: content;
|
|
114
|
-
color: white;
|
|
115
|
-
background: var(--fill-color);
|
|
116
|
-
border-radius: var(--border-radius);
|
|
117
|
-
min-width: 325px;
|
|
118
|
-
text-align: center;
|
|
119
|
-
box-shadow: 0 0 calc(var(--depth) * 1px) rgba(0,0,0,.5);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
...
|
|
123
|
-
`;
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
Rather than simply concatenating CSS strings, the `css` helper understands that `normalize` is `ElementStyles` and is able to re-use the same Constructable StyleSheet instance as any other component that uses `normalize`.
|
|
127
|
-
|
|
128
|
-
:::note
|
|
129
|
-
You can also pass a CSS `string` or a [CSSStyleSheet](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet) instance directly to the element definition, or even a mixed array of `string`, `CSSStyleSheet`, or `ElementStyles`.
|
|
130
|
-
:::
|
|
131
|
-
|
|
132
|
-
### Partial CSS
|
|
133
|
-
There are times when you may want to create reusable blocks of *partial* CSS, where the abstraction is not valid CSS in and of itself, such as groups of CSS properties or a complex value. To do that, you can use the `cssPartial` tagged template literal:
|
|
134
|
-
|
|
135
|
-
```ts
|
|
136
|
-
import { css, cssPartial } from "@microsoft/fast-element";
|
|
137
|
-
|
|
138
|
-
const partial = cssPartial`color: red;`;
|
|
139
|
-
const styles = css`:host{ ${partial} }`;
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
`cssPartial` can also compose all structures that `css` can compose, providing even greater flexibility.
|
|
143
|
-
|
|
144
|
-
## CSSDirective
|
|
145
|
-
The `CSSDirective` allows binding behavior to an element via `ElementStyles`. To create a `CSSDirective`, import and extend `CSSDirective` from `@microsoft/fast-element`:
|
|
146
|
-
|
|
147
|
-
```ts
|
|
148
|
-
import { CSSDirective } from "@microsoft/fast-element"
|
|
149
|
-
|
|
150
|
-
class RandomWidth extends CSSDirective {}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
A CSS directive has two key methods that you can leverage to add dynamic behavior via CSS:
|
|
154
|
-
|
|
155
|
-
### createCSS
|
|
156
|
-
`CSSDirective` has a `createCSS()` method that returns a string to be interpolated into an `ElementStyles`:
|
|
157
|
-
|
|
158
|
-
```ts
|
|
159
|
-
class RandomWidth extends CSSDirective {
|
|
160
|
-
createCSS() {
|
|
161
|
-
return "width: var(--random-width);"
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### createBehavior
|
|
167
|
-
The `createBehavior()` method can be used to create a `Behavior` that is bound to the element using the `CSSDirective`:
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
```ts
|
|
171
|
-
class RandomWidth extends CSSDirective {
|
|
172
|
-
private property = "--random-width";
|
|
173
|
-
createCSS() {
|
|
174
|
-
return `width: var(${this.property});`
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
createBehavior() {
|
|
178
|
-
return {
|
|
179
|
-
bind(el) {
|
|
180
|
-
el.style.setProperty(this.property, Math.random() * 100)
|
|
181
|
-
}
|
|
182
|
-
unbind(el) {
|
|
183
|
-
el.style.removeProperty(this.property);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### Usage in ElementStyles
|
|
191
|
-
The `CSSDirective` can then be used in an `ElementStyles`, where the CSS string from `createCSS()` will be interpolated into the stylesheet, and the behavior returned from `createBehavior()` will get bound to the element using the stylesheet:
|
|
192
|
-
|
|
193
|
-
```ts
|
|
194
|
-
const styles = css`:host {${new RandomWidth()}}`;
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
## Shadow DOM styling
|
|
198
|
-
|
|
199
|
-
You may have noticed the `:host` selector we used in our `name-tag` styles. This selector allows us to apply styles directly to our custom element. Here are a few things to consider always configuring for your host element:
|
|
200
|
-
|
|
201
|
-
* **display** - By default, the `display` property of a custom element is `inline`, so consider whether you want your element's default display behavior to be different.
|
|
202
|
-
* **contain** - If your element's painting is contained within its bounds, consider setting the CSS `contain` property to `content`. The right containment model can positively affect your element's performance. [See the MDN docs](https://developer.mozilla.org/en-US/docs/web/css/contain) for more information on the various values of `contain` and what they do.
|
|
203
|
-
* **hidden** - In addition to a default `display` style, add support for `hidden` so that your default `display` does not override this state. This can be done with `:host([hidden]) { display: none }`.
|
|
204
|
-
|
|
205
|
-
## Slotted content
|
|
206
|
-
|
|
207
|
-
In addition to providing host styles, you can also provide default styles for content that gets slotted. For example, if we wanted to style all `img` elements that were slotted into our `name-tag`, we could do it like this:
|
|
208
|
-
|
|
209
|
-
**Example: Slotted Styles**
|
|
210
|
-
|
|
211
|
-
```ts
|
|
212
|
-
const styles = css`
|
|
213
|
-
...
|
|
214
|
-
|
|
215
|
-
::slotted(img) {
|
|
216
|
-
border-radius: 50%;
|
|
217
|
-
height: 64px;
|
|
218
|
-
width: 64px;
|
|
219
|
-
box-shadow: 0 0 calc(var(--depth) / 2px) rgba(0,0,0,.5);
|
|
220
|
-
position: absolute;
|
|
221
|
-
left: 16px;
|
|
222
|
-
top: -4px;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
...
|
|
226
|
-
`;
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
:::note
|
|
230
|
-
Both slotted and host styles can be overridden by the element user. Think of these as the *default* styles that you are providing, so that your elements look and function correctly out-of-the-box.
|
|
231
|
-
:::
|
|
232
|
-
|
|
233
|
-
## Styles and the element lifecycle
|
|
234
|
-
|
|
235
|
-
It is during the `connectedCallback` phase of the Custom Element lifecycle that `FASTElement` adds the element's styles. The styles are only added the first time the element is connected.
|
|
236
|
-
|
|
237
|
-
In most cases, the styles that `FASTElement` renders are determined by the `styles` property of the Custom Element's configuration. However, you can also implement a method on your Custom Element class named `resolveStyles()` that returns an `ElementStyles` instance. If this method is present, it will be called during `connectedCallback` to obtain the styles to use. This allows the element author to dynamically select completely different styles based on the state of the element at the time of connection.
|
|
238
|
-
|
|
239
|
-
In addition to dynamic style selection during the `connectedCallback`, the `$fastController` property of `FASTElement` enables dynamically changing the styles at any time through setting the controller's `styles` property to any valid styles.
|
|
240
|
-
|
|
241
|
-
### Hiding undefined elements
|
|
242
|
-
|
|
243
|
-
Custom Elements that have not been [upgraded](https://developers.google.com/web/fundamentals/web-components/customelements#upgrades) and don't have styles attached can still be rendered by the browser but they likely do not look how they are supposed to. To avoid a *flash of un-styled content* (FOUC), visually hide Custom Elements if they have not been *defined*:
|
|
244
|
-
|
|
245
|
-
```CSS
|
|
246
|
-
:not(:defined) {
|
|
247
|
-
visibility: hidden;
|
|
248
|
-
}
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
:::important
|
|
252
|
-
The consuming application must apply this, as the components themselves do not.
|
|
253
|
-
:::
|
package/docs/guide/next-steps.md
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: next-steps
|
|
3
|
-
title: Next Steps
|
|
4
|
-
sidebar_label: Next Steps
|
|
5
|
-
custom_edit_url: https://github.com/microsoft/fast/edit/master/packages/web-components/fast-element/docs/guide/next-steps.md
|
|
6
|
-
description: Now that you're familiar with the robust and powerful features of FASTElement, you're ready to build your own components and apps.
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
We've seen how to use `FASTElement` to declaratively build Web Components. In addition to the basics of element and attribute definition, `FASTElement` also provides a way to declare templates capable of high-performance rendering, and efficient, incremental batched updates. Finally, CSS can easily be associated with an element in a way that leverages core platform optimizations for performance and low memory allocation.
|
|
10
|
-
|
|
11
|
-
Now that you're familiar with the robust and powerful features of `FASTElement`, you're ready to build your own components and apps. But you don't have to start from scratch there either! If you haven't already explored them, check out our [FAST Components](../components/getting-started.md), which provide all the basic UI building-blocks you'd expect in a modern component library. You can also leverage the same adaptive design system that our own components use to enable robust theming throughout all you create. Read more on that in [Styling Components](../design-systems/fast-frame.md#configuring-components). Finally, you'll want to take advantage of a modern toolset by installing [a powerful editor and plugins](../tools/vscode.md).
|
|
12
|
-
|
|
13
|
-
For a quick reference, check out [our Cheat Sheet](../resources/cheat-sheet.md).
|