@lightningjs/blits 1.30.1 → 1.30.2

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.
Files changed (149) hide show
  1. package/.editorconfig +7 -7
  2. package/.eslintignore +1 -1
  3. package/.eslintrc.cjs +65 -65
  4. package/.github/workflows/comment-lint-results.yml +124 -124
  5. package/.github/workflows/comment-test-results.yml +108 -108
  6. package/.github/workflows/deploy-docs.yml +27 -27
  7. package/.github/workflows/run-blits-tests.yml +141 -141
  8. package/.github/workflows/run-lint.yml +127 -127
  9. package/.husky/pre-commit +1 -1
  10. package/.vscode/extensions.json +7 -7
  11. package/.vscode/settings.json +9 -9
  12. package/CHANGELOG.md +1019 -1012
  13. package/COPYING +1 -0
  14. package/LICENSE +202 -202
  15. package/NOTICE +12 -12
  16. package/README.md +33 -33
  17. package/bin/index.js +8 -8
  18. package/blits.d.ts +6 -6
  19. package/docs/README.md +19 -19
  20. package/docs/_sidebar.md +37 -37
  21. package/docs/built-in/directives.md +50 -50
  22. package/docs/built-in/for-loop.md +203 -203
  23. package/docs/built-in/layout.md +168 -168
  24. package/docs/components/component_state.md +90 -90
  25. package/docs/components/computed_properties.md +45 -45
  26. package/docs/components/lifecycle_events.md +42 -42
  27. package/docs/components/methods.md +45 -45
  28. package/docs/components/props.md +56 -56
  29. package/docs/components/user_input.md +186 -186
  30. package/docs/components/utility_methods.md +320 -320
  31. package/docs/components/watchers.md +34 -34
  32. package/docs/essentials/application_root.md +19 -19
  33. package/docs/essentials/components.md +68 -68
  34. package/docs/essentials/displaying_images.md +67 -67
  35. package/docs/essentials/displaying_text.md +135 -135
  36. package/docs/essentials/element_attributes.md +195 -195
  37. package/docs/essentials/settings.md +117 -117
  38. package/docs/essentials/template_syntax.md +83 -83
  39. package/docs/getting_started/file_structure.md +58 -58
  40. package/docs/getting_started/getting_started.md +45 -45
  41. package/docs/getting_started/intro.md +20 -20
  42. package/docs/index.html +47 -47
  43. package/docs/performance/lazy-loading.md +161 -161
  44. package/docs/plugins/global_app_state.md +98 -98
  45. package/docs/plugins/language.md +172 -172
  46. package/docs/plugins/text-to-speech-announcer.md +119 -119
  47. package/docs/plugins/theme.md +176 -176
  48. package/docs/router/basics.md +175 -175
  49. package/docs/router/hooks.md +70 -70
  50. package/docs/router/transitions.md +146 -146
  51. package/docs/sidebar.json +171 -171
  52. package/docs/transitions_animations/transitions.md +150 -150
  53. package/index.d.ts +1099 -1099
  54. package/index.js +28 -28
  55. package/jsconfig.json +12 -12
  56. package/package.json +56 -56
  57. package/public/assets/fps_sprite.base64.js +1 -1
  58. package/scripts/postpublish.js +59 -59
  59. package/scripts/prepublishOnly.js +84 -84
  60. package/scripts/prepush.js +78 -78
  61. package/src/announcer/announcer.js +162 -162
  62. package/src/announcer/speechSynthesis.js +107 -107
  63. package/src/application.js +100 -100
  64. package/src/component/base/announcer.js +27 -27
  65. package/src/component/base/events.js +69 -69
  66. package/src/component/base/index.js +33 -33
  67. package/src/component/base/methods.js +244 -244
  68. package/src/component/base/router.js +41 -41
  69. package/src/component/base/timeouts_intervals.js +99 -99
  70. package/src/component/base/utils.js +72 -72
  71. package/src/component/setup/computed.js +48 -48
  72. package/src/component/setup/index.js +62 -62
  73. package/src/component/setup/input.js +30 -30
  74. package/src/component/setup/methods.js +37 -37
  75. package/src/component/setup/props.js +62 -62
  76. package/src/component/setup/props.test.js +238 -238
  77. package/src/component/setup/routes.js +42 -42
  78. package/src/component/setup/state.js +59 -59
  79. package/src/component/setup/watch.js +35 -35
  80. package/src/component.js +437 -437
  81. package/src/component.test.js +388 -388
  82. package/src/components/Circle.js +73 -73
  83. package/src/components/Circle.orig.js +31 -31
  84. package/src/components/FPScounter.js +1510 -1510
  85. package/src/components/FPScounter.orig.js +121 -121
  86. package/src/components/RouterView.js +81 -81
  87. package/src/components/RouterView.orig.js +54 -54
  88. package/src/components/Sprite.js +94 -94
  89. package/src/components/Sprite.orig.js +58 -58
  90. package/src/components/index.js +28 -28
  91. package/src/components/index.orig.js +28 -28
  92. package/src/constants.js +21 -21
  93. package/src/engine.js +1 -1
  94. package/src/engines/L3/element.js +744 -744
  95. package/src/engines/L3/element.test.js +579 -579
  96. package/src/engines/L3/fontLoader.js +38 -38
  97. package/src/engines/L3/index.js +7 -7
  98. package/src/engines/L3/launch.js +123 -123
  99. package/src/engines/L3/shaderLoader.js +12 -12
  100. package/src/engines/index.js +1 -1
  101. package/src/focus.js +90 -90
  102. package/src/helpers/deepEqualArray.js +50 -50
  103. package/src/helpers/deepEqualArray.test.js +127 -127
  104. package/src/helpers/fetchJson.js +34 -34
  105. package/src/helpers/sequence.js +26 -26
  106. package/src/launch.js +123 -123
  107. package/src/lib/blitsfileconverter/blitsfileconverter.js +52 -52
  108. package/src/lib/codegenerator/generator.js +788 -788
  109. package/src/lib/codegenerator/generator.test.js +3801 -3801
  110. package/src/lib/colors/colors.js +92 -92
  111. package/src/lib/colors/colors.test.js +290 -290
  112. package/src/lib/colors/htmlColors.js +168 -168
  113. package/src/lib/componentId.js +49 -49
  114. package/src/lib/componentId.test.js +84 -84
  115. package/src/lib/eventListeners.js +123 -123
  116. package/src/lib/eventListeners.test.js +236 -236
  117. package/src/lib/hooks.js +59 -59
  118. package/src/lib/lifecycle.js +85 -85
  119. package/src/lib/log.js +117 -117
  120. package/src/lib/precompiler/precompiler.js +73 -73
  121. package/src/lib/reactivity/effect.js +93 -93
  122. package/src/lib/reactivity/effect.test.js +35 -35
  123. package/src/lib/reactivity/reactive.js +208 -208
  124. package/src/lib/reactivity/reactive.test.js +27 -27
  125. package/src/lib/reactivityguard/computedprops.js +218 -218
  126. package/src/lib/symbols.js +108 -108
  127. package/src/lib/templateparser/parser.js +386 -386
  128. package/src/lib/templateparser/parser.test.js +1411 -1411
  129. package/src/lib/utils.js +27 -27
  130. package/src/plugin.js +27 -27
  131. package/src/plugins/appstate.js +26 -26
  132. package/src/plugins/index.js +20 -20
  133. package/src/plugins/language.js +152 -152
  134. package/src/plugins/log.js +25 -25
  135. package/src/plugins/theme.js +94 -94
  136. package/src/router/router.js +514 -514
  137. package/src/router/router.test.js +473 -473
  138. package/src/router/transitions/fadeIn.js +27 -27
  139. package/src/router/transitions/fadeInOut.js +33 -33
  140. package/src/router/transitions/index.js +21 -21
  141. package/src/router/transitions/slideIn.js +28 -28
  142. package/src/router/transitions/slideInOut.js +33 -33
  143. package/src/settings.js +40 -40
  144. package/vite/blitsFileConverter.js +67 -67
  145. package/vite/index.js +28 -28
  146. package/vite/msdfGenerator.js +269 -269
  147. package/vite/preCompiler.js +42 -42
  148. package/vite/reactivityGuard.js +45 -45
  149. package/vscode/data/template-attributes.json +589 -589
@@ -1,161 +1,161 @@
1
- # Lazy Loading with the :range Parameter
2
-
3
- The for-loop in Blits comes with a [`:range` parameter](../built-in/for-loop.html#using-the-range-attribute) that allows you to render only a portion of an array rather than all the items.
4
-
5
- This `:range` parameter can also be used to easily implement an efficient form of _lazy loading_. Lazy loading is a crucial concept for performance in TV applications where rails can contain hundreds of items, but only a small subset is visible at any time.
6
-
7
- ## Basic range implementation
8
-
9
- For the basic syntax of the `:range` attribute, we typically set dynamic `from` and `to` values, which define the subset of items to display.
10
-
11
- ```js
12
- <Tile :for="(item, index) in $items" :range="{from: $from, to: $to}" />
13
- ```
14
-
15
- A full example of a Rail component with a range would look something like this:
16
-
17
- ```js
18
- export default Blits.Component('RangedRail', {
19
- template: `
20
- <Element :x.transition="0 - $focused * 300">
21
- <Tile
22
- :for="(item, index) in $items"
23
- :range="{from: $range, to: $range + 7}"
24
- :key="$item.id"
25
- :focused="$focused"
26
- w="300"
27
- h="200"
28
- :x="$index * 320"
29
- />
30
- </Element>
31
- `,
32
- state() {
33
- return {
34
- range: 0,
35
- focused: 0,
36
- items: [] // Array of 100+ items
37
- }
38
- },
39
- input: {
40
- right() {
41
- this.focus = Math.min(this.focus + 1, items.length)
42
- this.range++
43
- },
44
- left() {
45
- this.focus = Math.max(this.focus - 1, 0)
46
- this.range--
47
- }
48
- }
49
- })
50
- ```
51
-
52
- Benefits of this approach are:
53
-
54
- - **Selective Rendering**: Only items within the specified range are actually created as elements
55
- - **Performance Optimization**: Reduces memory usage and improves rendering performance
56
- - **Dynamic Range Updates**: The range can be computed based on user interaction and scroll position
57
-
58
- A downside of this approach is that, as we scroll we are also **destroying** components that are out of range. And we may need those
59
- same items when we scroll back (and thus recreate them). On top of that, destroying Components and Elements also comes at a cost.
60
-
61
- ## Lazy loading with the range attribute
62
-
63
- We can solve the problem of destroying Components that we may want to use again by slightly changing the logic of the Rail component.
64
-
65
- 1) We set `from: 0`, to ensure we always start from the first item (and _keep_ the first items)
66
- 2) We use `to: $range + 7` to render up to the current position plus a lookahead buffer
67
- 3) The `$range` value tracks how far the user has navigated through the rail, but it doesn't decrement when navigating back
68
-
69
- With these changes a full example of a LazyRail component would look something like this:
70
-
71
- ```js
72
- export default Blits.Component('LazyRail', {
73
- template: `
74
- <Element :x.transition="0 - $focused * 300">
75
- <Tile
76
- :for="(item, index) in $items"
77
- :range="{from: 0, to: $range + 7}"
78
- :key="$item.id"
79
- w="300"
80
- h="200"
81
- :x="$index * 320"
82
- />
83
- </Element>
84
- `,
85
- state() {
86
- return {
87
- range: 0,
88
- items: [] // Array of 100+ items
89
- }
90
- },
91
- input: {
92
- right() {
93
- this.focus = Math.min(this.focus + 1, items.length)
94
- // push the range update to the next tick to spread out the work
95
- // and ease the CPU a bit
96
- this.$setTimeout(() => this.range = this.focus)
97
-
98
- },
99
- left() {
100
- this.focus = Math.max(this.focus - 1, 0)
101
- // we don't decrement the range when scrolling back to keep components alive
102
- // this.range--
103
- }
104
- }
105
- })
106
- ```
107
-
108
- ## Performance Benefits
109
-
110
- Properly applying the range attribute provides **Memory Efficiency**:
111
-
112
- - Instead of creating 100+ elements, only ~8-15 are active
113
- - Reduces GPU memory usage on constrained TV hardware
114
- - Lower overall memory footprint
115
-
116
- It also is beneficial for **Faster Rendering**
117
-
118
- - Initial page load only renders visible items
119
- - Scroll performance improves as fewer elements need updates
120
- - Reduced layout calculations
121
-
122
-
123
- It **optimizes bandwidth**
124
-
125
- - Images and assets only load for rendered items
126
- - Reduces network requests on page load
127
- - Progressive content loading
128
-
129
-
130
- ### Alpha Transitions
131
-
132
- For a smoother experience you consider applying an alpha transition, that fades out items at the end of the rang.e
133
-
134
- ```js
135
- :alpha.transition="$index <= $range ? 1 : ($index <= $range + 3 ? 0.8 : 0.6)"
136
- ```
137
-
138
- This creates a dimming effect for previously viewed items while maintaining full opacity for the current and upcoming items.
139
-
140
- ## Best Practices
141
-
142
- ### Buffer Size
143
-
144
- Use a buffer of 5-10 items ahead of current position:
145
-
146
- ```js
147
- // Conservative buffer for low-end devices
148
- :range="{from: $currentIndex - 1, to: $currentIndex + 6}"
149
-
150
- // Larger buffer for smoother experience
151
- :range="{from: $currentIndex - 2, to: $currentIndex + 10}"
152
- ```
153
-
154
- ## Performance Impact
155
-
156
- On typical TV hardware:
157
-
158
- - **Memory Usage**: 70-80% reduction compared to full rendering
159
- - **Initial Load Time**: 3-5x faster page initialization
160
- - **Scroll Performance**: Consistent fps maintained vs potential frame drops
161
- - **Network Requests**: Reduced by 80-90% on initial load
1
+ # Lazy Loading with the :range Parameter
2
+
3
+ The for-loop in Blits comes with a [`:range` parameter](../built-in/for-loop.html#using-the-range-attribute) that allows you to render only a portion of an array rather than all the items.
4
+
5
+ This `:range` parameter can also be used to easily implement an efficient form of _lazy loading_. Lazy loading is a crucial concept for performance in TV applications where rails can contain hundreds of items, but only a small subset is visible at any time.
6
+
7
+ ## Basic range implementation
8
+
9
+ For the basic syntax of the `:range` attribute, we typically set dynamic `from` and `to` values, which define the subset of items to display.
10
+
11
+ ```js
12
+ <Tile :for="(item, index) in $items" :range="{from: $from, to: $to}" />
13
+ ```
14
+
15
+ A full example of a Rail component with a range would look something like this:
16
+
17
+ ```js
18
+ export default Blits.Component('RangedRail', {
19
+ template: `
20
+ <Element :x.transition="0 - $focused * 300">
21
+ <Tile
22
+ :for="(item, index) in $items"
23
+ :range="{from: $range, to: $range + 7}"
24
+ :key="$item.id"
25
+ :focused="$focused"
26
+ w="300"
27
+ h="200"
28
+ :x="$index * 320"
29
+ />
30
+ </Element>
31
+ `,
32
+ state() {
33
+ return {
34
+ range: 0,
35
+ focused: 0,
36
+ items: [] // Array of 100+ items
37
+ }
38
+ },
39
+ input: {
40
+ right() {
41
+ this.focus = Math.min(this.focus + 1, items.length)
42
+ this.range++
43
+ },
44
+ left() {
45
+ this.focus = Math.max(this.focus - 1, 0)
46
+ this.range--
47
+ }
48
+ }
49
+ })
50
+ ```
51
+
52
+ Benefits of this approach are:
53
+
54
+ - **Selective Rendering**: Only items within the specified range are actually created as elements
55
+ - **Performance Optimization**: Reduces memory usage and improves rendering performance
56
+ - **Dynamic Range Updates**: The range can be computed based on user interaction and scroll position
57
+
58
+ A downside of this approach is that, as we scroll we are also **destroying** components that are out of range. And we may need those
59
+ same items when we scroll back (and thus recreate them). On top of that, destroying Components and Elements also comes at a cost.
60
+
61
+ ## Lazy loading with the range attribute
62
+
63
+ We can solve the problem of destroying Components that we may want to use again by slightly changing the logic of the Rail component.
64
+
65
+ 1) We set `from: 0`, to ensure we always start from the first item (and _keep_ the first items)
66
+ 2) We use `to: $range + 7` to render up to the current position plus a lookahead buffer
67
+ 3) The `$range` value tracks how far the user has navigated through the rail, but it doesn't decrement when navigating back
68
+
69
+ With these changes a full example of a LazyRail component would look something like this:
70
+
71
+ ```js
72
+ export default Blits.Component('LazyRail', {
73
+ template: `
74
+ <Element :x.transition="0 - $focused * 300">
75
+ <Tile
76
+ :for="(item, index) in $items"
77
+ :range="{from: 0, to: $range + 7}"
78
+ :key="$item.id"
79
+ w="300"
80
+ h="200"
81
+ :x="$index * 320"
82
+ />
83
+ </Element>
84
+ `,
85
+ state() {
86
+ return {
87
+ range: 0,
88
+ items: [] // Array of 100+ items
89
+ }
90
+ },
91
+ input: {
92
+ right() {
93
+ this.focus = Math.min(this.focus + 1, items.length)
94
+ // push the range update to the next tick to spread out the work
95
+ // and ease the CPU a bit
96
+ this.$setTimeout(() => this.range = this.focus)
97
+
98
+ },
99
+ left() {
100
+ this.focus = Math.max(this.focus - 1, 0)
101
+ // we don't decrement the range when scrolling back to keep components alive
102
+ // this.range--
103
+ }
104
+ }
105
+ })
106
+ ```
107
+
108
+ ## Performance Benefits
109
+
110
+ Properly applying the range attribute provides **Memory Efficiency**:
111
+
112
+ - Instead of creating 100+ elements, only ~8-15 are active
113
+ - Reduces GPU memory usage on constrained TV hardware
114
+ - Lower overall memory footprint
115
+
116
+ It also is beneficial for **Faster Rendering**
117
+
118
+ - Initial page load only renders visible items
119
+ - Scroll performance improves as fewer elements need updates
120
+ - Reduced layout calculations
121
+
122
+
123
+ It **optimizes bandwidth**
124
+
125
+ - Images and assets only load for rendered items
126
+ - Reduces network requests on page load
127
+ - Progressive content loading
128
+
129
+
130
+ ### Alpha Transitions
131
+
132
+ For a smoother experience you consider applying an alpha transition, that fades out items at the end of the rang.e
133
+
134
+ ```js
135
+ :alpha.transition="$index <= $range ? 1 : ($index <= $range + 3 ? 0.8 : 0.6)"
136
+ ```
137
+
138
+ This creates a dimming effect for previously viewed items while maintaining full opacity for the current and upcoming items.
139
+
140
+ ## Best Practices
141
+
142
+ ### Buffer Size
143
+
144
+ Use a buffer of 5-10 items ahead of current position:
145
+
146
+ ```js
147
+ // Conservative buffer for low-end devices
148
+ :range="{from: $currentIndex - 1, to: $currentIndex + 6}"
149
+
150
+ // Larger buffer for smoother experience
151
+ :range="{from: $currentIndex - 2, to: $currentIndex + 10}"
152
+ ```
153
+
154
+ ## Performance Impact
155
+
156
+ On typical TV hardware:
157
+
158
+ - **Memory Usage**: 70-80% reduction compared to full rendering
159
+ - **Initial Load Time**: 3-5x faster page initialization
160
+ - **Scroll Performance**: Consistent fps maintained vs potential frame drops
161
+ - **Network Requests**: Reduced by 80-90% on initial load
@@ -1,98 +1,98 @@
1
- # Global App State plugin
2
-
3
- Each Blits Component has its own, internal component state that is reactive and can automatically trigger updates in the template upon changes. The internal state is fully encapsulated, which ensures predictable component state and promotes a pattern of clear separation of concerns.
4
-
5
- But a Component usually doesn't live on its own, instead it's part of a bigger App. And there may arise a need for components to exchange data - intercomponent communication in other words.
6
-
7
- Blits offers the option to _emit_ and _listen_ to events, as explained in the section on Blits [utility methods](../components/utility_methods.md). For simple use cases, this is a convenient method to pass data along. But when used extensively, it may be easy to lose track of data flows.
8
-
9
- For more advanced cases, Blits offers an optional Global App State plugin that will act as a global state store that all components have direct access to. It's a simple implementation, focused on providing a _performant_ and _easy to use_ solution for global state. It's not a full flux / redux style state management solution, as we know from experience that these solutions (while very useful and cool), may lead to performance issues on low-end devices.
10
-
11
- ## Registering the plugin
12
-
13
- The Global App state plugin is provided in the core Blits package, but as it's an _optional_ plugin it first needs to be registered.
14
-
15
- The plugin can be imported from Blits and registered in the App's `index.js`, as demonstrated in the example below.
16
-
17
- Make sure to place the `Blits.Plugin()` method _before_ calling the `Blits.Launch()` method.
18
-
19
- ```js
20
- // index.js
21
-
22
- import Blits from '@lightningjs/blits'
23
- // import the app state plugin
24
- import { appState } from '@lightningjs/blits/plugins'
25
-
26
- import App from './App.js'
27
-
28
- // Use the Blits App State plugin
29
- Blits.Plugin(appState, {
30
- loggedIn: false,
31
- user: {
32
- id: null,
33
- name: '',
34
- lastname: ''
35
- },
36
- languages: ['en', 'nl', 'pt', 'es'],
37
- })
38
-
39
-
40
- Blits.Launch(App, 'app', {
41
- // launch settings
42
- })
43
- ```
44
-
45
- ### State object
46
-
47
- When registering the Global App State plugin, you pass it a state object as the second argument. This is a plain object literal that will be converted into a _reactive_ object, and is used to keep track of the global state variables.
48
-
49
- The newly created Global App state works exactly the same as an internal Component state. You can read values and you can directly change values. And when you do change a value, it automatically triggers reactive updates. Either via reactive attributes in the template, or in the form of watchers / computed values in the Component logic.
50
-
51
- ### Using global app state in a Component
52
-
53
- Any variable in the Global App state can be used directly in the template, much like a local Component state. Changing values in the global app state also works exactly the same as updating the internal component state.
54
-
55
- ```js
56
- Blits.Component('MyComponent', {
57
- template: `
58
- <Element>
59
- <Text :content="$$appState.loggedIn ? $$appState.user.name : 'Not logged in'" />
60
- </Element>
61
- `,
62
- input: {
63
- enter() {
64
- this.$appState.user.name = 'John'
65
- this.$appState.loggedIn = true
66
- }
67
- },
68
- })
69
- ```
70
-
71
- Note that in the template definition, 2 consecutive dollars signs are used (`$$appState`). The first `$`-sign is used
72
- to refer to the Component scope, as with any other state variable or computed property referenced in the template.
73
-
74
- The second `$`-sign is needed, since the appState plugin itself is prefixed with a dollar sign, to prevent accidental naming collisions.
75
-
76
- In order to read or update variables on the global app state inside the component logic, you can access the entire state via `this.$appState`.
77
-
78
- ### Watching global state
79
-
80
- Similar to component state, you can watch for changes in the global state as well. You can refer to global state variables using _dot-notation_ in the watcher function name, and _prefixing_ it with `$appState`. This means that you need to define your watcher as a `String`, matching one of the examples below, depending on your style preference.
81
-
82
- ```js
83
- Blits.Component('MyComponent', {
84
- template: `
85
- <Element>
86
- <Text :content="$$appState.loggedIn ? $$appState.user.name : 'Not logged in'" />
87
- </Element>
88
- `,
89
- watch: {
90
- '$appState.fooBar'(v, old) {
91
- console.log(`$appState.fooBar changed from ${old} to ${v}`)
92
- },
93
- '$appState.my.nested.data': function(v, old) {
94
- console.log(`My nested App state data changed!`)
95
- }
96
- },
97
- })
98
- ```
1
+ # Global App State plugin
2
+
3
+ Each Blits Component has its own, internal component state that is reactive and can automatically trigger updates in the template upon changes. The internal state is fully encapsulated, which ensures predictable component state and promotes a pattern of clear separation of concerns.
4
+
5
+ But a Component usually doesn't live on its own, instead it's part of a bigger App. And there may arise a need for components to exchange data - intercomponent communication in other words.
6
+
7
+ Blits offers the option to _emit_ and _listen_ to events, as explained in the section on Blits [utility methods](../components/utility_methods.md). For simple use cases, this is a convenient method to pass data along. But when used extensively, it may be easy to lose track of data flows.
8
+
9
+ For more advanced cases, Blits offers an optional Global App State plugin that will act as a global state store that all components have direct access to. It's a simple implementation, focused on providing a _performant_ and _easy to use_ solution for global state. It's not a full flux / redux style state management solution, as we know from experience that these solutions (while very useful and cool), may lead to performance issues on low-end devices.
10
+
11
+ ## Registering the plugin
12
+
13
+ The Global App state plugin is provided in the core Blits package, but as it's an _optional_ plugin it first needs to be registered.
14
+
15
+ The plugin can be imported from Blits and registered in the App's `index.js`, as demonstrated in the example below.
16
+
17
+ Make sure to place the `Blits.Plugin()` method _before_ calling the `Blits.Launch()` method.
18
+
19
+ ```js
20
+ // index.js
21
+
22
+ import Blits from '@lightningjs/blits'
23
+ // import the app state plugin
24
+ import { appState } from '@lightningjs/blits/plugins'
25
+
26
+ import App from './App.js'
27
+
28
+ // Use the Blits App State plugin
29
+ Blits.Plugin(appState, {
30
+ loggedIn: false,
31
+ user: {
32
+ id: null,
33
+ name: '',
34
+ lastname: ''
35
+ },
36
+ languages: ['en', 'nl', 'pt', 'es'],
37
+ })
38
+
39
+
40
+ Blits.Launch(App, 'app', {
41
+ // launch settings
42
+ })
43
+ ```
44
+
45
+ ### State object
46
+
47
+ When registering the Global App State plugin, you pass it a state object as the second argument. This is a plain object literal that will be converted into a _reactive_ object, and is used to keep track of the global state variables.
48
+
49
+ The newly created Global App state works exactly the same as an internal Component state. You can read values and you can directly change values. And when you do change a value, it automatically triggers reactive updates. Either via reactive attributes in the template, or in the form of watchers / computed values in the Component logic.
50
+
51
+ ### Using global app state in a Component
52
+
53
+ Any variable in the Global App state can be used directly in the template, much like a local Component state. Changing values in the global app state also works exactly the same as updating the internal component state.
54
+
55
+ ```js
56
+ Blits.Component('MyComponent', {
57
+ template: `
58
+ <Element>
59
+ <Text :content="$$appState.loggedIn ? $$appState.user.name : 'Not logged in'" />
60
+ </Element>
61
+ `,
62
+ input: {
63
+ enter() {
64
+ this.$appState.user.name = 'John'
65
+ this.$appState.loggedIn = true
66
+ }
67
+ },
68
+ })
69
+ ```
70
+
71
+ Note that in the template definition, 2 consecutive dollars signs are used (`$$appState`). The first `$`-sign is used
72
+ to refer to the Component scope, as with any other state variable or computed property referenced in the template.
73
+
74
+ The second `$`-sign is needed, since the appState plugin itself is prefixed with a dollar sign, to prevent accidental naming collisions.
75
+
76
+ In order to read or update variables on the global app state inside the component logic, you can access the entire state via `this.$appState`.
77
+
78
+ ### Watching global state
79
+
80
+ Similar to component state, you can watch for changes in the global state as well. You can refer to global state variables using _dot-notation_ in the watcher function name, and _prefixing_ it with `$appState`. This means that you need to define your watcher as a `String`, matching one of the examples below, depending on your style preference.
81
+
82
+ ```js
83
+ Blits.Component('MyComponent', {
84
+ template: `
85
+ <Element>
86
+ <Text :content="$$appState.loggedIn ? $$appState.user.name : 'Not logged in'" />
87
+ </Element>
88
+ `,
89
+ watch: {
90
+ '$appState.fooBar'(v, old) {
91
+ console.log(`$appState.fooBar changed from ${old} to ${v}`)
92
+ },
93
+ '$appState.my.nested.data': function(v, old) {
94
+ console.log(`My nested App state data changed!`)
95
+ }
96
+ },
97
+ })
98
+ ```