@lightningjs/blits 0.5.9 → 0.6.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 CHANGED
@@ -1,6 +1,20 @@
1
1
  # Changelog
2
2
 
3
- # v0.5.8
3
+ # v0.6.0
4
+
5
+ _4 jan 2024_
6
+
7
+ - Added pre-compilation functionality to improve performance. Requires an update to the `vite.config.js` to enable. Read more details in this [blog post](https://lightningjs.io/blogs/blitsPreCompilation.html)
8
+ - Added `defaultFont` to the Launch settings
9
+
10
+ # v0.5.10
11
+
12
+ _3 jan 2024_
13
+
14
+ - Updated and improved documentation
15
+ - Added `screenResolution` and `pixelRatio` options to settings
16
+
17
+ # v0.5.9
4
18
 
5
19
  _21 dec 2023_
6
20
 
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Blits - Lightning 3 App Development Framework
4
4
 
5
- With Blits (formaly know as Bolt), the App Development Framework for Lightning 3, it becomes a breeze to build great Lightning 3 applications.
5
+ With Blits, the App Development Framework for Lightning 3, it becomes a breeze to build great Lightning 3 applications.
6
6
 
7
7
  Blits is built on top of the Lightning 3 Rendererer and aims to provide a **great developer experience**, making it fun and easy to build your apps!
8
8
 
@@ -31,6 +31,6 @@
31
31
  "vite": "^4.0.4"
32
32
  },
33
33
  "dependencies": {
34
- "@lightningjs/blits": "^0.5.9"
34
+ "@lightningjs/blits": "^0.6.0"
35
35
  }
36
36
  }
@@ -1,9 +1,9 @@
1
1
  import { defineConfig } from 'vite'
2
- import { importChunkUrl } from '@lightningjs/blits/vite'
2
+ import blitsVitePlugins from '@lightningjs/blits/vite'
3
3
 
4
4
  export default defineConfig(({ command, mode, ssrBuild }) => {
5
5
  return {
6
- plugins: [importChunkUrl()],
6
+ plugins: [...blitsVitePlugins],
7
7
  resolve: {
8
8
  mainFields: ['browser', 'module', 'jsnext:main', 'jsnext'],
9
9
  },
package/docs/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Blits - Lightning 3 App Development Framework
2
2
 
3
- With Blits (formerly know as Bolt), the App Development Framework for Lightning 3, it becomes a breeze to build great Lightning 3 applications.
3
+ With Blits, the App Development Framework for Lightning 3, it becomes a breeze to build great Lightning 3 applications.
4
4
 
5
5
  Blits is built on top of the Lightning 3 Renderer and aims to provide a **great developer experience**, making it fun and easy to build your apps!
6
6
 
@@ -12,7 +12,9 @@ The Blits framework uses a **readable** XML-style template syntax and comes with
12
12
 
13
13
  You may be wondering where the name Blits comes from?
14
14
 
15
- Firstly, it short, memorable and has a nice ring to it. The name is derived from the word "Blitz", which means Lightning in German. Additionally, "Blits" is a Dutch term (a significant portion of the Lightning Open Source teams is based in the Netherlands) used to showcase something great or simply refer to things that are cool.
15
+ Firstly, it's short, memorable and just has a nice ring to it.
16
+
17
+ "Blits" is a Dutch word (a significant portion of the Lightning Open Source teams is based in the Netherlands). It means _flashy_ and it's often used to for things that are _great_ or _cool_.
16
18
 
17
19
  Finally it's a nerdy reference to the computer term "Bit Blits" commonly used in graphics processing, for rapidly moving a block of data into memory - quite similar to what Lightning is doing 🙂
18
20
 
@@ -28,11 +30,12 @@ Finally it's a nerdy reference to the computer term "Bit Blits" commonly used in
28
30
  - [Computed properties](computed_properties.md)
29
31
  - [Watching for changes](watchers.md)
30
32
  - [Styling and positioning Elements](element_attributes.md)
33
+ - [Displaying images](displaying_images.md)
34
+
31
35
  <!---
32
36
  - More complex logic in methods
33
37
  - Transitions
34
38
  - Implementing Custom components
35
39
  - Handling Text
36
- - Handling Images
37
40
  - Routing
38
41
  -->
package/docs/_sidebar.md CHANGED
@@ -8,4 +8,5 @@
8
8
  - [Computed properties](computed_properties.md)
9
9
  - [Watching for changes](watchers.md)
10
10
  - [Styling and positioning Elements](element_attributes.md)
11
+ - [Displaying images](displaying_images.md)
11
12
 
@@ -2,20 +2,60 @@
2
2
 
3
3
  ## Component State
4
4
 
5
- In Blits, a component can start as simple as a template with fixed, hardcoded values. However, for dynamic behavior and logic, you'll often want to incorporate an internal state within your components.
5
+ 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 extend your components with an _internal state_.
6
6
 
7
- Some key concepts to keep in mind:
7
+ Some key concepts to keep in mind regarding Component state:
8
8
 
9
- - Each component instance maintains its own distinct internal state.
9
+ - Each component _instance_ maintains its own distinct internal state.
10
10
  - The component state is defined within the `state` key of the Component configuration object.
11
- - 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.
11
+ - 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.
12
12
  - 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`.
13
13
  - While flexibility in structuring your state is advantageous, be cautious about excessive nesting, as it could have a negative effect on performance.
14
14
 
15
15
  ### Accessing State in Templates
16
16
 
17
- As explained in the template section, you can refer to state variables in your Element's arguments by prefixing the state variable name with a dollar sign (e.g., `$alpha`). For nested objects, you can use dot notation (e.g., `$style.w`).
17
+ As explained in the [template section](./template_syntax.md), you can refer to state variables in an Element's arguments by prefixing the state variable name with a _dollar sign_ (e.g., `$alpha`). For nested objects, you can use_dot notation_ (e.g., `$style.dimensions.w`).
18
18
 
19
19
  ### Accessing State in Component Code
20
20
 
21
- In your component's code, you can reference state variables within the `this` scope. For instance, a state variable named `color` can be accessed and modified by referencing `this.color`. 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.
21
+ In your component's code, you can reference state variables within the `this` scope. For instance, a state variable named `color` can be accessed and modified by referencing `this.color`. 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.
22
+
23
+ ```js
24
+ export default Blits.Component('MyComponent', {
25
+ template: `
26
+ <Element :show="$active">
27
+ <Element :x="$style.x" w="100" :h="$style.dimensions.h">
28
+ <Element w="20" :h="$style.dimensions.h / 2" :color="$color" />
29
+ </Element>
30
+ </Element>
31
+ `,
32
+ state() {
33
+ return {
34
+ active: false,
35
+ items: [],
36
+ style: {
37
+ positions: {
38
+ x: 100,
39
+ },
40
+ dimensions: {
41
+ h: 100,
42
+ },
43
+ },
44
+ color: 'tomato'
45
+ }
46
+ }
47
+ hooks: {
48
+ ready() {
49
+ this.active = true
50
+ this.$setInterval(() => {
51
+ this.style.positions.x += 10
52
+ })
53
+ }
54
+ },
55
+ input: {
56
+ right() {
57
+ this.color = '#c0ffee'
58
+ }
59
+ }
60
+ })
61
+ ```
@@ -6,7 +6,6 @@ Components in Blits follow a clearly defined structure, which helps keep your co
6
6
 
7
7
  This universal structure is also valuable for the interoperability of components.
8
8
 
9
-
10
9
  ### Creating a new Component
11
10
 
12
11
  Let's see how to create a new component and explore the basic anatomy of a component.
@@ -15,13 +14,45 @@ A new component is created using the `Blits.Component()` function. This function
15
14
 
16
15
  1. The first argument is the name of the component, which is mainly used for debugging purposes. It's essential to choose a unique and descriptive name for your component, such as `Homepage`, `Loader` or `SidebarMenuItem`.
17
16
 
18
- 2. The second argument is a configuration object, represented as an `object literal`. This configuration object can contain a predefined set of key-value pairs, including for example:
17
+ 2. The second argument is a _configuration object_, represented as an `object literal`. This configuration object can contain a predefined set of key-value pairs, including for example:
19
18
 
20
19
  - `template`: to define the template for the component.
21
20
  - `state`: to specify the component instance's internal state.
22
- - `prop`: to define the props that can be passed into the component.
21
+ - `props`: to define the props that can be passed into the component.
23
22
  - `hooks`: allowing you to hook into different lifecycle events of the component.
24
23
  - `input`: used to tap into user input.
24
+ - `methods`: used to define more complex functionality of the component
25
+
26
+ ```js
27
+ // src/components/Loader.js
28
+ export default Blits('Loader', {
29
+ template: `
30
+ <Element x="880" y="500" :show="$active">
31
+ <Element x="$offset" w="40" h="40" color="#94a3b8" :alpha="$alpha" />
32
+ </Element>
33
+ `,
34
+ props: ['type', 'size'],
35
+ state() {
36
+ return {
37
+ active: false,
38
+ alpha: 0.4,
39
+ offset: 100
40
+ }
41
+ },
42
+ hooks: {
43
+ ready() {
44
+ this.$setTimeout(() => {
45
+ this.active = true
46
+ }, 300)
47
+ }
48
+ },
49
+ input: {
50
+ enter() {
51
+ this.alpha = 1
52
+ }
53
+ }
54
+ })
55
+ ```
25
56
 
26
57
  In the next sections, we will go into the details of each of the component configuration options.
27
58
 
@@ -0,0 +1,69 @@
1
+ # Blits - Lightning 3 App Development Framework
2
+
3
+ ## Displaying Images
4
+
5
+
6
+ Now that we've covered the basics of creating Elements, as well as styling and positioning them, it's time to move away from these boring rectangles and explore how you can incorporate _images_ into your App.
7
+
8
+ In Blits is very easy to display an image. Simply add the `src` attribute to an Element, specifying the image's location.
9
+
10
+ For local images, make sure to place them in the `public` folder (e.g., `public/assets/background.jpg` or `public/images/logo.png`) and refer to them with a _relative_ path (omitting the `public` folder as root).
11
+
12
+ Remote images are also supported and can be linked directly (e.g., `http://mycdn.com/artists/jimi_hendrix/woodstock.jpg`).
13
+
14
+ ```xml
15
+ <Element src="images/logo.png" w="100" h="80" />
16
+ <Element src="http://mycdn.com/artists/jimi_hendrix/woodstock.jpg" w="1920" h="1080" />
17
+ ```
18
+
19
+ ### Sizing and Scaling
20
+
21
+ Make sure to give your Element a width (`w` ) and a height (`h`) attribute. Blits will scale the image to fit these exact dimensions.
22
+
23
+ For the best performance, it's important to keep your source images as small as possible. If you're displaying an image at `200px x 200px`, make sure the image is exactly that size or _smaller_. The latter option may lead to some quality loss.
24
+
25
+ ### Colorization
26
+
27
+ You also have the option to _colorize_ an image on the fly. Just add a `color` attribute to the Element with a `src` attribute. You can use a single color, or apply a gradient. By default all Elements with a `src` attribute get the a solid white background, which corresponds with the actual colors of the image.
28
+
29
+ ```xml
30
+ <Element
31
+ w="200"
32
+ h="300"
33
+ :src="$src"
34
+ color="{top: '#fff', bottom: '#000'}"
35
+ />
36
+ ```
37
+
38
+ ### Asynchronous Loading
39
+
40
+ All images are loaded asynchronously (and can possibly fail to load), even those local to your App. Blits allows you to easily hook into the `loaded` and `error` events of image Elements.
41
+
42
+ You can use this, for example, to only make something visible once an image is fully loaded. Or to display a fallback image when an remote image can't be retrieved.
43
+
44
+ ```xml
45
+ <Element src="http://mycdn.com/lightning.jpg" @loaded="$revealPage" @error="$showFallback" />
46
+ ```
47
+
48
+ > Note how events are prefixed with a `@` sign.
49
+
50
+ Considering the template above, in the `methods` key of your Component configuration object, you would then do something like:
51
+
52
+ ```js
53
+ {
54
+ //...
55
+ methods: {
56
+ revealPage(dimensions) {
57
+ this.$log.info('Image dimensions', dimensions.w, dimensions.h)
58
+ this.show = true
59
+ },
60
+ showFallback(error) {
61
+ this.$log.error('Image failed to load', error)
62
+ this.showBackupImage()
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+ The `loaded` event receives the images dimensions as it's argument and the `error` event receives an error message explaining the failure.
69
+
@@ -92,7 +92,9 @@ The value of alpha is also being applied recursively to the children of the Elem
92
92
 
93
93
  ### Rotation and scaling
94
94
 
95
- If you want to rotate an Element, you can use the `rotation` attribute. The rotation attribute in Blits accepts values in degrees. The rotation of an Element is also automatically applied to any children down the tree.
95
+ If you want to rotate an Element, you can use the `rotation` attribute. The rotation attribute in Blits accepts values in _degrees_.
96
+
97
+ The rotation of an Element is also automatically applied to any children down the tree.
96
98
 
97
99
  ```xml
98
100
  <Element w="200" h="200" color="blue" rotation="90">
@@ -100,13 +102,20 @@ If you want to rotate an Element, you can use the `rotation` attribute. The rota
100
102
  </Element>
101
103
  ```
102
104
 
103
- For scaling an Element the `scale` attribute is used. This attribute can be any numeric value starting at `0`. The default value is `1`, which means no scaling. Any value below `1` will scale down the element and values greater than `1` will scale the element up.
105
+ For scaling an Element the `scale` attribute is used.
106
+
107
+ This attribute either accepts a single numeric value for scaling evenly accross width and height. Or an _object literal_, if you want to apply a different scaling for the `x` and the `y` axis.
108
+
109
+ The value should start at `0` and the default value is `1`, which means no scaling.
110
+
111
+ Any value below `1` will scale _down_ the element and values greater than `1` will scale the element _up_.
104
112
 
105
113
  Similar to rotation, scale is also applied recursively to children down the tree of the Element that has it's `scale` attribute set.
106
114
 
107
115
  ```xml
108
116
  <Element w="200" h="200" color="blue" scale="0.5" />
109
117
  <Element w="200" h="200" color="#000" scale="2.3" />
118
+ <Element w="200" h="200" color="#000" scale="{x: 1, y: 3.14}" />
110
119
  ```
111
120
 
112
121
  ### Mounting point
@@ -119,20 +128,27 @@ In order to align the position starting at the _bottom-right_ corner, we would s
119
128
 
120
129
  If you omit either the `x` or the `y` key from the _object literal_, it's value will default to `0`.
121
130
 
131
+ In the case where the `x` and `y` values are the same (i.e. centering with `{x: 0.5, y: 0.5}`), you can also just supply a single value (`mount="0.5"`) instead of the object literal notation.
132
+
122
133
  ```xml
123
134
  <Element w="200" h="200" x="20" y="100" color="#333" mount="{x: 0.5, y: 0.8}" />
124
135
  <Element w="200" h="200" x="800" y="400" color="#333" mount="{y: 1}" />
136
+ <Element w="200" h="200" x="800" y="700" color="#333" mount="0.5" />
125
137
  ```
126
138
 
127
139
  ### Pivot point
128
140
 
129
- The pivot point of an Element comes into play when it's rotated or scaled. The pivot point defaults to the center of the Element, which means that when setting `rotation` it rotates around the middle. And when the Element is scaled it scales from the center out.
141
+ The pivot point of an Element comes into play when it's rotated or scaled. The pivot point defaults to the _center_ of the Element, which means that when setting `rotation` it rotates around the middle. And when the Element is scaled it scales from the center out.
130
142
 
131
143
  But sometimes you may want rotate around the left corner, or scale from the right side out. This can be controlled by adding the `pivot` attribute to the Element and, similar to the `mount` attribute, specify an _object literal_ with a `x` and a `y` key.
132
144
 
133
145
  Both `y` and `x` values should be anything between `0` and `1`, where `{x: 0, y: 0}` sets the pivot point to the _top-left_ corner and `{x: 1, y: 1}` refers to the _bottom-right_ corner. The default pivot value is `{x: 0.5, y: 0.5}` (i.e. the center) and if you omit `x` or `y` in your pivot object, it will default to `0.5`.
134
146
 
147
+ In the case where the `x` and `y` values are the same, you can also just supply a single value (`pivot="0.9"`) instead of the object literal notation.
148
+
149
+
135
150
  ```xml
136
151
  <Element w="200" h="200" x="20" y="100" pivot="{x: 0.5, y: 0.8}" rotation="69" />
137
152
  <Element w="200" h="200" x="800" y="400" pivot="{y: 1}" scale="3" />
153
+ <Element w="200" h="200" x="800" y="700" pivot="0.9" rotation="42" />
138
154
  ```
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Hooking into Lifecycle Events
4
4
 
5
- In Blits, components follow a defined flow of lifecycle events. Developers can integrate their logic into these events by specifying them in the `hooks` key of the Component configuration object.
5
+ 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.
6
6
 
7
7
  For each available lifecycle event, you can define a function with the same name as the event itself. This function will execute each time the 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.
8
8
 
@@ -18,11 +18,9 @@ For each available lifecycle event, you can define a function with the same name
18
18
 
19
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
20
 
21
- ### Example
22
-
23
- ```javascript
24
- {
25
- // Other component configurations...
21
+ ```js
22
+ export default Blits.Component('MyComponent', {
23
+ // ...
26
24
  hooks: {
27
25
  init() {
28
26
  // Logic to execute on init event
@@ -40,7 +38,5 @@ For each available lifecycle event, you can define a function with the same name
40
38
  // Logic to execute on destroy event
41
39
  },
42
40
  },
43
- };
41
+ })
44
42
  ```
45
-
46
- In the provided example, each function within the `hooks` object corresponds to a specific lifecycle event, allowing developers to inject custom logic at different stages of the component's lifecycle.
package/docs/props.md CHANGED
@@ -25,9 +25,11 @@ For more advanced usage, you can define props using an array of objects for each
25
25
  - Mark the prop as _required_.
26
26
  - Apply a `cast` function to modify the value passed as a prop.
27
27
 
28
- ```javascript
29
- {
28
+ ```js
29
+ export default Blits.Component('MyComponent', {
30
+ // ...
30
31
  props: [
32
+ 'color',
31
33
  {
32
34
  key: 'alpha',
33
35
  default: 0.5,
@@ -38,7 +40,7 @@ For more advanced usage, you can define props using an array of objects for each
38
40
  cast: Number
39
41
  }
40
42
  ]
41
- }
43
+ })
42
44
  ```
43
45
 
44
46
  You can mix and match the simple string notation with the more advanced object notation within the same `props` array.
@@ -2,15 +2,13 @@
2
2
 
3
3
  ## Template structure
4
4
 
5
- Blits uses an easy-to-read XML-style template syntax. The syntax is inspired by frameworks like VueJS, so developers familiar with Vue will recognize certain concepts.
5
+ Blits uses an easy-to-read _XML-style_ template syntax. The syntax is inspired by frameworks like VueJS, so developers familiar with Vue will recognize certain concepts.
6
6
 
7
- The template key in the configuration object holds a string with an XML-like structure. Templates often span multiple lines, so it's advisable to use a JS template literal.
7
+ The _template_ key in the Componentn configuration object holds a string with an XML-like structure. Templates often span multiple lines, so it's advisable to use a JS template literal.
8
8
 
9
9
  You can use different tags in your templates. And similar to HTML you can use arguments and nested tags. Self-closing tags and HTML-style comments are also supported.
10
10
 
11
- The default tag within a template is the `<Element>` tag, which corresponds to a node in the Lightning 3 renderer. For each element, you can define a set of predefined render properties, such as `x`, `y`, `w`, `color`, and more. Detailed information regarding the properties supported by the <Element> tag can be found here.
12
-
13
- As your component grows in complexity, you may want to organize your template with custom components, abstracting both templates and logic. Inside a component template, you can utilize sub-components (i.e. a `Menu` component) and reference them with tags like `<Menu></Menu>`.
11
+ The default tag within a template is the `<Element>` tag, which corresponds to a node in the Lightning 3 renderer. For each element, you can define a set of predefined render properties, such as `x`, `y`, `w`, `color`, and more. Detailed information regarding the attributes supported by the <Element> tag can be found [here](./element_attributes.md).
14
12
 
15
13
  Consider the following template example:
16
14
 
@@ -22,10 +20,46 @@ Consider the following template example:
22
20
  </Element>
23
21
  ```
24
22
 
23
+ ### Hardcoded arguments
24
+
25
25
  In this template, you'll observe certain arguments with hardcoded values. You use these to configure the parts of your component that never change.
26
26
 
27
+ ### Dynamic arguments
28
+
27
29
  Additionally, some arguments contain a value prefixed with a dollar sign (`$`), representing _dynamic_ arguments. When the component renders, it automatically populates these dynamic values based on the component's state (or props or computed properties).
28
30
 
31
+ ### Reactive arguments
32
+
29
33
  Furthermore, certain arguments are prefixed with a colon sign (`:`), indicating _reactive_ arguments. These are not only dynamically set when your component renders, but also _rerender_ the corresponding part of the template whenever the referenced value in your component's internal state changes. This reactive data binding eliminates the need for manual template patching, as seen in Lightning 2.
30
34
 
31
35
  Reactive arguments support _interpolation_, enabling the use of simple JavaScript instructions, such as ternary conditions or basic string and Math manipulations. For more complex logic, it's recommended to abstract this into a Component method or a Computed property.
36
+
37
+ ## Custom components
38
+
39
+ As your component grows in complexity, you may want to reorganize your codebase with custom components, abstracting and reusing both templates and logic.
40
+
41
+ Inside a component template, you can utilize sub-components (i.e. a `Menu` component) and reference them with tags like `<Menu></Menu>`.
42
+
43
+ In order for the `<Menu />` tag to become available for use in a component's template, you first have to `import` the file that exports that component.
44
+
45
+ Next you have to _register_ this imported component using the `components`-key in the configuration object. The `components` key is an _object literal_, where the value is the reference to the Blits component. The key will correspond with the _tag_ that can be used to invoke the component.
46
+
47
+ ```js
48
+
49
+ import Menu from './components/menu.js'
50
+ import Button from './components/button.js'
51
+
52
+ export default Blits.Component('MyComponent', {
53
+ components: {
54
+ Menu, // makes <Menu /> available for use in the template
55
+ MyButton: Button, // makes Button available as <MyButton /> in the template
56
+ },
57
+ template: `
58
+ <Element>
59
+ <Menu />
60
+ <MyButton />
61
+ </Element>
62
+ `
63
+ })
64
+
65
+ ```
@@ -2,18 +2,25 @@
2
2
 
3
3
  ## Handling User Input
4
4
 
5
- You don't want your Lightning 3 App to be completely static, instead users should be able to navigate and interact with the app, often using devices like a remote control.
5
+ When building an App you probably want users to interact with it as well, for example to enable them to navigate through your App. In other words, you will want to handle _user input_. In the context of a Blits / Lightning App this often will be key input via a remote control.
6
6
 
7
- Blits offers a straightforward interface to handle user input for each component.
7
+ Blits offers an intuitive and straightforward interface to handle key input in components.
8
+
9
+ ### Focus
10
+
11
+ Before diving into the specifics of key handling, it is important to understand the concept of _focus_. In a Blits app, there is always one Component that has the focus. By default this will be the root App component.
12
+
13
+ The component that currently has focus, is the one that is responsible for handling the user input at that moment. For example, when a user clicks the _right_ or _left_ button while a _Poster Component_ has focus, it is that instance of the Poster Component that will initially _receive_ the key press event.
8
14
 
9
15
  ### Configuring Input Handling
10
16
 
11
- Within the Component configuration object, the `input` key is utilized to define how the component should react to specific key presses when it has focus. It should contain an object of functions that specify the actions to take based on key presses.
17
+ Within the Component configuration object, the `input` key is used to define how the component should react to specific key presses when it has focus. The `input` key should be an `object literal` of `functions` for each input event that the component wants to handle.
12
18
 
13
- Each function should correspond to a key name, such as `up`, `down`, `enter`, `space`, `back`, `1`, `2`, `a` etc. Each function defined in the `input` object receives the full `InputEvent` object as its first argument.
19
+ Each function corresponds to a _key name_, such as `up`, `down`, `enter`, `space`, `back`, `1`, `2`, `a` etc. Each function defined in the `input` object, receives the full `InputEvent` object as its first argument.
14
20
 
15
21
  ```javascript
16
- {
22
+ export default Blits.Component('MyComponent', {
23
+ // ...
17
24
  input: {
18
25
  up() {
19
26
  // Logic to execute when users press up
@@ -30,9 +37,9 @@ Each function should correspond to a key name, such as `up`, `down`, `enter`, `s
30
37
 
31
38
  ### Event Handling Chain
32
39
 
33
- If the currently focused component does not handle a key press, the framework will traverse up the component hierarchy, checking if any parent components have defined functions for that key press in their `input`-object. This event handling chain continues until it reaches the root Application.
40
+ If the currently focused component does not handle a key press, Blits will traverse up the component hierarchy, checking for any _parent_ component that does have a function defined for that key press in the `input`-key. This input event handling chain continues until it reaches the root App component.
34
41
 
35
- When a component handles a key press by having a corresponding function specified, the event handling chain stops by default. However, if you want the input event to propagate up the hierarchy, you can set focus to the parent element and pass the `InputEvent` object on in the function call.
42
+ When a component handles a key press by having a corresponding function specified, the event handling chain stops by default. However, if you want the input event to propagate up the hierarchy, you can set focus to the parent element and pass the `InputEvent` object on in that function call.
36
43
 
37
44
  ```javascript
38
45
  {
@@ -51,7 +58,7 @@ When a component handles a key press by having a corresponding function specifie
51
58
 
52
59
  ### Catch-All Handling
53
60
 
54
- To allow a focused component to respond to any key and act as a catch-all, you can add an `any()` function to the input object.
61
+ To allow a focused component to respond to any key and act as a _catch-all_, you can add an `any()` function to the input object.
55
62
 
56
63
  ```javascript
57
64
  {
@@ -62,3 +69,59 @@ To allow a focused component to respond to any key and act as a catch-all, you c
62
69
  }
63
70
  }
64
71
  ```
72
+
73
+ ### Custom Keycode mapping
74
+
75
+ Blits comes with a default keycode mapping. This mapping is a sensible default that works in your desktop browser and with most RDK based devices.
76
+
77
+ But it's possible that the keycodes and mapping of your target device are slightly or even completely different.
78
+
79
+ In Blits you can easily configure the key mapping to match your needs. In the `src/index.js` file where we instaniate the App via the `Blits.Launch` function, we can add an extra key, called `keys`, to the _settings object_.
80
+
81
+ The `'key` item should be an object literal with _key value pairs_. As the `key`, you should provide the `key` or `keyCode` of the `KeyboardEvent` and the `value` should be the name of the event as used in the `input` object of the Component configuration object.
82
+
83
+ > You can use a site like [keyjs.dev](https://keyjs.dev/) to find the key and keyCode
84
+
85
+ ```js
86
+ // src/index.js
87
+ Blits.Launch(App, 'app', {
88
+ w: 1920,
89
+ h: 1080,
90
+ //...
91
+ keys: {
92
+ // switch left and right using the key
93
+ ArrowLeft: 'right',
94
+ ArrowRight: 'left',
95
+ // switch up and down using the keyCode
96
+ 38: 'down',
97
+ 40: 'up',
98
+ // register new handlers
99
+ '.': 'dot', // dot() can now be used in the input object
100
+ // key code for letter 's'
101
+ 83: 'search' // search() can now be used in the input object
102
+ }
103
+ })
104
+ ```
105
+
106
+ The custom keys object will be merged with the default key mapping, that looks like this:
107
+
108
+ ```js
109
+ const defaultKeyMap = {
110
+ ArrowLeft: 'left',
111
+ ArrowRight: 'right',
112
+ ArrowUp: 'up',
113
+ ArrowDown: 'down',
114
+ Enter: 'enter',
115
+ ' ': 'space',
116
+ Backspace: 'back',
117
+ Escape: 'escape',
118
+ 37: 'left',
119
+ 39: 'right',
120
+ 38: 'up',
121
+ 40: 'down',
122
+ 13: 'enter',
123
+ 32: 'space',
124
+ 8: 'back',
125
+ 27: 'escape',
126
+ }
127
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightningjs/blits",
3
- "version": "0.5.9",
3
+ "version": "0.6.0",
4
4
  "description": "Blits: The Lightning 3 App Development Framework",
5
5
  "bin": "bin/index.cjs",
6
6
  "exports": {
package/src/component.js CHANGED
@@ -47,13 +47,11 @@ const required = (name) => {
47
47
  }
48
48
 
49
49
  const Component = (name = required('name'), config = required('config')) => {
50
- let code = null
51
-
52
50
  const setupComponent = (lifecycle) => {
53
51
  // code generation
54
- if (!code) {
52
+ if (!config.code) {
55
53
  Log.debug(`Generating code for ${name} component`)
56
- code = codegenerator.call(config, parser(config.template))
54
+ config.code = codegenerator.call(config, parser(config.template))
57
55
  }
58
56
 
59
57
  setupBase(component)
@@ -167,7 +165,7 @@ const Component = (name = required('name'), config = required('config')) => {
167
165
  this.lifecycle.state = 'init'
168
166
 
169
167
  Object.defineProperty(this, symbols.children, {
170
- value: code.render.apply(stage, [parentEl, this, code.context]),
168
+ value: config.code.render.apply(stage, [parentEl, this, config]),
171
169
  writable: false,
172
170
  enumerable: false,
173
171
  configurable: false,
@@ -180,9 +178,9 @@ const Component = (name = required('name'), config = required('config')) => {
180
178
  configurable: false,
181
179
  })
182
180
 
183
- code.effects.forEach((eff) => {
181
+ config.code.effects.forEach((eff) => {
184
182
  effect(() => {
185
- eff.apply(stage, [this, this[symbols.children], code.context])
183
+ eff.apply(stage, [this, this[symbols.children], config])
186
184
  })
187
185
  })
188
186
 
@@ -16,6 +16,7 @@
16
16
  */
17
17
 
18
18
  import Component from '../component.js'
19
+ import Settings from '../settings.js'
19
20
 
20
21
  export default () =>
21
22
  Component('Text', {
@@ -41,7 +42,7 @@ export default () =>
41
42
  'content',
42
43
  {
43
44
  key: 'font',
44
- default: 'lato',
45
+ default: Settings.get('defaultFont', 'lato'),
45
46
  },
46
47
  {
47
48
  key: 'size',
package/src/element.js CHANGED
@@ -163,7 +163,7 @@ const Props = {
163
163
  this._set.add('scale')
164
164
  },
165
165
  set show(v) {
166
- this.alpha = v ? 1 : 0
166
+ this._props.alpha = v ? 1 : 0
167
167
  },
168
168
  set alpha(v) {
169
169
  this._props.alpha = v
package/src/launch.d.ts CHANGED
@@ -51,6 +51,8 @@ interface SdfFont {
51
51
  png: string
52
52
  }
53
53
 
54
+ type ScreenResolutions = 'hd' | '720p' | 720 | 'fhd' | 'fullhd' | '1080p' | 1080 | '4k' | '2160p' | 2160
55
+
54
56
  type Font = WebFont | SdfFont
55
57
 
56
58
  export type DebugLevel = 0 | 1 | 2
@@ -88,6 +90,15 @@ export interface Settings {
88
90
  * Fonts to be used in the Application
89
91
  */
90
92
  fonts?: Font[],
93
+ /**
94
+ * Default font family to use in the Application when no font attribute is specified
95
+ * on a Text-component
96
+ *
97
+ * The default font must be registered in the `fonts` array in the settings.
98
+ *
99
+ * Defaults to `lato` font family
100
+ */
101
+ defaultFont?: string,
91
102
  /**
92
103
  * Custom keymapping
93
104
  */
@@ -95,7 +106,45 @@ export interface Settings {
95
106
  /**
96
107
  * Mode of reactivity (`Proxy` or `defineProperty`)
97
108
  */
98
- reactivityMode?: ReactivityModes
109
+ reactivityMode?: ReactivityModes,
110
+ /**
111
+ * Screen resolution of the device, defining the pixelRatio used to convert dimensions
112
+ * and positions in the App code to the actual device logical coordinates
113
+ *
114
+ * If not supplied, Blits will try to autodetect the device screen resolution. Otherwise
115
+ * the exact dimensions and positions used the app code are used.
116
+ *
117
+ * Note: If the option `pixelRatio` is specified in the Settings object, this value will take presedence
118
+ * over the screen resolution setting.
119
+ *
120
+ * Currently 3 screen resolutions are supported, which can be defined with different alias values:
121
+ *
122
+ * For 720x1080 (1px = 0.66666667px)
123
+ * - hd
124
+ * - 720p
125
+ * - 720
126
+ *
127
+ * For 1080x1920 (1px = 1px)
128
+ * - fhd
129
+ * - fullhd
130
+ * - 1080p
131
+ * - 1080
132
+ *
133
+ * For 2160x3840 (1px = 2px)
134
+ * - 4k
135
+ * - 2160p
136
+ * - 2160
137
+ */
138
+ screenResolution?: ScreenResolutions,
139
+ /**
140
+ * Custom pixel ratio of the device used to convert dimensions
141
+ * and positions in the App code to the actual device logical coordinates
142
+ *
143
+ * Takes presedence over the `screenResolution` setting
144
+ *
145
+ * Defaults to 1 if not specified
146
+ */
147
+ pixelRatio?: number
99
148
  }
100
149
 
101
150
  /**
package/src/launch.js CHANGED
@@ -19,7 +19,7 @@ import { MainCoreDriver, RendererMain } from '@lightningjs/renderer'
19
19
  // import RendererWorker from '@lightningjs/renderer/workers/renderer?worker'
20
20
  import Settings from './settings.js'
21
21
  import { initLog, Log } from './lib/log.js'
22
-
22
+ import { screenResolutions } from './lib/utils.js'
23
23
  // import coreExtensionModule from './fontLoader.js?importChunkUrl'
24
24
 
25
25
  export let renderer
@@ -41,6 +41,11 @@ export default (App, target, settings) => {
41
41
  appWidth: settings.w || 1920,
42
42
  appHeight: settings.h || 1080,
43
43
  coreExtensionModule: settings.fontLoader,
44
+ deviceLogicalPixelRatio:
45
+ settings.pixelRatio ||
46
+ screenResolutions[settings.screenResolution] ||
47
+ screenResolutions[window.innerHeight] ||
48
+ 1,
44
49
  },
45
50
  target,
46
51
  driver
@@ -92,8 +92,8 @@ const generateElementCode = function (
92
92
  if (options.holder === true) {
93
93
  renderCode.push(`
94
94
  if(typeof cmp${counter} !== 'undefined') {
95
- for(key in cmp${counter}.config.props) {
96
- delete elementConfig${counter}[cmp${counter}.config.props[key]]
95
+ for(let key in cmp${counter}.config.props) {
96
+ delete elementConfig${counter}[cmp${counter}.config.props[key]]
97
97
  }
98
98
  }
99
99
  `)
@@ -171,7 +171,7 @@ const generateComponentCode = function (
171
171
 
172
172
  renderCode.push(`
173
173
  if(!${elm}) {
174
- ${elm} = (context.components && context.components['${templateObject.type}'] || component[Symbol.for('components')]['${templateObject.type}'] || (() => { console.log('component ${templateObject.type} not found')})).call(null, {props: props${counter}}, ${parent}, component)
174
+ ${elm} = (context.components && context.components['${templateObject.type}'] || component[Symbol.for('components')]['${templateObject.type}'] || (() => { console.error('component ${templateObject.type} not found')})).call(null, {props: props${counter}}, ${parent}, component)
175
175
  if (${elm}[Symbol.for('slots')][0]) {
176
176
  parent = ${elm}[Symbol.for('slots')][0]
177
177
  component = ${elm}
@@ -0,0 +1,12 @@
1
+ export const screenResolutions = {
2
+ hd: 0.66666667,
3
+ '720p': 0.66666667,
4
+ 720: 0.66666667,
5
+ fhd: 1,
6
+ fullhd: 1,
7
+ '1080p': 1,
8
+ 1080: 1,
9
+ '4k': 2,
10
+ '2160p': 2,
11
+ 2160: 2,
12
+ }
package/vite/index.js CHANGED
@@ -1 +1,7 @@
1
+ import preCompiler from './preCompiler.js'
2
+ import { importChunkUrl } from '@lightningjs/vite-plugin-import-chunk-url'
3
+
1
4
  export { importChunkUrl as importChunkUrl } from '@lightningjs/vite-plugin-import-chunk-url'
5
+ export { default as preCompiler } from './preCompiler.js'
6
+
7
+ export default [importChunkUrl(), preCompiler()]
@@ -0,0 +1,46 @@
1
+ import parser from '../src/lib/templateparser/parser.js'
2
+ import generator from '../src/lib/codegenerator/generator.js'
3
+
4
+ export default function () {
5
+ let config
6
+ return {
7
+ name: 'preCompiler',
8
+ configResolved(resolvedConfig) {
9
+ config = resolvedConfig
10
+ },
11
+ transform(source) {
12
+ if (config.blits && config.blits.precompile === false) return source
13
+ if (source.indexOf('Blits.Component(') > -1 || source.indexOf('Blits.Application(') > -1) {
14
+ // get the start of the template key in de component configuration object
15
+ const templateKeyRegex = /template:\s*([`"'])*/g
16
+ const templateStartResult = templateKeyRegex.exec(source)
17
+ const typeOfQuotesUsed = templateStartResult[1]
18
+ const templateStartIndex = templateStartResult.index
19
+
20
+ // get the template contents from the configuration object
21
+ const templateContentsRegex = new RegExp(
22
+ `${typeOfQuotesUsed}([\\s\\S]*?)${typeOfQuotesUsed}`
23
+ )
24
+
25
+ const templateContentResult = templateContentsRegex.exec(source.slice(templateStartIndex))
26
+ const templateEndIndex =
27
+ templateStartIndex + templateContentResult.index + templateContentResult[0].length
28
+
29
+ // Parse the template
30
+ const parsed = parser(templateContentResult[1])
31
+
32
+ // Generate the code
33
+ const code = generator.call({ components: {} }, parsed)
34
+
35
+ // Insert the code in the component using the 'code' key, replacing the template key
36
+ const replacement = `code: { render: ${code.render.toString()}, effects: [${code.effects.map(
37
+ (fn) => fn.toString() + ','
38
+ )}], context: {}}`
39
+ const newSource =
40
+ source.substring(0, templateStartIndex) + replacement + source.substring(templateEndIndex)
41
+
42
+ return newSource
43
+ }
44
+ },
45
+ }
46
+ }