@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,172 +1,172 @@
1
- # Language plugin
2
-
3
- Blits comes with a built-in Language plugin, that can be used to add internationalization (i18n) to your App.
4
-
5
- The Blits Language plugin is a simple and lightweight implementation, closely modeled after the tried and tested Language plugin in the Lightning-SDK (for Lightning 2). It is designed to provide a flexible and easy way of translating texts to multiple languages, in a performant way.
6
-
7
- ## Registering the plugin
8
-
9
- While the Language plugin is provided in the core Blits package, it's an _optional_ plugin that needs to be registered before you're able to use it. As such the Language plugin is _tree-shakable_, i.e. for Apps that don't have a need for translation functionality, the Language plugin will not be part of the final App bundle.
10
-
11
- The Language plugin should be imported from Blits and registered in the App's `index.js`, as demonstrated in the example below.
12
-
13
- Make sure to place the `Blits.Plugin()` method _before_ calling the `Blits.Launch()` method
14
-
15
- ```js
16
- // index.js
17
-
18
- import Blits from '@lightningjs/blits'
19
- // import the language plugin
20
- import { language } from '@lightningjs/blits/plugins'
21
-
22
- import App from './App.js'
23
-
24
- // Use the Blits Language plugin and
25
- // optionally pass in a settings object
26
- Blits.Plugin(language, {
27
- file: '/assets/translations.json', // file with translations
28
- language: 'EN-us', // default language
29
- })
30
-
31
-
32
- Blits.Launch(App, 'app', {
33
- // launch settings
34
- })
35
- ```
36
-
37
- The Language plugin accepts an optional configuration object with 2 keys:
38
-
39
- - `file` - the JSON file with translations to be loaded at initialization
40
- - `language` - the default language to use
41
-
42
- After registration of the Language plugin, it will be available in each Blits Component as `this.$language`.
43
-
44
- ## Translations file
45
-
46
- The most common way of defining a set of translations, is to use a dedicated JSON file, modeled after
47
- the following format:
48
-
49
- ```json
50
- {
51
- "nl-NL": {
52
- "hello": "Hallo, alles goed?",
53
- "bye": "Doei!",
54
- "replacement": "Mijn naam is {first} {last}, ik ben {age} jaar"
55
- },
56
- "en-US": {
57
- "hello": "Hello, how are you doing?",
58
- "bye": "Goodbye!",
59
- "replacement": "My name is {first} {last}, I'm {age} years old"
60
- },
61
- "fr-FR": {
62
- "hello": "Bonjour, ça va?",
63
- "bye": "Au revoir!",
64
- "replacement": "Je m'appelle {first} {last}, j'ai {age} ans"
65
- },
66
- "de-DE": {
67
- "hello": "Gutentag, wie geht's?",
68
- "bye": "Tschüss!",
69
- "replacement": "Mein Name ist {first} {last}, ich bin {age} Jahre alt"
70
- }
71
- }
72
- ```
73
-
74
- Each top level key represents a language, which contains an object with translation key-value pairs. The language key
75
- doesn't require to be in a specific format, but it's recommended to use ISO-codes.
76
-
77
- When the JSON file is specified in the Plugin registration method, the language file is loaded automatically upon instantiation.
78
-
79
- In case you want to load the file with translations manually, you can use the `this.$language.load()`-method anywhere in a Component and pass in the path to the JSON file as the first argument.
80
-
81
- ## Defining translations manually
82
-
83
- As an alternative to a JSON file with translations, you can also define translations directly via an object, using the `translations()`-method.
84
-
85
- The `this.$language.translations()`-methods accepts a translations object as it's first argument, following the same format as the JSON file. The method is typically used in an `init` or `ready` hook
86
-
87
- ```js
88
- Blits.Component('MyComponent', {
89
- // ...
90
- hooks: {
91
- init() {
92
- this.$language.translations({
93
- english: {
94
- hello: "Hello",
95
- world: "World"
96
- },
97
- italian: {
98
- hello: "Ciao",
99
- world: "Mondo"
100
- }
101
- })
102
- }
103
- },
104
- })
105
- ```
106
-
107
- ## Setting the language
108
-
109
- In order to set (or change) the current language, the `this.$language.set()`-method can be used, passing in the new language code (matching one of the languages defined in the translations).
110
-
111
- ```js
112
- Blits.Component('MyComponent', {
113
- // ...
114
- input: {
115
- enter() {
116
- this.$language.set('pt-BR')
117
- }
118
- },
119
- })
120
- ```
121
-
122
- ## Getting the current language
123
-
124
- The current language can be retrieved via the `this.$language.language` property. It will return the currently set language code.
125
-
126
- ## Translating
127
-
128
- The most important functionality in the Language plugin is translating. The Language plugin exposes a `translate()` method that takes as string to translate as it's first argument. It will return the translated value in the currently set language. If either the language or the string to translate can't be found, it will return the inputed string.
129
-
130
- The translate method can be used both inside the javascript business logic, but also directly in the template.
131
-
132
- ```js
133
- Blits.Component('MyComponent', {
134
- template: `
135
- <Element>
136
- <Text :content="$$language.translate('hello')" />
137
- <Text y="100" :content="$$language.get()" />
138
- </Element>
139
- `,
140
- hooks: {
141
- ready() {
142
- console.log(this.$language.translate('world'))
143
- }
144
- },
145
- })
146
- ```
147
-
148
- Note that in the template definition 2 consecutive dollars signs are used (`$$language`). The first `$`-sign is used
149
- to refer to the Component scope, as with any other state variable or computed property refereced in the template.
150
-
151
- The second `$`-sign is needed, since the Language plugin itself is prefixed with a dollar sign on the Component scope as well (i.e `this.$language`).
152
-
153
-
154
- ### Dynamic replacements
155
-
156
- The `tranlate()`-method also supports dynamic replacements. This allows you to specify variables inside your translation string, and replace them with dynamic values passed into the `translate()`-method.
157
-
158
- Replacements are marked in the translation value using _handlebars_, like so:
159
-
160
- ```js
161
- {
162
- replacements = "My name is {first} {last}, I'm {age} years old"
163
- }
164
- ```
165
-
166
- Now when you call the `translate()`-method and pass in an object with dynamic values, those will be replaced
167
- in the final string accordingly:
168
-
169
- ```js
170
- this.$language.translate('replacements', {name: 'John', last: 'Doe', age: 18})
171
- // result: My name is John Doe, I'm 18 years old
172
- ```
1
+ # Language plugin
2
+
3
+ Blits comes with a built-in Language plugin, that can be used to add internationalization (i18n) to your App.
4
+
5
+ The Blits Language plugin is a simple and lightweight implementation, closely modeled after the tried and tested Language plugin in the Lightning-SDK (for Lightning 2). It is designed to provide a flexible and easy way of translating texts to multiple languages, in a performant way.
6
+
7
+ ## Registering the plugin
8
+
9
+ While the Language plugin is provided in the core Blits package, it's an _optional_ plugin that needs to be registered before you're able to use it. As such the Language plugin is _tree-shakable_, i.e. for Apps that don't have a need for translation functionality, the Language plugin will not be part of the final App bundle.
10
+
11
+ The Language plugin should be imported from Blits and registered in the App's `index.js`, as demonstrated in the example below.
12
+
13
+ Make sure to place the `Blits.Plugin()` method _before_ calling the `Blits.Launch()` method
14
+
15
+ ```js
16
+ // index.js
17
+
18
+ import Blits from '@lightningjs/blits'
19
+ // import the language plugin
20
+ import { language } from '@lightningjs/blits/plugins'
21
+
22
+ import App from './App.js'
23
+
24
+ // Use the Blits Language plugin and
25
+ // optionally pass in a settings object
26
+ Blits.Plugin(language, {
27
+ file: '/assets/translations.json', // file with translations
28
+ language: 'EN-us', // default language
29
+ })
30
+
31
+
32
+ Blits.Launch(App, 'app', {
33
+ // launch settings
34
+ })
35
+ ```
36
+
37
+ The Language plugin accepts an optional configuration object with 2 keys:
38
+
39
+ - `file` - the JSON file with translations to be loaded at initialization
40
+ - `language` - the default language to use
41
+
42
+ After registration of the Language plugin, it will be available in each Blits Component as `this.$language`.
43
+
44
+ ## Translations file
45
+
46
+ The most common way of defining a set of translations, is to use a dedicated JSON file, modeled after
47
+ the following format:
48
+
49
+ ```json
50
+ {
51
+ "nl-NL": {
52
+ "hello": "Hallo, alles goed?",
53
+ "bye": "Doei!",
54
+ "replacement": "Mijn naam is {first} {last}, ik ben {age} jaar"
55
+ },
56
+ "en-US": {
57
+ "hello": "Hello, how are you doing?",
58
+ "bye": "Goodbye!",
59
+ "replacement": "My name is {first} {last}, I'm {age} years old"
60
+ },
61
+ "fr-FR": {
62
+ "hello": "Bonjour, ça va?",
63
+ "bye": "Au revoir!",
64
+ "replacement": "Je m'appelle {first} {last}, j'ai {age} ans"
65
+ },
66
+ "de-DE": {
67
+ "hello": "Gutentag, wie geht's?",
68
+ "bye": "Tschüss!",
69
+ "replacement": "Mein Name ist {first} {last}, ich bin {age} Jahre alt"
70
+ }
71
+ }
72
+ ```
73
+
74
+ Each top level key represents a language, which contains an object with translation key-value pairs. The language key
75
+ doesn't require to be in a specific format, but it's recommended to use ISO-codes.
76
+
77
+ When the JSON file is specified in the Plugin registration method, the language file is loaded automatically upon instantiation.
78
+
79
+ In case you want to load the file with translations manually, you can use the `this.$language.load()`-method anywhere in a Component and pass in the path to the JSON file as the first argument.
80
+
81
+ ## Defining translations manually
82
+
83
+ As an alternative to a JSON file with translations, you can also define translations directly via an object, using the `translations()`-method.
84
+
85
+ The `this.$language.translations()`-methods accepts a translations object as it's first argument, following the same format as the JSON file. The method is typically used in an `init` or `ready` hook
86
+
87
+ ```js
88
+ Blits.Component('MyComponent', {
89
+ // ...
90
+ hooks: {
91
+ init() {
92
+ this.$language.translations({
93
+ english: {
94
+ hello: "Hello",
95
+ world: "World"
96
+ },
97
+ italian: {
98
+ hello: "Ciao",
99
+ world: "Mondo"
100
+ }
101
+ })
102
+ }
103
+ },
104
+ })
105
+ ```
106
+
107
+ ## Setting the language
108
+
109
+ In order to set (or change) the current language, the `this.$language.set()`-method can be used, passing in the new language code (matching one of the languages defined in the translations).
110
+
111
+ ```js
112
+ Blits.Component('MyComponent', {
113
+ // ...
114
+ input: {
115
+ enter() {
116
+ this.$language.set('pt-BR')
117
+ }
118
+ },
119
+ })
120
+ ```
121
+
122
+ ## Getting the current language
123
+
124
+ The current language can be retrieved via the `this.$language.language` property. It will return the currently set language code.
125
+
126
+ ## Translating
127
+
128
+ The most important functionality in the Language plugin is translating. The Language plugin exposes a `translate()` method that takes as string to translate as it's first argument. It will return the translated value in the currently set language. If either the language or the string to translate can't be found, it will return the inputed string.
129
+
130
+ The translate method can be used both inside the javascript business logic, but also directly in the template.
131
+
132
+ ```js
133
+ Blits.Component('MyComponent', {
134
+ template: `
135
+ <Element>
136
+ <Text :content="$$language.translate('hello')" />
137
+ <Text y="100" :content="$$language.get()" />
138
+ </Element>
139
+ `,
140
+ hooks: {
141
+ ready() {
142
+ console.log(this.$language.translate('world'))
143
+ }
144
+ },
145
+ })
146
+ ```
147
+
148
+ Note that in the template definition 2 consecutive dollars signs are used (`$$language`). The first `$`-sign is used
149
+ to refer to the Component scope, as with any other state variable or computed property refereced in the template.
150
+
151
+ The second `$`-sign is needed, since the Language plugin itself is prefixed with a dollar sign on the Component scope as well (i.e `this.$language`).
152
+
153
+
154
+ ### Dynamic replacements
155
+
156
+ The `tranlate()`-method also supports dynamic replacements. This allows you to specify variables inside your translation string, and replace them with dynamic values passed into the `translate()`-method.
157
+
158
+ Replacements are marked in the translation value using _handlebars_, like so:
159
+
160
+ ```js
161
+ {
162
+ replacements = "My name is {first} {last}, I'm {age} years old"
163
+ }
164
+ ```
165
+
166
+ Now when you call the `translate()`-method and pass in an object with dynamic values, those will be replaced
167
+ in the final string accordingly:
168
+
169
+ ```js
170
+ this.$language.translate('replacements', {name: 'John', last: 'Doe', age: 18})
171
+ // result: My name is John Doe, I'm 18 years old
172
+ ```
@@ -1,120 +1,120 @@
1
- # Text-to-Speech / Announcer
2
-
3
- Blits comes with a built-in Text-to-Speech / Announcer functionality, to easily make your App more accessible. This is something that's often overlooked when developing an App, but having speech assistance integrated into your App is a huge deal for those users who are visually impaired.
4
-
5
- ## Integrated with the router
6
-
7
- The Announcer in Blits is directly integrated with the router functionality. This means that through simple configuration, a descriptive message can be announced, when navigating from page to page, without the need for adding extra custom code.
8
-
9
- Just add an `announce` key in the configuration of your route, that contains the message you would like to be announced when visiting that route.
10
-
11
- ```js
12
- const routes = [
13
- // ...
14
- {
15
- path: '/settings',
16
- component: Settings,
17
- announce: "Welcome to the Settings page",
18
- },
19
- // ...
20
- ]
21
- ```
22
-
23
- ## Custom announcement messages
24
-
25
- Furthermore, it's possible to speak out custom messages anywhere in your App logic, for example when a component receives focus, as a reaction to user input, or to announce error messages when a remote API call
26
- fails.
27
-
28
- Each component in Blits has a `this.$announcer.speak()` available, which accepts a `string` with the message to be announced.
29
-
30
- ```js
31
- Blits.Component('MyComponent', {
32
- // ...
33
- hooks: {
34
- focus() {
35
- this.$announcer.speak('MyComponent just got focus')
36
- }
37
- },
38
- keys: {
39
- right() {
40
- if(this.focused === this.items.length - 1) {
41
- this.$announcer.speak('End of row reached')
42
- } else {
43
- //
44
- }
45
- }
46
- }
47
- })
48
- ```
49
-
50
- ### Execute logic when done
51
-
52
- The `speak()`-function returns a promise that resolves when it's done speaking, or when it's interupted or errors out. The reason of the `speak()` method resolving is passed as an argument into the resolve function.
53
-
54
- ```js
55
- this.$announcer.speak('Hello').then((reason) => console.log('Speaking hello finished', reason))
56
- ```
57
-
58
- ### Announcement queue
59
-
60
- The `speak()`-method places the messages in an announcement queue and then starts processing that queue. That means that when the queue is empty, it will instantly announce the messages passed. If there are other messages in the queue, the messages will be spoken when all previous messages are announced.
61
-
62
- Optionally you can set the politeness of a message to `assertive` and pass it a the second argument of the `speak()`-method.
63
-
64
- ```js
65
- this.$announcer.speak('Very important message that should get priority', 'assertive')
66
- ```
67
-
68
- This will place the message at the beginning of the queue, making in the first message to be announced after the current message (if any) has finished.
69
-
70
- #### Clearing and interupting
71
-
72
- Since each message added into the queue may take a bit of time to actually be announced, it's possible that the user has navigated elsewhere in the mean time, making the queued up messages not relevant.
73
-
74
- The announcer plugin allows you to clear the entire queue by calling `this.$announcer.clear()`. Additionally if you want to interup the messages being currently spoken, the announcer plugin offers the `this.$announcer.stop()`-method.
75
-
76
- #### Canceling individual messages
77
-
78
- In some cases you may not want to clear the entire queue, but instead cancel out a single message.
79
-
80
- Imagine an App with a row of tiles, it's possible that before the title of the role is being spoken out, the user already navigates through the tiles within the row. Traditionally you'd use the focus event to speak out info about each tile (i.e. adding tot the queue). You don't want all previously focused tiles to still be announced, but would still want the category of the row to be announced, making clearing the queue not required.
81
-
82
- The `speak()`-method return a Promise that also contains a `cancel()` function. When called, it will cancel that specific message and remove it from the queue before it can be spoken out.
83
-
84
- Additionally if you want to _interrupt_ a specific messages as it's being spoken out as well and go straight to the next message in the queue (i.e. the newly focused item, for example). You can use the `stop()` message that is returned on the Promise returned by the `speak()`-method.
85
-
86
- ```js
87
- Blits.Component('MyTile', {
88
- //
89
- props: ['title'],
90
- state() {
91
- return {
92
- message: null
93
- }
94
- },
95
- hooks: {
96
- focus() {
97
- // add message to the announcement queue
98
- this.message = this.$announcer.speak(`This is tile ${this.title}`)
99
- },
100
- unfocus() {
101
- // when unfocused interrupt the message if it's already being spoken out
102
- this.message.stop()
103
- // and cancel the message to remove it from the queue
104
- this.message.cancel()
105
- }
106
- }
107
- })
108
- ```
109
-
110
- ## Enabling / disabling the announcer
111
-
112
- By default the announcer is disabled. This means that whenever you call `this.$announcer.speak()` there will actually not be anything spoken out via the Text To Speech engine.
113
-
114
- In order to enable utterances being spoken out, you can set the Blits launch setting `announcer` to `true` in the index.js.
115
-
116
- Alternatively the announcer can be enabled or disabled run time by using one of the following methods on the Announcer pluging:
117
-
118
- - `this.$announcer.enable()` - activates the announcer
119
- - `this.$announcer.disable()` - deactivates the announcer
1
+ # Text-to-Speech / Announcer
2
+
3
+ Blits comes with a built-in Text-to-Speech / Announcer functionality, to easily make your App more accessible. This is something that's often overlooked when developing an App, but having speech assistance integrated into your App is a huge deal for those users who are visually impaired.
4
+
5
+ ## Integrated with the router
6
+
7
+ The Announcer in Blits is directly integrated with the router functionality. This means that through simple configuration, a descriptive message can be announced, when navigating from page to page, without the need for adding extra custom code.
8
+
9
+ Just add an `announce` key in the configuration of your route, that contains the message you would like to be announced when visiting that route.
10
+
11
+ ```js
12
+ const routes = [
13
+ // ...
14
+ {
15
+ path: '/settings',
16
+ component: Settings,
17
+ announce: "Welcome to the Settings page",
18
+ },
19
+ // ...
20
+ ]
21
+ ```
22
+
23
+ ## Custom announcement messages
24
+
25
+ Furthermore, it's possible to speak out custom messages anywhere in your App logic, for example when a component receives focus, as a reaction to user input, or to announce error messages when a remote API call
26
+ fails.
27
+
28
+ Each component in Blits has a `this.$announcer.speak()` available, which accepts a `string` with the message to be announced.
29
+
30
+ ```js
31
+ Blits.Component('MyComponent', {
32
+ // ...
33
+ hooks: {
34
+ focus() {
35
+ this.$announcer.speak('MyComponent just got focus')
36
+ }
37
+ },
38
+ keys: {
39
+ right() {
40
+ if(this.focused === this.items.length - 1) {
41
+ this.$announcer.speak('End of row reached')
42
+ } else {
43
+ //
44
+ }
45
+ }
46
+ }
47
+ })
48
+ ```
49
+
50
+ ### Execute logic when done
51
+
52
+ The `speak()`-function returns a promise that resolves when it's done speaking, or when it's interupted or errors out. The reason of the `speak()` method resolving is passed as an argument into the resolve function.
53
+
54
+ ```js
55
+ this.$announcer.speak('Hello').then((reason) => console.log('Speaking hello finished', reason))
56
+ ```
57
+
58
+ ### Announcement queue
59
+
60
+ The `speak()`-method places the messages in an announcement queue and then starts processing that queue. That means that when the queue is empty, it will instantly announce the messages passed. If there are other messages in the queue, the messages will be spoken when all previous messages are announced.
61
+
62
+ Optionally you can set the politeness of a message to `assertive` and pass it a the second argument of the `speak()`-method.
63
+
64
+ ```js
65
+ this.$announcer.speak('Very important message that should get priority', 'assertive')
66
+ ```
67
+
68
+ This will place the message at the beginning of the queue, making in the first message to be announced after the current message (if any) has finished.
69
+
70
+ #### Clearing and interupting
71
+
72
+ Since each message added into the queue may take a bit of time to actually be announced, it's possible that the user has navigated elsewhere in the mean time, making the queued up messages not relevant.
73
+
74
+ The announcer plugin allows you to clear the entire queue by calling `this.$announcer.clear()`. Additionally if you want to interup the messages being currently spoken, the announcer plugin offers the `this.$announcer.stop()`-method.
75
+
76
+ #### Canceling individual messages
77
+
78
+ In some cases you may not want to clear the entire queue, but instead cancel out a single message.
79
+
80
+ Imagine an App with a row of tiles, it's possible that before the title of the role is being spoken out, the user already navigates through the tiles within the row. Traditionally you'd use the focus event to speak out info about each tile (i.e. adding tot the queue). You don't want all previously focused tiles to still be announced, but would still want the category of the row to be announced, making clearing the queue not required.
81
+
82
+ The `speak()`-method return a Promise that also contains a `cancel()` function. When called, it will cancel that specific message and remove it from the queue before it can be spoken out.
83
+
84
+ Additionally if you want to _interrupt_ a specific messages as it's being spoken out as well and go straight to the next message in the queue (i.e. the newly focused item, for example). You can use the `stop()` message that is returned on the Promise returned by the `speak()`-method.
85
+
86
+ ```js
87
+ Blits.Component('MyTile', {
88
+ //
89
+ props: ['title'],
90
+ state() {
91
+ return {
92
+ message: null
93
+ }
94
+ },
95
+ hooks: {
96
+ focus() {
97
+ // add message to the announcement queue
98
+ this.message = this.$announcer.speak(`This is tile ${this.title}`)
99
+ },
100
+ unfocus() {
101
+ // when unfocused interrupt the message if it's already being spoken out
102
+ this.message.stop()
103
+ // and cancel the message to remove it from the queue
104
+ this.message.cancel()
105
+ }
106
+ }
107
+ })
108
+ ```
109
+
110
+ ## Enabling / disabling the announcer
111
+
112
+ By default the announcer is disabled. This means that whenever you call `this.$announcer.speak()` there will actually not be anything spoken out via the Text To Speech engine.
113
+
114
+ In order to enable utterances being spoken out, you can set the Blits launch setting `announcer` to `true` in the index.js.
115
+
116
+ Alternatively the announcer can be enabled or disabled run time by using one of the following methods on the Announcer pluging:
117
+
118
+ - `this.$announcer.enable()` - activates the announcer
119
+ - `this.$announcer.disable()` - deactivates the announcer
120
120
  - `this.$announcer.disable(true/false)` - turns the announcer or on off