@lightningjs/blits 1.30.2 → 1.31.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/CHANGELOG.md +1029 -1019
- package/LICENSE +202 -202
- package/NOTICE +12 -12
- package/README.md +33 -33
- package/bin/index.js +8 -8
- package/blits.d.ts +6 -6
- package/index.d.ts +1099 -1099
- package/index.js +28 -28
- package/package.json +57 -56
- package/public/assets/fps_sprite.base64.js +1 -1
- package/scripts/postpublish.js +59 -59
- package/scripts/prepublishOnly.js +84 -84
- package/scripts/prepush.js +78 -78
- package/src/announcer/announcer.js +162 -162
- package/src/announcer/speechSynthesis.js +107 -107
- package/src/application.js +100 -100
- package/src/component/base/announcer.js +27 -27
- package/src/component/base/events.js +69 -69
- package/src/component/base/index.js +33 -33
- package/src/component/base/methods.js +244 -244
- package/src/component/base/router.js +41 -41
- package/src/component/base/timeouts_intervals.js +99 -99
- package/src/component/base/utils.js +72 -72
- package/src/component/setup/computed.js +48 -48
- package/src/component/setup/index.js +62 -62
- package/src/component/setup/input.js +30 -30
- package/src/component/setup/methods.js +37 -37
- package/src/component/setup/props.js +62 -62
- package/src/component/setup/routes.js +42 -42
- package/src/component/setup/state.js +59 -59
- package/src/component/setup/watch.js +35 -35
- package/src/component.js +437 -437
- package/src/components/Circle.js +73 -73
- package/src/components/FPScounter.js +1510 -1510
- package/src/components/RouterView.js +81 -81
- package/src/components/Sprite.js +94 -94
- package/src/components/index.js +28 -28
- package/src/constants.js +21 -21
- package/src/engine.js +1 -1
- package/src/engines/L3/element.js +744 -744
- package/src/engines/L3/fontLoader.js +38 -38
- package/src/engines/L3/index.js +7 -7
- package/src/engines/L3/launch.js +123 -123
- package/src/engines/L3/shaderLoader.js +12 -12
- package/src/engines/index.js +1 -1
- package/src/focus.js +90 -90
- package/src/helpers/deepEqualArray.js +50 -50
- package/src/helpers/fetchJson.js +34 -34
- package/src/helpers/sequence.js +26 -26
- package/src/launch.js +123 -123
- package/src/lib/blitsfileconverter/blitsfileconverter.js +52 -52
- package/src/lib/codegenerator/generator.js +788 -788
- package/src/lib/colors/colors.js +92 -92
- package/src/lib/colors/htmlColors.js +168 -168
- package/src/lib/componentId.js +49 -49
- package/src/lib/eventListeners.js +123 -123
- package/src/lib/hooks.js +59 -59
- package/src/lib/lifecycle.js +85 -85
- package/src/lib/log.js +117 -117
- package/src/lib/precompiler/precompiler.js +73 -73
- package/src/lib/reactivity/effect.js +93 -93
- package/src/lib/reactivity/reactive.js +208 -208
- package/src/lib/reactivityguard/computedprops.js +218 -218
- package/src/lib/symbols.js +108 -108
- package/src/lib/templateparser/parser.js +386 -386
- package/src/lib/utils.js +27 -27
- package/src/plugin.js +27 -27
- package/src/plugins/appstate.js +26 -26
- package/src/plugins/index.js +20 -20
- package/src/plugins/language.js +152 -152
- package/src/plugins/log.js +25 -25
- package/src/plugins/theme.js +94 -94
- package/src/router/router.js +516 -514
- package/src/router/transitions/fadeIn.js +27 -27
- package/src/router/transitions/fadeInOut.js +33 -33
- package/src/router/transitions/index.js +21 -21
- package/src/router/transitions/slideIn.js +28 -28
- package/src/router/transitions/slideInOut.js +33 -33
- package/src/settings.js +40 -40
- package/vite/blitsFileConverter.js +67 -67
- package/vite/index.js +28 -28
- package/vite/msdfGenerator.js +269 -269
- package/vite/preCompiler.js +47 -42
- package/vite/reactivityGuard.js +45 -45
- package/vscode/data/template-attributes.json +589 -589
- package/.editorconfig +0 -7
- package/.eslintignore +0 -1
- package/.eslintrc.cjs +0 -65
- package/.github/workflows/comment-lint-results.yml +0 -125
- package/.github/workflows/comment-test-results.yml +0 -109
- package/.github/workflows/deploy-docs.yml +0 -27
- package/.github/workflows/run-blits-tests.yml +0 -142
- package/.github/workflows/run-lint.yml +0 -128
- package/.husky/pre-commit +0 -1
- package/.husky/pre-push +0 -1
- package/.vscode/extensions.json +0 -7
- package/.vscode/settings.json +0 -9
- package/COPYING +0 -1
- package/banner.png +0 -0
- package/docs/.nojekyll +0 -0
- package/docs/README.md +0 -19
- package/docs/_sidebar.md +0 -37
- package/docs/built-in/directives.md +0 -50
- package/docs/built-in/for-loop.md +0 -204
- package/docs/built-in/layout.md +0 -168
- package/docs/components/component_state.md +0 -90
- package/docs/components/computed_properties.md +0 -45
- package/docs/components/lifecycle_events.md +0 -42
- package/docs/components/methods.md +0 -45
- package/docs/components/props.md +0 -56
- package/docs/components/user_input.md +0 -186
- package/docs/components/utility_methods.md +0 -320
- package/docs/components/watchers.md +0 -34
- package/docs/essentials/application_root.md +0 -19
- package/docs/essentials/components.md +0 -68
- package/docs/essentials/displaying_images.md +0 -67
- package/docs/essentials/displaying_text.md +0 -135
- package/docs/essentials/element_attributes.md +0 -195
- package/docs/essentials/settings.md +0 -117
- package/docs/essentials/template_syntax.md +0 -83
- package/docs/getting_started/file_structure.md +0 -58
- package/docs/getting_started/getting_started.md +0 -45
- package/docs/getting_started/intro.md +0 -20
- package/docs/index.html +0 -47
- package/docs/performance/lazy-loading.md +0 -161
- package/docs/plugins/global_app_state.md +0 -98
- package/docs/plugins/language.md +0 -172
- package/docs/plugins/text-to-speech-announcer.md +0 -120
- package/docs/plugins/theme.md +0 -176
- package/docs/router/basics.md +0 -175
- package/docs/router/hooks.md +0 -70
- package/docs/router/transitions.md +0 -146
- package/docs/sidebar.json +0 -171
- package/docs/transitions_animations/transitions.md +0 -150
- package/jsconfig.json +0 -12
- package/src/component/setup/props.test.js +0 -238
- package/src/component.test.js +0 -388
- package/src/components/Circle.orig.js +0 -31
- package/src/components/FPScounter.orig.js +0 -121
- package/src/components/RouterView.orig.js +0 -54
- package/src/components/Sprite.orig.js +0 -58
- package/src/components/index.orig.js +0 -28
- package/src/engines/L3/element.test.js +0 -579
- package/src/helpers/deepEqualArray.test.js +0 -127
- package/src/lib/codegenerator/generator.test.js +0 -3801
- package/src/lib/colors/colors.test.js +0 -290
- package/src/lib/componentId.test.js +0 -84
- package/src/lib/eventListeners.test.js +0 -236
- package/src/lib/reactivity/effect.test.js +0 -35
- package/src/lib/reactivity/reactive.test.js +0 -27
- package/src/lib/templateparser/parser.test.js +0 -1411
- package/src/router/router.test.js +0 -473
package/docs/_sidebar.md
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
- Getting started
|
|
2
|
-
- [Intro](/getting_started/intro.md)
|
|
3
|
-
- [Getting started](/getting_started/getting_started.md)
|
|
4
|
-
- [File structure](/getting_started/file_structure.md)
|
|
5
|
-
- Essentials
|
|
6
|
-
- [Application root](/essentials/application_root.md)
|
|
7
|
-
- [Component basics](/essentials/components.md)
|
|
8
|
-
- [Template syntax](/essentials/template_syntax.md)
|
|
9
|
-
- [Supported element attributes](/essentials/element_attributes.md)
|
|
10
|
-
- [Displaying images](/essentials/displaying_images.md)
|
|
11
|
-
- [Displaying text](/essentials/displaying_text.md)
|
|
12
|
-
- Components
|
|
13
|
-
- [State](/components/component_state.md)
|
|
14
|
-
- [Props](/components/props.md)
|
|
15
|
-
- [Computed properties](/components/computed_properties.md)
|
|
16
|
-
- [Watchers](/components/watchers.md)
|
|
17
|
-
- [Hooking into lifecycle events](/components/lifecycle_events.md)
|
|
18
|
-
- [Handling User input](/components/user_input.md)
|
|
19
|
-
- [Methods](/components/methods.md)
|
|
20
|
-
- [Utility methods](/components/utility_methods.md)
|
|
21
|
-
- Transitions and Animations
|
|
22
|
-
- [Transitions](/transitions_animations/transitions.md)
|
|
23
|
-
- Built-in components
|
|
24
|
-
- [Directives](/built-in/directives.md)
|
|
25
|
-
- [For loop](/built-in/for-loop.md)
|
|
26
|
-
- [Layout](/built-in/layout.md)
|
|
27
|
-
- Router
|
|
28
|
-
- [Basics](/router/basics.md)
|
|
29
|
-
- [Hooks](/router/hooks.md)
|
|
30
|
-
- [Transitions](/router/transitions.md)
|
|
31
|
-
- Plugins
|
|
32
|
-
- [Text-to-Speech / Announcer](/plugins/text-to-speech-announcer.md)
|
|
33
|
-
- [Language](/plugins/language.md)
|
|
34
|
-
- [Theme](/plugins/theme.md)
|
|
35
|
-
- [Global App State](/plugins/global_app_state.md)
|
|
36
|
-
- Performance
|
|
37
|
-
- [Lazy loading]('/performance/lazy-loading.md')
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# Directives
|
|
2
|
-
|
|
3
|
-
Blits comes with a few built-in attributes that tap into specific behaviour provided by the framework - also known as _directives_. Most of them can be used in the template on both Elements and Components.
|
|
4
|
-
|
|
5
|
-
## Show-directive
|
|
6
|
-
|
|
7
|
-
The `show` attribute allows you to conditionally show and hide Components and Elements.
|
|
8
|
-
|
|
9
|
-
When passed a _truthy_ value, such as `true` or `1`, the element will be made visible. And when passed a _falsey_ value (`false` or `0`) it will not be visible.
|
|
10
|
-
|
|
11
|
-
```xml
|
|
12
|
-
<Element>
|
|
13
|
-
<Element w="100" h="100" color="purple" :show="$active"></Element>
|
|
14
|
-
<Element w="100" h="100" y="200" color="purple" show="false"></Element>
|
|
15
|
-
</Element>
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Is-directive
|
|
19
|
-
|
|
20
|
-
The `is` directive allows you to dynamically instantiate a Component based on a `state` variable or a passed `prop`.
|
|
21
|
-
|
|
22
|
-
It is very useful in combination with API driven Apps, where the type of Component to use, depends on what data is returned (i.e. a `Poster` or a `HeroImage`).
|
|
23
|
-
|
|
24
|
-
The `is`-component should always be used together with the built-in `Component`-tag.
|
|
25
|
-
|
|
26
|
-
```js
|
|
27
|
-
export default Blits.Component('DynamicComponents', {
|
|
28
|
-
template: `
|
|
29
|
-
<Element>
|
|
30
|
-
<Component is="$firstComponent" />
|
|
31
|
-
<Component is="$secondComponent" x="500" />
|
|
32
|
-
</Element>
|
|
33
|
-
`,
|
|
34
|
-
props: ['firstComponent', 'secondComponent'],
|
|
35
|
-
})
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
At the moment it's not possible to use the `is`-attribute as a _reactive_ attribute and have a component change type after instantiation.
|
|
39
|
-
|
|
40
|
-
## Ref-attribute
|
|
41
|
-
|
|
42
|
-
The declarative coding style that is promoted in Blits components, should generally remove the need to directly interact with individual Elements or Components in your template. However, in some cases you may need to reference them directly. For example, in order to delegate the focus.
|
|
43
|
-
|
|
44
|
-
For this use case, you can specify a `ref`-attribute on Elements (or Components). And by using the helper function `this.select()`, which is available on every Blits component, you can gain access to the child Element or Component inside your business logic.
|
|
45
|
-
|
|
46
|
-
The `select()`-function accepts the `ref`-value that you are looking for as a single argument, and returns the Element or Component if found.
|
|
47
|
-
|
|
48
|
-
<!-- ### If-directive
|
|
49
|
-
|
|
50
|
-
Todo -->
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
# For loop
|
|
2
|
-
|
|
3
|
-
The for loop is technically also a [directive](../directives.md), but such an important one that it deserves its own section.
|
|
4
|
-
|
|
5
|
-
The for loop directive can be used when you want to repeat multiple instances of an Element or a Component, without having to specify them hardcoded one by one in your template.
|
|
6
|
-
|
|
7
|
-
The for loop takes an `Array` of data, loops over it and for each Array-item an Element or Component is created. The `Array` can be a fixed one, but it can also dynamically be filled or modified and have it's changes reflect in the rendered result.
|
|
8
|
-
|
|
9
|
-
> Important: the for loop is a powerful and often used directive. Within Blits it's optimized to be as performant as possible. But if used incorrectly, it can be the cause of slow performance. So please read carefully through this entire section.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
## Basic syntax
|
|
13
|
-
|
|
14
|
-
The for-loop directive should be added as an attribute on the Element or Component that you want to repeat for each item in your Array. In the template syntax a `for ... in` construct is used. This ultimately transpiles down to a classic, optimized for loop.
|
|
15
|
-
|
|
16
|
-
```js
|
|
17
|
-
export default Blits.Component('ForLoop', {
|
|
18
|
-
template: `
|
|
19
|
-
<Element>
|
|
20
|
-
<Element :for="item in $items" w="100" h="100" color="lime" />
|
|
21
|
-
</Element>
|
|
22
|
-
`,
|
|
23
|
-
state() {
|
|
24
|
-
return {
|
|
25
|
-
items: ['Item 1', 'Item 2', 'Item 3']
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
})
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
The example above will generate 3 _lime green_ elements, based on the array of `items` in the Component state. They will appear on top of each other though, since they have no `x` and `y` positioning (which default to 0).
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
## Using the index
|
|
35
|
-
|
|
36
|
-
In order to fix the example above and make all 3 elements visible, we can use the `index` of the Array to position each item correctly.
|
|
37
|
-
|
|
38
|
-
All we need to do is declare the `index` in the `for`-directive and subsequently use it in the `x`-attribute, with a simple calculation.
|
|
39
|
-
|
|
40
|
-
You may choose any name for the `index` variable (like `i` or `forIndex`). This may be useful when you already have the `index`-key specified as a `state` or `prop` variable on your component, causing a conflict.
|
|
41
|
-
|
|
42
|
-
```js
|
|
43
|
-
export default Blits.Component('ForLoop', {
|
|
44
|
-
template: `
|
|
45
|
-
<Element>
|
|
46
|
-
<Element :for="(item, index) in $items" w="100" h="100" color="lime" :x="$index * 150" />
|
|
47
|
-
</Element>
|
|
48
|
-
`,
|
|
49
|
-
state() {
|
|
50
|
-
return {
|
|
51
|
-
items: ['Item 1', 'Item 2', 'Item 3']
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
})
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
You will now see that each Element is positioned next to each other, with a 50px space in between.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
## Using variables inside a for loop
|
|
61
|
-
|
|
62
|
-
When iterating over an Array in the for loop, you can reference the current Array item under the name specified in the for-in construct, prefixed with a `$`-sign. Besides this scoped Array item context, you _also_ have access to any `prop`, `state` or `computed` variable as you loop over an Array.
|
|
63
|
-
|
|
64
|
-
Consider the example below, that loops over an array of _Objects_, and _also_ references the `alpha` state variable.
|
|
65
|
-
|
|
66
|
-
```js
|
|
67
|
-
export default Blits.Component('ForLoop', {
|
|
68
|
-
template: `
|
|
69
|
-
<Element>
|
|
70
|
-
<Element
|
|
71
|
-
:for="(item, index) in $items"
|
|
72
|
-
w="100"
|
|
73
|
-
h="100"
|
|
74
|
-
:color="$item.color"
|
|
75
|
-
:x="$index * 150"
|
|
76
|
-
alpha="$alpha"
|
|
77
|
-
/>
|
|
78
|
-
</Element>
|
|
79
|
-
`,
|
|
80
|
-
state() {
|
|
81
|
-
return {
|
|
82
|
-
alpha: 0.5,
|
|
83
|
-
items: [{
|
|
84
|
-
id: 1,
|
|
85
|
-
color: 'green'
|
|
86
|
-
}, {
|
|
87
|
-
id: 2,
|
|
88
|
-
color: 'blue'
|
|
89
|
-
}, {
|
|
90
|
-
id: 3,
|
|
91
|
-
color: 'yellow'
|
|
92
|
-
}]
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
})
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
This will generate 3 squares aligned next to each other, each with a different color and they will use the _alpha_ specific in the Component state.
|
|
99
|
-
|
|
100
|
-
## The importance of using the key attribute
|
|
101
|
-
|
|
102
|
-
The examples above have demonstrated the basic usage of the for-loop. But they are all missing one _very important_ ingredient to make sure that for-loops that are subject to change, continue to perform well. Meet the `key`-attribute.
|
|
103
|
-
|
|
104
|
-
For performance reasons, it is essential to be able track the _identity_ of an Element or Component, whenever changes are made to the Array in the for loop.
|
|
105
|
-
|
|
106
|
-
Think of _identity_ as the field that makes an item in the Array unique, such as an `id` or a `hash`. It's basically the thing that allows you to distinguish between the poster of _The Matrix_ and the poster of _Frozen 2_, for example.
|
|
107
|
-
|
|
108
|
-
Providing this information, allows the for-loop to decide whether it should _update_ an existing Component or Element instance. Or whether we're dealing with a new Array item, and a new instance should be _created_.
|
|
109
|
-
|
|
110
|
-
Correctly using the `key`-attribute enables Blits to _reuse_ existing instances whenever possible - which obviously is good for performance.
|
|
111
|
-
|
|
112
|
-
It's important that the `key`-attribute is _unique_ for each Array item. Also beware that we can't rely on the `index` parameter provided in for loop, because that only identifies the position in the Array, and not the actual item itself.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
```js
|
|
116
|
-
export default Blits.Component('ForLoop', {
|
|
117
|
-
template: `
|
|
118
|
-
<Element>
|
|
119
|
-
<Element
|
|
120
|
-
:for="(item, index) in $items"
|
|
121
|
-
w="100"
|
|
122
|
-
h="100"
|
|
123
|
-
:color="$item.color"
|
|
124
|
-
:x="$index * 150"
|
|
125
|
-
alpha="$alpha"
|
|
126
|
-
key="$item.id"
|
|
127
|
-
/>
|
|
128
|
-
<!-- ^^ id is the unique field that identifies each array item -->
|
|
129
|
-
</Element>
|
|
130
|
-
`,
|
|
131
|
-
state() {
|
|
132
|
-
return {
|
|
133
|
-
alpha: 0.5,
|
|
134
|
-
items: [{
|
|
135
|
-
id: 1,
|
|
136
|
-
color: 'green'
|
|
137
|
-
}, {
|
|
138
|
-
id: 2,
|
|
139
|
-
color: 'blue'
|
|
140
|
-
}, {
|
|
141
|
-
id: 3,
|
|
142
|
-
color: 'yellow'
|
|
143
|
-
}]
|
|
144
|
-
}
|
|
145
|
-
},
|
|
146
|
-
hooks: {
|
|
147
|
-
ready() {
|
|
148
|
-
let count = 3
|
|
149
|
-
this.$setInterval(() => {
|
|
150
|
-
this.items.push({id: count++, color: randomColor()})
|
|
151
|
-
}, 2000)
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
})
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
In the example above we have added the `key`-attribute in the template. Now whenever we push a new item to the `items`-array, the for-loop will reuse the Elements previously created and only instantiate a new Element for the newly added item.
|
|
158
|
-
|
|
159
|
-
If we would omit the `key`-attribute, then whenever we push a new item to the Array, the for-loop would dispose all the old Elements and create new instances for _each_ item in the array.
|
|
160
|
-
|
|
161
|
-
## Referencing elements in the for loop
|
|
162
|
-
|
|
163
|
-
When you specify a `for`-attribute on an Element or a Component, it will effectively create multiple Elements / Components depending
|
|
164
|
-
on the length of the Array.
|
|
165
|
-
|
|
166
|
-
Generally it's not recommended to access and interact directly with Elements in a template, and that also goes for items in a For loop. But in some cases you may need to, for example to delegate focus to a specific item in the For loop.
|
|
167
|
-
|
|
168
|
-
The `ref`-attribute can be used in combination with the `for`-attribute as well.
|
|
169
|
-
|
|
170
|
-
Setting the _ref_ in a for loop context, can be done by either passing a string (i.e. `myitem`) and as Elements get generated in the for loop, the `index` value will be appended to it (i.e. `myitem0`, `myitem1`, etc.). Alternatively you can make the attribute interpolated and define the value for each item yourself (i.e. `:ref="'item' + $item.id"`).
|
|
171
|
-
|
|
172
|
-
## Using the range attribute
|
|
173
|
-
|
|
174
|
-
Sometimes you may only need to render a portion of an array rather than all the items.
|
|
175
|
-
|
|
176
|
-
To do this you can use the `range` variable to specify a subset of items to render. You should specify a `from` and `to` value (`from` is inclusive, and `to` is exclusive) inside the `range` variable (i.e. `range="{from: 0, to: 2}"`). You can also make the variable reactive, and use moving pointers to dynamically render your items.
|
|
177
|
-
|
|
178
|
-
This works differently to using the `show` directive on the items, as the items will be destroyed once they are outside the range, and created again when they fall back in it.
|
|
179
|
-
|
|
180
|
-
```js
|
|
181
|
-
export default Blits.Component('ForLoop', {
|
|
182
|
-
template: `
|
|
183
|
-
<Element>
|
|
184
|
-
<Element :for="(item, index) in $items" :range="{from: $selected - 1, to: $selected + 2}" w="100" h="100" color="lime" :x="$index * 150" />
|
|
185
|
-
</Element>
|
|
186
|
-
`,
|
|
187
|
-
state() {
|
|
188
|
-
return {
|
|
189
|
-
selected: 0,
|
|
190
|
-
items: ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6', 'Item 7']
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
input: {
|
|
194
|
-
left() {
|
|
195
|
-
this.selected = Math.max(0, this.selected - 1)
|
|
196
|
-
},
|
|
197
|
-
right() {
|
|
198
|
-
this.selected = Math.min(this.items.length, this.selected + 1)
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
})
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
In the example above, there are 7 items in the array, but we only render the items immediately before and after the selected item at any time.
|
package/docs/built-in/layout.md
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
# Layout
|
|
2
|
-
|
|
3
|
-
A big portion of building a pixel-perfect App is all about correctly positioning Elements and Components on the screen. In Lightning and Blits, _absolute_ positions are used. This fits the whole concept of building a TV app where the viewport dimensions are known and fixed. Absolute positioning (versus spacing Elements relative to each other) is also more performant.
|
|
4
|
-
|
|
5
|
-
Imagine a complex design with several nested layers. Relying solely on _relative_ positioning and elements automatically floating as space is available may lead to heavy and recursive calculations. Then throw some dynamically changing dimensions and animations in the mix as well, and your App may be starting to noticeably drop frames due to expensive re-calculations.
|
|
6
|
-
|
|
7
|
-
That being said, there are often cases where it becomes very cumbersome to calculate all the positions manually. Especially when dimensions are not known in advance and elements may load asynchronously.
|
|
8
|
-
|
|
9
|
-
If you come from a CSS background, you may be tempted to say: "_this is why we have Flexbox!_". And while Flexbox is great and versatile in CSS and running on a powerful device, a full flexbox implementation does come at a cost and the risk of slowing down your App, when applied extensively or incorrectly.
|
|
10
|
-
|
|
11
|
-
In order to address the core problem of "_how do I easily position a bunch of Elements and Components without writing a lot of code with `@loaded` event handlers_", Blits offers the built-in `<Layout>` component - a basic and performant solution that automatically puts your Elements in the right place.
|
|
12
|
-
|
|
13
|
-
## How to use
|
|
14
|
-
|
|
15
|
-
Since the Layout component is a built-in component, there is no need to register it separately. You can use the `<Layout>` tag anywhere in your templates, just as you would use `<Element>` and `<Text>`.
|
|
16
|
-
|
|
17
|
-
The Layout component is a wrapper component that encloses a number of children. All direct children wrapped in a `<Layout>` tag are automatically positioned in order, one next to the other.
|
|
18
|
-
|
|
19
|
-
Whenever dimensions of a child change, the positioning of the next children is automatically recalculated and reapplied.
|
|
20
|
-
|
|
21
|
-
```xml
|
|
22
|
-
<Layout>
|
|
23
|
-
<Element w="40" h="40" color="red" />
|
|
24
|
-
<Element w="80" h="40" color="blue" />
|
|
25
|
-
<Text>Hello world</Text>
|
|
26
|
-
<Element w="40" h="40" color="green" />
|
|
27
|
-
</Layout>
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### Horizontal and vertical layout
|
|
31
|
-
|
|
32
|
-
By default, the Layout component lays out its contents _horizontally_. The Layout component accepts a `direction` attribute that allows you to control the direction.
|
|
33
|
-
|
|
34
|
-
In order to align vertically, use `<Layout direction="vertical"></Layout>`. And use `<Layout direction="horizontal"></Layout>` to explicitly apply the default horizontal layout.
|
|
35
|
-
|
|
36
|
-
### Spacing between children
|
|
37
|
-
|
|
38
|
-
By default, the Layout-component places each Element directly besides (or below) the previous one. By adding the `gap`-attribute, you can control how much space will be added between each Element or Component. The `gap`-attribute accepts a number in pixels.
|
|
39
|
-
|
|
40
|
-
### Aligning items
|
|
41
|
-
|
|
42
|
-
The layout component positions its children based on the provided direction (`horizontal` or `vertical`). With the `align-items`-attribute, you can specify how to align the children on the opposite axis:
|
|
43
|
-
|
|
44
|
-
- `start` (the default value) - aligns the children at the _top_ for horizontal layouts and on the _left_ for vertical layouts
|
|
45
|
-
- `center` - align the children in the center
|
|
46
|
-
- `end` - aligns the children in the _bottom_ for horizontal layouts, and on the _right_ for vertical layouts
|
|
47
|
-
|
|
48
|
-
### Dynamic dimensions
|
|
49
|
-
|
|
50
|
-
For the Layout component to work properly, all direct children need to have dimensions (i.e., `w` and `h` attributes). The exception here being Text elements.
|
|
51
|
-
|
|
52
|
-
Due to the asynchronous nature of rendering text, the final text dimensions are not known beforehand. The width and height of Text elements are automatically set when the text has been loaded. This fires a `@loaded` event that you can tap into as described [here](../essentials/displaying_text#text-dimensions).
|
|
53
|
-
|
|
54
|
-
The Layout component also uses this event to execute its calculation and properly position the text and other elements around it.
|
|
55
|
-
|
|
56
|
-
When the children of the Layout-component have _reactive_ dimensions (i.e., `<Element :w="$mywidth" :h="$myheight" />`), the Layout component ensures that all child elements are properly repositioned whenever a dimension changes.
|
|
57
|
-
|
|
58
|
-
### Components inside a Layout
|
|
59
|
-
|
|
60
|
-
It is also possible to place Components inside of a Layout, but there is a small _gotcha_ there. By default a Component does not have any dimensions - it has a width and height of `0`, regardless of the contents of the Component. Normally, when using absolute positioning, this isn't a problem. But in the context of a Layout, each child needs to have dimensions.
|
|
61
|
-
|
|
62
|
-
If the Component has fixed dimensions, you can just add a `w` and a `h` attribute to the Component tag (i.e. `<MyButton w="100" h="40" />`). This is the most performant way to supply dimensions to a Component and should be used whenever possible.
|
|
63
|
-
|
|
64
|
-
If the Component has dynamic dimensions that are not known upfront, you can dynamically update the dimensions from inside the Component by calling the `this.$size()`-method. This method accepts an object as its argument with a `w` property for setting the _width_ and a `h` property for setting the _height_.
|
|
65
|
-
|
|
66
|
-
```js
|
|
67
|
-
export default Blits.Component('MyButton', {
|
|
68
|
-
template: ``,
|
|
69
|
-
props: ['type'],
|
|
70
|
-
hooks: {
|
|
71
|
-
ready() {
|
|
72
|
-
if(this.type === 'large') {
|
|
73
|
-
this.$size({
|
|
74
|
-
w: 200,
|
|
75
|
-
h: 80
|
|
76
|
-
})
|
|
77
|
-
} else {
|
|
78
|
-
this.$size({
|
|
79
|
-
w: 100,
|
|
80
|
-
h: 40
|
|
81
|
-
})
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
```
|
|
88
|
-
At this moment, Blits does not support automatically growing a Component's dimensions based on its contents due to the performance impact of this functionality.
|
|
89
|
-
|
|
90
|
-
### Nesting Layouts
|
|
91
|
-
|
|
92
|
-
It's also possible to nest layouts. Simply place a new `<Layout>`-tag, with it's own children in between the children of another Layout-component. The Layout component itself will grow automatically with the dimensions of its children. In other words, it's not required to specify a width (`w`) or height (`h`) on the `<Layout>` tag itself.
|
|
93
|
-
|
|
94
|
-
And of course you can nest _vertical_ Layouts inside a _horizontal_ one - and vice versa.
|
|
95
|
-
|
|
96
|
-
### Padding
|
|
97
|
-
|
|
98
|
-
By default a `<Layout />`-tag will be resized to the exact dimensions as the content it is containing. The `padding`-attribute can be used to add spacing between the content and the edges of the Layout Component.
|
|
99
|
-
|
|
100
|
-
The `padding`-attribute accepts a `number` or an `object`. When passed a number, that padding will be applied equally to all sides. With an object value, the padding can be controlled for each side individually.
|
|
101
|
-
|
|
102
|
-
Valid keys in the _padding-object_ are: `top`, `bottom`, `left`, `right`, `x` and `y`. The `x` and `y` keys can be used to define the same values for `top` and `bottom`, and `left` and `right` in one go. When a value is not specified for a side, it will default to `0`.
|
|
103
|
-
|
|
104
|
-
```xml
|
|
105
|
-
<Layout color="silver" padding="10" >
|
|
106
|
-
<Element w="40" h="40" color="red" />
|
|
107
|
-
<Element w="80" h="40" color="blue" />
|
|
108
|
-
<Element w="40" h="40" color="green" />
|
|
109
|
-
</Layout>
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
```xml
|
|
113
|
-
<Layout color="silver" padding="{x: 20, top: 30, bottom: 10}">
|
|
114
|
-
<Element w="40" h="40" color="red" />
|
|
115
|
-
<Element w="80" h="40" color="blue" />
|
|
116
|
-
<Element w="40" h="40" color="green" />
|
|
117
|
-
</Layout>
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### Transitioning layouts
|
|
121
|
-
|
|
122
|
-
The `<Layout>`-component can also take into account when dimensions of children change with a transition applied to it (i.e. `<Element :w.transition="$myWidth">`). The component will recalculate the position of its children as the transition progresses, making sure that elements are always perfectly positioned relative to one another.
|
|
123
|
-
|
|
124
|
-
### Updated event
|
|
125
|
-
|
|
126
|
-
The `<Layout>`-tag automatically updates its dimensions based on the dimensions of its children. After each update in the children, an `updated`-event is emitted on the `<Layout>`-tag. It will receive the current dimensions of the layout.
|
|
127
|
-
|
|
128
|
-
You can tap into this event by adding an `@updated`-attribute to the `<Layout />`-tag and refer to a method in your Component logic.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
```js
|
|
132
|
-
export default Blits.Component('LayoutUpdate', {
|
|
133
|
-
template: `
|
|
134
|
-
<Element>
|
|
135
|
-
<Layout @updated="$layoutUpdate">
|
|
136
|
-
<Element :w="$width" h="40" color="red" />
|
|
137
|
-
<Element :w="$width" h="40" color="blue" />
|
|
138
|
-
<Element :w="$width" h="40" color="green" />
|
|
139
|
-
</Layout>
|
|
140
|
-
</Element>
|
|
141
|
-
`,
|
|
142
|
-
methods: {
|
|
143
|
-
layoutUpdate(dimensions, el) {
|
|
144
|
-
console.log(`Layout (${el.nodeId}) dimensions updated! Width: ${dimensions.w}, Height: ${dimensions.h}`)
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
})
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
> Please be aware that the `@updated` event can fire multiple times. The size of the Layout-tag is recalculated for each change in children. Also note that the `@updated` event does not guarantee a change in dimensions. It is possible that it fires for a children update, but remains the same size.
|
|
151
|
-
|
|
152
|
-
## Performance
|
|
153
|
-
|
|
154
|
-
The Layout component is a very useful utility that will make it a lot easier to put together complex layouts. It will reduce the code required, it means less hardcoding of values and removes the need to manually wire up `@loaded` events when working with dynamic / asynchronous elements.
|
|
155
|
-
|
|
156
|
-
We have done our best to make the Component as performant as possible by deliberately keeping it simple and straightforward. However, it is important to understand that the Layout component does come at a cost. Depending on the use case these costs may be negligible, but there are cases where the Layout component might prove to be a bottleneck.
|
|
157
|
-
|
|
158
|
-
The performance costs may always be there to some degree. Whether it's the Layout component that does the complex calculations, or you do it in your custom code. So, please feel encouraged to use the `<Layout>` tag!
|
|
159
|
-
|
|
160
|
-
Some pointers to keep in mind, though:
|
|
161
|
-
|
|
162
|
-
- Every change in the dimensions of a child, triggers the Layout component to recalculate and reposition. If your child elements change frequently, the Layout component may have a performance impact.
|
|
163
|
-
|
|
164
|
-
- The Layout component support transitions, but beware that when transitioning child dimensions a recalculation happens every frame tick. If you see frame-drops in your App, you may want to see if the `<Layout>`-tag has an impact on this.
|
|
165
|
-
|
|
166
|
-
- Be mindful to not apply unnecessary deep nesting of Layout tags. Each change in a deep child, will trigger recalculations up the tree of Layout tags.
|
|
167
|
-
|
|
168
|
-
- When using the `<Layout>`-tag with a for-loop, it may be more performant to use the `$index` of the for-loop and manually position the elements yourself (i.e. `<Element :for="(item, index) in $items" :$x="$item * 200" w="150" h="150" />`). Especially if the dimensions are known beforehand and possibly are the same for each child.
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
# Component State
|
|
2
|
-
|
|
3
|
-
In Blits, a component can be as simple as a template with fixed, hardcoded values. However, for dynamic behavior and logic, you'll often want to give your components an _internal state_.
|
|
4
|
-
|
|
5
|
-
Some key concepts to keep in mind regarding Component state:
|
|
6
|
-
|
|
7
|
-
- The component state is defined within the `state` key of the Component configuration object.
|
|
8
|
-
- The `state` is expected to be a `function` (a regular function, not an ES6 arrow function), that returns an object representing the component's state.
|
|
9
|
-
- While defined on the configuration object, each component `instance` maintains its own distinct internal state.
|
|
10
|
-
- The structure of the `state` object is flexible, allowing you to define state values according to your component's requirements. These values can range from `strings`, `booleans`, `arrays`, to even nested `objects`.
|
|
11
|
-
- While you have full flexibility in structuring your state, be cautious about _excessive nesting_, as it could have a negative effect on performance.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Example of defining a component state:
|
|
15
|
-
|
|
16
|
-
```js
|
|
17
|
-
export default Blits.Component('MyComponent', {
|
|
18
|
-
// ...
|
|
19
|
-
state() {
|
|
20
|
-
return {
|
|
21
|
-
active: false,
|
|
22
|
-
items: [],
|
|
23
|
-
style: {
|
|
24
|
-
positions: {
|
|
25
|
-
x: 100,
|
|
26
|
-
},
|
|
27
|
-
dimensions: {
|
|
28
|
-
h: 100,
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
color: 'tomato'
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
})
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Accessing State in Templates
|
|
38
|
-
|
|
39
|
-
As explained in the [template section](../essentials/template_syntax.md), you can refer to state variables in a template by prefixing the state variable name with a _dollar sign_ (e.g., `$alpha`). Think of the `$`-sign as a reference to the `this`-scope of the component.
|
|
40
|
-
|
|
41
|
-
For nested objects, you can use _dot notation_ (e.g., `$style.dimensions.w`).
|
|
42
|
-
|
|
43
|
-
## Accessing State in Component Code
|
|
44
|
-
|
|
45
|
-
In your component's code, you can reference state variables directly within the `this`-scope. For instance, a state variable named `color` can be accessed (and modified) by referencing `this.color`.
|
|
46
|
-
|
|
47
|
-
It's important to note that unlike in the template, you should _not_ use the dollar sign when accessing state variables within the component's code.
|
|
48
|
-
Also, remember that there is no need to explicitly reference the `state`-key. Blits automatically maps all state variables directly on the `this`-scope, for easy access.
|
|
49
|
-
|
|
50
|
-
The example below gives a full example of defining and using a component's state:
|
|
51
|
-
|
|
52
|
-
```js
|
|
53
|
-
export default Blits.Component('MyComponent', {
|
|
54
|
-
template: `
|
|
55
|
-
<Element :show="$active">
|
|
56
|
-
<Element :x="$style.x" w="100" :h="$style.dimensions.h">
|
|
57
|
-
<Element w="20" :h="$style.dimensions.h / 2" :color="$color" />
|
|
58
|
-
</Element>
|
|
59
|
-
</Element>
|
|
60
|
-
`,
|
|
61
|
-
state() {
|
|
62
|
-
return {
|
|
63
|
-
active: false,
|
|
64
|
-
items: [],
|
|
65
|
-
style: {
|
|
66
|
-
positions: {
|
|
67
|
-
x: 100,
|
|
68
|
-
},
|
|
69
|
-
dimensions: {
|
|
70
|
-
h: 100,
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
color: 'tomato'
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
hooks: {
|
|
77
|
-
ready() {
|
|
78
|
-
this.active = true
|
|
79
|
-
this.$setInterval(() => {
|
|
80
|
-
this.style.positions.x += 10
|
|
81
|
-
})
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
input: {
|
|
85
|
-
right() {
|
|
86
|
-
this.color = '#c0ffee'
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
})
|
|
90
|
-
```
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# Computed properties
|
|
2
|
-
|
|
3
|
-
So far we've learned how to utilize a Component's [internal state](./component_state.md) and [props](./props.md) passed by a parent into a child component.
|
|
4
|
-
|
|
5
|
-
We've also seen how we can perform simple operations like `Math.max()` or `str.toUpperCase()` directly within an argument of a template on the Component's internal state or passed props.
|
|
6
|
-
However, as these operations become more complex it's more clear and more maintainable to abstract these operations into what we call _computed properties_.
|
|
7
|
-
|
|
8
|
-
Computed properties are a powerful tool for enhancing the readability of your component code. By abstracting complex or frequently used calculations from your template into computed properties, you can make your code more concise and easier to understand.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## Defining computed properties
|
|
12
|
-
|
|
13
|
-
Within the `computed`-key of the Component configuration object, you can specify an object of `functions`. Each function name you define (`offset()` for example) becomes accessible as a _computed property_.
|
|
14
|
-
|
|
15
|
-
A computed property function should always _return_ a value.
|
|
16
|
-
|
|
17
|
-
In your template, you can reference these computed properties exactly the same as you would with _state_ variables and _props_, by prefixing them with a dollar sign (e.g., `$offset`).
|
|
18
|
-
|
|
19
|
-
In the rest of your app's code, you can access these computed properties (but not modify them!) using `this.offset`. Note that similar to Component state and props, you do not need to prefix with `computed` to access the computed property.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
```js
|
|
23
|
-
export default Blits.Component('MyComponent', {
|
|
24
|
-
// ...
|
|
25
|
-
computed: {
|
|
26
|
-
offset() {
|
|
27
|
-
return this.index * 100
|
|
28
|
-
},
|
|
29
|
-
bgColor() {
|
|
30
|
-
return this.focused === true ? 'aqua' : '#ccc'
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
})
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Reactivity
|
|
37
|
-
|
|
38
|
-
Within a computed property, you can reference one or more state variables or props and _return_ a value based on calculations or logical operations.
|
|
39
|
-
|
|
40
|
-
Whenever the value of any of the referenced variables changes, the computed property will automatically recalculate.
|
|
41
|
-
|
|
42
|
-
If a computed property is referenced reactively in the template (i.e., the argument is prefixed with colons `:`), it will also trigger an automatic rerender of that portion of the template.
|
|
43
|
-
|
|
44
|
-
Computed properties should **not** have any _side effects_ (i.e. should not change the value of any state variable). Side effects can potentially lead your app into an endless loop if not handled carefully. If you want to execute certain logic upon state changes, you can consider to use a [watcher](./watchers.md) for this.
|
|
45
|
-
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Hooking into Lifecycle Events
|
|
2
|
-
|
|
3
|
-
Blits components follow a defined flow of lifecycle events. You can integrate specific logic into these events by specifying them in the `hooks` key of the Component configuration object.
|
|
4
|
-
|
|
5
|
-
For each available lifecycle event, you can define a function with the same name as the event itself. This function will then execute each time the lifecycle event is triggered for your component's instance. It's essential to use a regular function instead of an arrow function if you intend to access the `this` scope of your component instance.
|
|
6
|
-
|
|
7
|
-
## Lifecycle Events
|
|
8
|
-
|
|
9
|
-
The following lifecycle events are available in Blits components.
|
|
10
|
-
|
|
11
|
-
- **init()**: This event fires when the component is being instantiated, just before it sends its render instructions to the Lightning renderer. At this point, the elements of your template won't be available yet.
|
|
12
|
-
|
|
13
|
-
- **ready()**: The `ready` event fires when the component instance is fully initialized and rendered, indicating that it's ready for interaction.
|
|
14
|
-
|
|
15
|
-
- **focus()**: This event triggers whenever the component instance receives focus. It's important to note that this event can fire multiple times during the component's lifecycle, depending on user interactions.
|
|
16
|
-
|
|
17
|
-
- **unfocus()**: The `unfocus` event fires whenever the component instance loses focus. Similar to the `focus` event, it can occur multiple times during the component's lifecycle.
|
|
18
|
-
|
|
19
|
-
- **destroy()**: The `destroy` event fires when the component is being destroyed and removed. This event provides an opportunity to perform any custom cleanup operations before the component is removed.
|
|
20
|
-
|
|
21
|
-
```js
|
|
22
|
-
export default Blits.Component('MyComponent', {
|
|
23
|
-
// ...
|
|
24
|
-
hooks: {
|
|
25
|
-
init() {
|
|
26
|
-
// Logic to execute on init event
|
|
27
|
-
},
|
|
28
|
-
ready() {
|
|
29
|
-
// Logic to execute on ready event
|
|
30
|
-
},
|
|
31
|
-
focus() {
|
|
32
|
-
// Logic to execute on focus event
|
|
33
|
-
},
|
|
34
|
-
unfocus() {
|
|
35
|
-
// Logic to execute on unfocus event
|
|
36
|
-
},
|
|
37
|
-
destroy() {
|
|
38
|
-
// Logic to execute on destroy event
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
})
|
|
42
|
-
```
|