@lightningjs/blits 1.1.0 → 1.3.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/NOTICE +9 -0
  3. package/docs/_sidebar.md +1 -0
  4. package/docs/built-in/directives.md +4 -6
  5. package/docs/built-in/for-loop.md +6 -8
  6. package/docs/components/component_state.md +3 -5
  7. package/docs/components/computed_properties.md +3 -5
  8. package/docs/components/lifecycle_events.md +2 -4
  9. package/docs/components/methods.md +1 -3
  10. package/docs/components/props.md +3 -5
  11. package/docs/components/user_input.md +6 -8
  12. package/docs/components/utilities.md +1 -2
  13. package/docs/components/watchers.md +2 -4
  14. package/docs/essentials/application_root.md +1 -3
  15. package/docs/essentials/components.md +2 -4
  16. package/docs/essentials/displaying_images.md +4 -6
  17. package/docs/essentials/displaying_text.md +4 -6
  18. package/docs/essentials/element_attributes.md +10 -12
  19. package/docs/essentials/template_syntax.md +5 -7
  20. package/docs/getting_started/file_structure.md +9 -11
  21. package/docs/getting_started/getting_started.md +5 -7
  22. package/docs/plugins/language.md +172 -0
  23. package/docs/plugins/text-to-speech-announcer.md +2 -4
  24. package/docs/sidebar.json +4 -0
  25. package/docs/transitions_animations/transitions.md +5 -7
  26. package/index.d.ts +2 -0
  27. package/index.js +2 -0
  28. package/package.json +3 -2
  29. package/src/component/base/index.js +4 -1
  30. package/src/component/base/log.js +1 -1
  31. package/src/component/base/methods.js +1 -2
  32. package/src/component/setup/state.js +9 -13
  33. package/src/component.d.ts +6 -0
  34. package/src/component.js +30 -10
  35. package/src/components/FPScounter.js +56 -12
  36. package/src/components/index.js +0 -2
  37. package/src/components/index.orig.js +0 -2
  38. package/src/engines/L3/element.js +56 -66
  39. package/src/helpers/fetchJson.js +34 -0
  40. package/src/lib/codegenerator/generator.js +104 -28
  41. package/src/lib/codegenerator/generator.test.js +184 -0
  42. package/src/lib/colors/colors.js +6 -7
  43. package/src/lib/reactivity/reactive.js +3 -5
  44. package/src/lib/symbols.js +1 -0
  45. package/src/lib/templateparser/parser.js +1 -1
  46. package/src/plugin.d.ts +71 -0
  47. package/src/plugin.js +23 -0
  48. package/src/{components/Image.orig.js → plugins/index.js} +2 -17
  49. package/src/plugins/language.js +122 -0
  50. package/src/components/Image.js +0 -52
@@ -0,0 +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 availabe 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 manualy
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.get()` method. 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,10 +1,8 @@
1
- # Blits - Lightning 3 App Development Framework
2
-
3
- ## Text-to-Speech / Announcer
1
+ # Text-to-Speech / Announcer
4
2
 
5
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.
6
4
 
7
- ### Integrated with the router
5
+ ## Integrated with the router
8
6
 
9
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.
10
8
 
package/docs/sidebar.json CHANGED
@@ -106,6 +106,10 @@
106
106
  {
107
107
  "text": "Text-to-Speech / Announcer",
108
108
  "link": "/plugins/text-to-speech-announcer"
109
+ },
110
+ {
111
+ "text": "Language",
112
+ "link": "/plugins/language"
109
113
  }
110
114
  ]
111
115
  }
@@ -1,6 +1,4 @@
1
- # Blits - Lightning 3 App Development Framework
2
-
3
- ## Transitions
1
+ # Transitions
4
2
 
5
3
  So far we have explored how to create components and draw elements on the screen. But everything has
6
4
  been rather static so far.
@@ -28,7 +26,7 @@ export default Blits('Gold', {
28
26
 
29
27
  Using _transitions_ we really make our App come alive.
30
28
 
31
- ### Applying a transition
29
+ ## Applying a transition
32
30
 
33
31
  Blits offers an easy and intuitive way to apply transitions. All you need to do is add the `.transition` modifier to a reactive attribute, and now whenever you change the value referenced in the attribute, it will automatically _smooth_ into the new value.
34
32
 
@@ -55,7 +53,7 @@ If we try out the modified example above, you'll notice how much difference addi
55
53
 
56
54
  When the `.transition`-modifier is added to a reactive attribute, a default `ease-in` transition with a duration of `300ms` is applied
57
55
 
58
- ### Customizing transitions
56
+ ## Customizing transitions
59
57
 
60
58
  While the default transition will look pretty good out of the box and is great for quickly improving the look of your App, you may want to customize specific transitions.
61
59
 
@@ -86,7 +84,7 @@ Besides a reference to the `value`, you can also use dynamic values for the othe
86
84
  </Element>
87
85
  ```
88
86
 
89
- #### Available easing functions
87
+ ### Available easing functions
90
88
 
91
89
  - `ease-in`
92
90
  - `ease-out`
@@ -104,7 +102,7 @@ Besides a reference to the `value`, you can also use dynamic values for the othe
104
102
  - `ease-out-back`
105
103
  - `ease-in-out-back`
106
104
 
107
- ### Listening to transition events
105
+ ## Listening to transition events
108
106
 
109
107
  Sometimes you may want to perform an action when a transition ends or when it starts.
110
108
 
package/index.d.ts CHANGED
@@ -18,6 +18,7 @@
18
18
  import Component from './src/component.js'
19
19
  import Application from './src/application.js'
20
20
  import Launch from './src/launch.js'
21
+ import Plugin from './src/plugin.js'
21
22
 
22
23
  /**
23
24
  * Blits - The Lightning 3 App Development Framework
@@ -26,6 +27,7 @@ declare module Blits {
26
27
  export { Component }
27
28
  export { Application }
28
29
  export { Launch }
30
+ export { Plugin }
29
31
  }
30
32
 
31
33
  export default Blits
package/index.js CHANGED
@@ -18,9 +18,11 @@
18
18
  import Component from './src/component.js'
19
19
  import Application from './src/application.js'
20
20
  import Launch from './src/launch.js'
21
+ import Plugin from './src/plugin.js'
21
22
 
22
23
  export default {
23
24
  Component,
24
25
  Application,
25
26
  Launch,
27
+ Plugin,
26
28
  }
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@lightningjs/blits",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "Blits: The Lightning 3 App Development Framework",
5
5
  "bin": "bin/index.js",
6
6
  "exports": {
7
7
  ".": "./index.js",
8
8
  "./vite": "./vite/index.js",
9
9
  "./transitions": "./src/router/transitions/index.js",
10
- "./precompiler": "./src/lib/precompiler/precompiler.js"
10
+ "./precompiler": "./src/lib/precompiler/precompiler.js",
11
+ "./plugins": "./src/plugins/index.js"
11
12
  },
12
13
  "scripts": {
13
14
  "test": "c8 npm run test:run",
@@ -22,8 +22,11 @@ import log from './log.js'
22
22
  import router from './router.js'
23
23
  import announcer from './announcer.js'
24
24
  import utils from './utils.js'
25
+ import symbols from '../../lib/symbols.js'
25
26
 
26
27
  export default Object.defineProperties(
27
- {},
28
+ {
29
+ [symbols['pluginsRegistered']]: false,
30
+ },
28
31
  { ...methods, ...scheduling, ...events, ...log, ...router, ...announcer, ...utils }
29
32
  )
@@ -21,7 +21,7 @@ export default {
21
21
  $log: {
22
22
  value: log('App'),
23
23
  writable: false,
24
- enumerable: false,
24
+ enumerable: true,
25
25
  configurable: false,
26
26
  },
27
27
  }
@@ -95,9 +95,8 @@ export default {
95
95
  },
96
96
  shader: {
97
97
  value: function (type, args) {
98
- const target = type
99
98
  return {
100
- type: target,
99
+ type: type,
101
100
  props: args,
102
101
  }
103
102
  // const shaders = renderer.driver.stage.shManager.getRegisteredEffects()
@@ -37,18 +37,14 @@ export default (component, state = () => {}) => {
37
37
  Log.error(`State ${key} already exists as a method`)
38
38
  }
39
39
  component[symbols.stateKeys].push(key)
40
- try {
41
- Object.defineProperty(component, key, {
42
- get() {
43
- return this[symbols.state] && key in this[symbols.state] && this[symbols.state][key]
44
- },
45
- set(v) {
46
- if (this[symbols.state]) this[symbols.state][key] = v
47
- },
48
- // enumerable: true,
49
- })
50
- } catch (e) {
51
- Log.error(e)
52
- }
40
+ Object.defineProperty(component, key, {
41
+ get() {
42
+ return this[symbols.state][key]
43
+ },
44
+ set(v) {
45
+ this[symbols.state][key] = v
46
+ },
47
+ // enumerable: true,
48
+ })
53
49
  })
54
50
  }
@@ -328,6 +328,12 @@ declare namespace Component {
328
328
  * Triggers a forced update on state variables.
329
329
  */
330
330
  $trigger: (key: string) => void
331
+ /**
332
+ * @deprecated
333
+ *
334
+ * Triggers a forced update on state variables.
335
+ * Deprecated: use `this.$trigger()` instead
336
+ */
331
337
  trigger: (key: string) => void
332
338
 
333
339
  /**
package/src/component.js CHANGED
@@ -34,6 +34,8 @@ import Settings from './settings.js'
34
34
  import setupComponent from './component/setup/index.js'
35
35
  import components from './components/index.js'
36
36
 
37
+ import { plugins } from './plugin.js'
38
+
37
39
  // object to store global components
38
40
  let globalComponents
39
41
 
@@ -158,16 +160,11 @@ const Component = (name = required('name'), config = required('config')) => {
158
160
 
159
161
  // setup (and execute) all the generated side effects based on the
160
162
  // reactive bindings define in the template
161
- for (let i = 0; i < config.code.effects.length; i++) {
163
+ const effects = config.code.effects
164
+ for (let i = 0; i < effects.length; i++) {
165
+ // console.log(config.code.effects[i].toString())
162
166
  effect(() => {
163
- config.code.effects[i].apply(stage, [
164
- this,
165
- this[symbols.children],
166
- config,
167
- globalComponents,
168
- rootComponent,
169
- effect,
170
- ])
167
+ effects[i](this, this[symbols.children], config, globalComponents, rootComponent, effect)
171
168
  })
172
169
  }
173
170
 
@@ -202,7 +199,30 @@ const Component = (name = required('name'), config = required('config')) => {
202
199
  }
203
200
 
204
201
  const factory = (options = {}, parentEl, parentComponent, rootComponent) => {
205
- // setup the component once, using Base as the prototype
202
+ // Register user defined plugins once on the Base object
203
+ if (Base[symbols['pluginsRegistered']] === false) {
204
+ Object.keys(plugins).forEach((pluginName) => {
205
+ const prefixedPluginName = `$${pluginName}`
206
+ if (prefixedPluginName in Base) {
207
+ Log.warn(
208
+ `"${pluginName}" (this.${prefixedPluginName}) already exists as a property or plugin on the Base Component. You may be overwriting built-in functionality. Proceed with care!`
209
+ )
210
+ }
211
+
212
+ const plugin = plugins[pluginName]
213
+
214
+ Object.defineProperty(Base, prefixedPluginName, {
215
+ // instantiate the plugin, passing in provided options
216
+ value: plugin.plugin(plugin.options),
217
+ writable: false,
218
+ enumerable: true,
219
+ configurable: false,
220
+ })
221
+ })
222
+ Base[symbols['pluginsRegistered']] = true
223
+ }
224
+
225
+ // setup the component once per component type, using Base as the prototype
206
226
  if (!base) {
207
227
  Log.debug(`Setting up ${name} component`)
208
228
  base = setupComponent(Object.create(Base), config)