@lightningjs/blits 0.5.8 → 0.5.10
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 +18 -0
- package/README.md +1 -1
- package/boilerplate/package.json +1 -1
- package/docs/README.md +6 -3
- package/docs/_sidebar.md +1 -0
- package/docs/component_state.md +46 -6
- package/docs/components.md +34 -3
- package/docs/displaying_images.md +69 -0
- package/docs/element_attributes.md +19 -3
- package/docs/lifecycle_events.md +5 -9
- package/docs/props.md +5 -3
- package/docs/template_syntax.md +39 -5
- package/docs/user_input.md +71 -8
- package/package.json +2 -2
- package/src/component.js +1 -1
- package/src/element.js +2 -2
- package/src/launch.d.ts +41 -1
- package/src/launch.js +6 -1
- package/src/lib/setup/routes.js +12 -1
- package/src/lib/symbols.js +1 -0
- package/src/lib/utils.js +12 -0
- package/src/router/router.js +25 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
# v0.5.10
|
|
4
|
+
|
|
5
|
+
_3 jan 2024_
|
|
6
|
+
|
|
7
|
+
- Updated and improved documentation
|
|
8
|
+
- Added `screenResolution` and `pixelRatio` options to settings
|
|
9
|
+
|
|
10
|
+
# v0.5.9
|
|
11
|
+
|
|
12
|
+
_21 dec 2023_
|
|
13
|
+
|
|
14
|
+
- Changed transition-end callback to receive real prop value from node
|
|
15
|
+
- Implemented symbol for `wrapper` on Component (freeing up the name wrapper to be used in Component state)
|
|
16
|
+
- Added functionality to prevent a route ending up in the history stack (route option: `inHistory: false`)
|
|
17
|
+
- Improved router backtracking logic
|
|
18
|
+
- Added functionality to override route options during navigation
|
|
19
|
+
- Upgraded to latest version of the renderer (0.6.1) which contains a fix for animations not finishing correctly
|
|
20
|
+
|
|
3
21
|
# v0.5.8
|
|
4
22
|
|
|
5
23
|
_15 dec 2023_
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Blits - Lightning 3 App Development Framework
|
|
4
4
|
|
|
5
|
-
With Blits
|
|
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
|
|
package/boilerplate/package.json
CHANGED
package/docs/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Blits - Lightning 3 App Development Framework
|
|
2
2
|
|
|
3
|
-
With Blits
|
|
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.
|
|
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
package/docs/component_state.md
CHANGED
|
@@ -2,20 +2,60 @@
|
|
|
2
2
|
|
|
3
3
|
## Component State
|
|
4
4
|
|
|
5
|
-
In Blits, a component can
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
+
```
|
package/docs/components.md
CHANGED
|
@@ -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
|
|
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
|
-
- `
|
|
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
|
|
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.
|
|
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
|
|
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
|
```
|
package/docs/lifecycle_events.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Hooking into Lifecycle Events
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
```
|
|
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.
|
package/docs/template_syntax.md
CHANGED
|
@@ -2,15 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## Template structure
|
|
4
4
|
|
|
5
|
-
Blits uses an easy-to-read
|
|
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
|
|
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
|
|
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
|
+
```
|
package/docs/user_input.md
CHANGED
|
@@ -2,18 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
## Handling User Input
|
|
4
4
|
|
|
5
|
-
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
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.
|
|
3
|
+
"version": "0.5.10",
|
|
4
4
|
"description": "Blits: The Lightning 3 App Development Framework",
|
|
5
5
|
"bin": "bin/index.cjs",
|
|
6
6
|
"exports": {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"tape": "^5.5.0"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@lightningjs/renderer": "^0.6.
|
|
45
|
+
"@lightningjs/renderer": "^0.6.1",
|
|
46
46
|
"@lightningjs/vite-plugin-import-chunk-url": "^0.3.0"
|
|
47
47
|
}
|
|
48
48
|
}
|
package/src/component.js
CHANGED
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
|
|
@@ -317,7 +317,7 @@ const Element = {
|
|
|
317
317
|
// fire transition end callback if specified
|
|
318
318
|
transition.end &&
|
|
319
319
|
typeof transition.end === 'function' &&
|
|
320
|
-
transition.end.call(this.component, this, prop,
|
|
320
|
+
transition.end.call(this.component, this, prop, this.node[prop])
|
|
321
321
|
})
|
|
322
322
|
.then(resolve)
|
|
323
323
|
} catch (e) {
|
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
|
|
@@ -95,7 +97,45 @@ export interface Settings {
|
|
|
95
97
|
/**
|
|
96
98
|
* Mode of reactivity (`Proxy` or `defineProperty`)
|
|
97
99
|
*/
|
|
98
|
-
reactivityMode?: ReactivityModes
|
|
100
|
+
reactivityMode?: ReactivityModes,
|
|
101
|
+
/**
|
|
102
|
+
* Screen resolution of the device, defining the pixelRatio used to convert dimensions
|
|
103
|
+
* and positions in the App code to the actual device logical coordinates
|
|
104
|
+
*
|
|
105
|
+
* If not supplied, Blits will try to autodetect the device screen resolution. Otherwise
|
|
106
|
+
* the exact dimensions and positions used the app code are used.
|
|
107
|
+
*
|
|
108
|
+
* Note: If the option `pixelRatio` is specified in the Settings object, this value will take presedence
|
|
109
|
+
* over the screen resolution setting.
|
|
110
|
+
*
|
|
111
|
+
* Currently 3 screen resolutions are supported, which can be defined with different alias values:
|
|
112
|
+
*
|
|
113
|
+
* For 720x1080 (1px = 0.66666667px)
|
|
114
|
+
* - hd
|
|
115
|
+
* - 720p
|
|
116
|
+
* - 720
|
|
117
|
+
*
|
|
118
|
+
* For 1080x1920 (1px = 1px)
|
|
119
|
+
* - fhd
|
|
120
|
+
* - fullhd
|
|
121
|
+
* - 1080p
|
|
122
|
+
* - 1080
|
|
123
|
+
*
|
|
124
|
+
* For 2160x3840 (1px = 2px)
|
|
125
|
+
* - 4k
|
|
126
|
+
* - 2160p
|
|
127
|
+
* - 2160
|
|
128
|
+
*/
|
|
129
|
+
screenResolution?: ScreenResolutions,
|
|
130
|
+
/**
|
|
131
|
+
* Custom pixel ratio of the device used to convert dimensions
|
|
132
|
+
* and positions in the App code to the actual device logical coordinates
|
|
133
|
+
*
|
|
134
|
+
* Takes presedence over the `screenResolution` setting
|
|
135
|
+
*
|
|
136
|
+
* Defaults to 1 if not specified
|
|
137
|
+
*/
|
|
138
|
+
pixelRatio?: number
|
|
99
139
|
}
|
|
100
140
|
|
|
101
141
|
/**
|
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
|
package/src/lib/setup/routes.js
CHANGED
|
@@ -21,6 +21,17 @@ export default (component, routes) => {
|
|
|
21
21
|
component.prototype[symbols.routes] = []
|
|
22
22
|
Object.keys(routes).forEach((key) => {
|
|
23
23
|
// todo: validate routes[key] for expected format etc.
|
|
24
|
-
component.prototype[symbols.routes][key] =
|
|
24
|
+
component.prototype[symbols.routes][key] = {
|
|
25
|
+
...routes[key],
|
|
26
|
+
...{
|
|
27
|
+
// merge default route options with route specific options
|
|
28
|
+
options: {
|
|
29
|
+
...{
|
|
30
|
+
inHistory: true,
|
|
31
|
+
},
|
|
32
|
+
...routes[key].options,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
}
|
|
25
36
|
})
|
|
26
37
|
}
|
package/src/lib/symbols.js
CHANGED
package/src/lib/utils.js
ADDED
package/src/router/router.js
CHANGED
|
@@ -27,6 +27,8 @@ export let navigating = false
|
|
|
27
27
|
|
|
28
28
|
const cacheMap = new WeakMap()
|
|
29
29
|
const history = []
|
|
30
|
+
let overrideOptions = {}
|
|
31
|
+
let navigatingBack = false
|
|
30
32
|
|
|
31
33
|
export const getHash = () => {
|
|
32
34
|
return (document.location.hash || '/').replace(/^#/, '')
|
|
@@ -38,7 +40,10 @@ export const matchHash = (path, routes = []) => {
|
|
|
38
40
|
return r.path === path
|
|
39
41
|
})
|
|
40
42
|
.pop()
|
|
41
|
-
if (route)
|
|
43
|
+
if (route) {
|
|
44
|
+
route.options = { ...route.options, ...overrideOptions }
|
|
45
|
+
currentRoute = route
|
|
46
|
+
}
|
|
42
47
|
return route
|
|
43
48
|
}
|
|
44
49
|
|
|
@@ -50,7 +55,11 @@ export const navigate = async function () {
|
|
|
50
55
|
const route = matchHash(hash, this.parent[symbols.routes])
|
|
51
56
|
|
|
52
57
|
if (route) {
|
|
53
|
-
|
|
58
|
+
// add the previous route (tecnhically still the current route at this point)
|
|
59
|
+
// into the history stack, unless navigating back or inHistory flag of route is false
|
|
60
|
+
if (navigatingBack === false && previousRoute && previousRoute.options.inHistory === true) {
|
|
61
|
+
history.push(previousRoute)
|
|
62
|
+
}
|
|
54
63
|
// apply default transition if none specified
|
|
55
64
|
if (!('transition' in route)) {
|
|
56
65
|
route.transition = fadeInFadeOutTransition
|
|
@@ -82,7 +91,7 @@ export const navigate = async function () {
|
|
|
82
91
|
view = view(this[symbols.props], holder, this)
|
|
83
92
|
}
|
|
84
93
|
} else {
|
|
85
|
-
holder = view.wrapper
|
|
94
|
+
holder = view[symbols.wrapper]
|
|
86
95
|
}
|
|
87
96
|
|
|
88
97
|
this[symbols.children].push(view)
|
|
@@ -130,6 +139,9 @@ export const navigate = async function () {
|
|
|
130
139
|
Log.error(`Route ${hash} not found`)
|
|
131
140
|
}
|
|
132
141
|
}
|
|
142
|
+
|
|
143
|
+
// reset navigating indicators
|
|
144
|
+
navigatingBack = false
|
|
133
145
|
navigating = false
|
|
134
146
|
}
|
|
135
147
|
|
|
@@ -139,11 +151,11 @@ const removeView = async (route, view, transition) => {
|
|
|
139
151
|
if (Array.isArray(transition)) {
|
|
140
152
|
for (let i = 0; i < transition.length; i++) {
|
|
141
153
|
i === transition.length - 1
|
|
142
|
-
? await setOrAnimate(view.wrapper, transition[i])
|
|
143
|
-
: setOrAnimate(view.wrapper, transition[i])
|
|
154
|
+
? await setOrAnimate(view[symbols.wrapper], transition[i])
|
|
155
|
+
: setOrAnimate(view[symbols.wrapper], transition[i])
|
|
144
156
|
}
|
|
145
157
|
} else {
|
|
146
|
-
await setOrAnimate(view.wrapper, transition)
|
|
158
|
+
await setOrAnimate(view[symbols.wrapper], transition)
|
|
147
159
|
}
|
|
148
160
|
}
|
|
149
161
|
|
|
@@ -169,14 +181,17 @@ const setOrAnimate = (node, transition, shouldAnimate = true) => {
|
|
|
169
181
|
: node.set(transition.prop, transition.value)
|
|
170
182
|
}
|
|
171
183
|
|
|
172
|
-
export const to = (location) => {
|
|
184
|
+
export const to = (location, options = {}) => {
|
|
185
|
+
overrideOptions = options
|
|
173
186
|
window.location.hash = `#${location}`
|
|
174
187
|
}
|
|
175
188
|
|
|
176
189
|
export const back = () => {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
190
|
+
const route = history.pop()
|
|
191
|
+
if (route) {
|
|
192
|
+
// set indicator that we are navigating back (to prevent adding page to history stack)
|
|
193
|
+
navigatingBack = true
|
|
194
|
+
to(route.path)
|
|
180
195
|
return true
|
|
181
196
|
} else {
|
|
182
197
|
return false
|