@lightningjs/blits 1.4.2 → 1.5.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 +17 -0
- package/docs/components/user_input.md +48 -2
- package/package.json +2 -2
- package/src/application.js +7 -2
- package/src/engines/L3/element.js +12 -12
- package/src/engines/L3/launch.js +8 -1
- package/src/focus.js +8 -2
- package/src/lib/codegenerator/generator.js +2 -1
- package/src/lib/reactivity/reactive.js +2 -1
- package/src/plugins/appstate.js +2 -1
- package/src/plugins/language.js +9 -4
- package/src/plugins/theme.js +8 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.5.0
|
|
4
|
+
|
|
5
|
+
_1 oct 2024_
|
|
6
|
+
|
|
7
|
+
- Fixed issue with interupting running / scheduled transitions with a new transition on the same prop
|
|
8
|
+
- Fixed issue with (incompatible) SDF text renderer being loaded when `renderMode` is set to convas
|
|
9
|
+
- Added support for handling key release (i.e `keyup`) events
|
|
10
|
+
|
|
11
|
+
## v1.4.3
|
|
12
|
+
|
|
13
|
+
_26 sept 2024_
|
|
14
|
+
|
|
15
|
+
- Fixed issues with sprites in minified production build
|
|
16
|
+
- Bumped renderer to v2.2.0 (with fixes for nested alpha / show issue)
|
|
17
|
+
- Fixed reactivity in plugins not using reactivity mode setting
|
|
18
|
+
- Fixed named slots functionality
|
|
19
|
+
|
|
3
20
|
## v1.4.2
|
|
4
21
|
|
|
5
22
|
_24 sept 2024_
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Handling User Input
|
|
2
2
|
|
|
3
|
-
In order to allow users to interact with your app, you will want to capture and handle _user input_. If you are developing a TV based app this will
|
|
4
|
-
often be key input via a remote control.
|
|
3
|
+
In order to allow users to interact with your app, you will want to capture and handle _user input_. If you are developing a TV based app this will often be key input via a remote control.
|
|
5
4
|
|
|
6
5
|
Blits offers an intuitive and straightforward interface to handle key input in Components.
|
|
7
6
|
|
|
@@ -73,6 +72,53 @@ When a component handles a key press by having a corresponding function specifie
|
|
|
73
72
|
}
|
|
74
73
|
```
|
|
75
74
|
|
|
75
|
+
## Key-up handling
|
|
76
|
+
|
|
77
|
+
The functions specified in the `input` configuration are invoked when a key is _pressed down_ (i.e. the `keydown` event listener). But sometimes you may also want to execute some logic when a key is _released_ (i.e. the `keyup` event listener).
|
|
78
|
+
|
|
79
|
+
Instead of introducing a separate key on the Component configuration object for key release callbacks, Blits relies on the concept that a `keyup` event is always preceeded by a `keydown` event.
|
|
80
|
+
|
|
81
|
+
Following this logic, whenever you return a function in an input (key down) handler, this function will be executed upon release (i.e. the `keyup` event) of that key .
|
|
82
|
+
|
|
83
|
+
When an input key is being a hold down, it will execute the key down handler multipe times. Upon key release, only the last returned key up callback function will be executed.
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
Blits.Component('MyComponemnt', {
|
|
88
|
+
//
|
|
89
|
+
input: {
|
|
90
|
+
enter() {
|
|
91
|
+
// execute logic on key down
|
|
92
|
+
this.pressedEnter = true
|
|
93
|
+
return () => {
|
|
94
|
+
// execute logic on key up
|
|
95
|
+
this.pressedEnter = false
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
space(e) {
|
|
99
|
+
// not logic on key down
|
|
100
|
+
return () => {
|
|
101
|
+
// only execute logic on key up
|
|
102
|
+
console.log('Space key released')
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
left() {
|
|
106
|
+
// some logic on key down here ..
|
|
107
|
+
this.leftHold = true
|
|
108
|
+
// return a reference to a Component method
|
|
109
|
+
// (instead of creating a new function on the fly)
|
|
110
|
+
return this.leftKeyUp
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
methods: {
|
|
114
|
+
leftKeyUp() {
|
|
115
|
+
console.log('Left key up')
|
|
116
|
+
this.leftHold = false
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
76
122
|
## Custom Keycode mapping
|
|
77
123
|
|
|
78
124
|
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.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightningjs/blits",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Blits: The Lightning 3 App Development Framework",
|
|
5
5
|
"bin": "bin/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@lightningjs/msdf-generator": "^1.0.2",
|
|
50
|
-
"@lightningjs/renderer": "^2.
|
|
50
|
+
"@lightningjs/renderer": "^2.3.0",
|
|
51
51
|
"execa": "^8.0.1",
|
|
52
52
|
"kolorist": "^1.8.0",
|
|
53
53
|
"ora": "^7.0.1",
|
package/src/application.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import Component from './component.js'
|
|
19
|
-
import Focus from './focus.js'
|
|
19
|
+
import { default as Focus, keyUpCallbacks } from './focus.js'
|
|
20
20
|
import Settings from './settings.js'
|
|
21
21
|
|
|
22
22
|
import symbols from './lib/symbols.js'
|
|
@@ -65,7 +65,12 @@ const Application = (config) => {
|
|
|
65
65
|
}, Settings.get('holdTimeout', DEFAULT_HOLD_TIMEOUT_MS))
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
keyUpHandler = () => {
|
|
68
|
+
keyUpHandler = (e) => {
|
|
69
|
+
const cb = keyUpCallbacks.get(e.code)
|
|
70
|
+
if (cb !== undefined && typeof cb === 'function') {
|
|
71
|
+
keyUpCallbacks.delete(e.code)
|
|
72
|
+
cb()
|
|
73
|
+
}
|
|
69
74
|
clearTimeout(holdTimeout)
|
|
70
75
|
Focus.hold = false
|
|
71
76
|
}
|
|
@@ -268,7 +268,7 @@ const Element = {
|
|
|
268
268
|
|
|
269
269
|
this.props.element = this
|
|
270
270
|
|
|
271
|
-
this.props['parent'] = this.config.parent
|
|
271
|
+
this.props['parent'] = props['parent'] || this.config.parent
|
|
272
272
|
delete props.parent
|
|
273
273
|
|
|
274
274
|
this.props.raw = data
|
|
@@ -305,7 +305,7 @@ const Element = {
|
|
|
305
305
|
})
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
-
// if (this.component && this.component
|
|
308
|
+
// if (this.component !== undefined && '___layout' in this.component) {
|
|
309
309
|
// this.node.on('loaded', () => {
|
|
310
310
|
// this.component.___layout()
|
|
311
311
|
// })
|
|
@@ -344,16 +344,17 @@ const Element = {
|
|
|
344
344
|
// }
|
|
345
345
|
},
|
|
346
346
|
animate(prop, value, transition) {
|
|
347
|
+
// check if a transition is already scheduled to run on the same prop
|
|
348
|
+
// and cancels it if it does
|
|
349
|
+
if (
|
|
350
|
+
this.scheduledTransitions[prop] !== undefined &&
|
|
351
|
+
this.scheduledTransitions[prop].f.state === 'scheduled'
|
|
352
|
+
) {
|
|
353
|
+
this.scheduledTransitions[prop].f.stop()
|
|
354
|
+
}
|
|
355
|
+
|
|
347
356
|
// if current value is the same as the value to animate to, instantly resolve
|
|
348
357
|
if (this.node[prop] === value) return
|
|
349
|
-
// check if a transition is already scheduled or running on the same prop
|
|
350
|
-
if (this.scheduledTransitions[prop]) {
|
|
351
|
-
if (this.scheduledTransitions[prop].f.state === 'running') {
|
|
352
|
-
// fastforward to final value
|
|
353
|
-
this.node[prop] = this.scheduledTransitions[prop].v
|
|
354
|
-
// this.scheduledTransitions[prop].f.stop()
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
358
|
|
|
358
359
|
const props = {}
|
|
359
360
|
props[prop] = value
|
|
@@ -382,7 +383,6 @@ const Element = {
|
|
|
382
383
|
// removed if another transition for the same prop starts in the mean time
|
|
383
384
|
this.scheduledTransitions[prop] = {
|
|
384
385
|
v: props[prop],
|
|
385
|
-
cancel: false,
|
|
386
386
|
f,
|
|
387
387
|
}
|
|
388
388
|
|
|
@@ -395,7 +395,7 @@ const Element = {
|
|
|
395
395
|
|
|
396
396
|
f.once('stopped', () => {
|
|
397
397
|
// remove the prop from scheduled transitions
|
|
398
|
-
this.scheduledTransitions[prop] =
|
|
398
|
+
this.scheduledTransitions[prop] = undefined
|
|
399
399
|
// fire transition end callback when animation ends (if specified)
|
|
400
400
|
if (transition.end && typeof transition.end === 'function') {
|
|
401
401
|
transition.end.call(this.component, this, prop, this.node[prop])
|
package/src/engines/L3/launch.js
CHANGED
|
@@ -35,6 +35,13 @@ const renderEngine = (settings) => {
|
|
|
35
35
|
if (renderMode === 'canvas') return CanvasCoreRenderer
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
const textRenderEngines = (settings) => {
|
|
39
|
+
const renderMode = 'renderMode' in settings ? settings.renderMode : 'webgl'
|
|
40
|
+
|
|
41
|
+
if (renderMode === 'webgl') return [SdfTextRenderer, CanvasTextRenderer]
|
|
42
|
+
if (renderMode === 'canvas') return [CanvasTextRenderer]
|
|
43
|
+
}
|
|
44
|
+
|
|
38
45
|
export default (App, target, settings = {}) => {
|
|
39
46
|
renderer = new RendererMain(
|
|
40
47
|
{
|
|
@@ -57,7 +64,7 @@ export default (App, target, settings = {}) => {
|
|
|
57
64
|
txMemByteThreshold:
|
|
58
65
|
'gpuMemoryLimit' in settings ? settings.gpuMemoryLimit * 1024 * 1024 : 200 * 1024 * 1024,
|
|
59
66
|
renderEngine: renderEngine(settings),
|
|
60
|
-
fontEngines:
|
|
67
|
+
fontEngines: textRenderEngines(settings),
|
|
61
68
|
},
|
|
62
69
|
target
|
|
63
70
|
)
|
package/src/focus.js
CHANGED
|
@@ -24,6 +24,8 @@ let focusedComponent = null
|
|
|
24
24
|
let focusChain = []
|
|
25
25
|
let setFocusTimeout
|
|
26
26
|
|
|
27
|
+
export const keyUpCallbacks = new Map()
|
|
28
|
+
|
|
27
29
|
export default {
|
|
28
30
|
_hold: false,
|
|
29
31
|
set hold(v) {
|
|
@@ -60,10 +62,14 @@ export default {
|
|
|
60
62
|
const componentWithInputEvent = focusChain.shift()
|
|
61
63
|
|
|
62
64
|
if (componentWithInputEvent) {
|
|
65
|
+
let cb
|
|
63
66
|
if (componentWithInputEvent[symbols.inputEvents][key]) {
|
|
64
|
-
componentWithInputEvent[symbols.inputEvents][key].call(componentWithInputEvent, event)
|
|
67
|
+
cb = componentWithInputEvent[symbols.inputEvents][key].call(componentWithInputEvent, event)
|
|
65
68
|
} else if (componentWithInputEvent[symbols.inputEvents].any) {
|
|
66
|
-
componentWithInputEvent[symbols.inputEvents].any.call(componentWithInputEvent, event)
|
|
69
|
+
cb = componentWithInputEvent[symbols.inputEvents].any.call(componentWithInputEvent, event)
|
|
70
|
+
}
|
|
71
|
+
if (cb !== undefined) {
|
|
72
|
+
keyUpCallbacks.set(event.code, cb)
|
|
67
73
|
}
|
|
68
74
|
}
|
|
69
75
|
},
|
|
@@ -91,7 +91,7 @@ const generateElementCode = function (
|
|
|
91
91
|
Object.keys(templateObject).forEach((key) => {
|
|
92
92
|
if (key === 'slot') {
|
|
93
93
|
renderCode.push(`
|
|
94
|
-
elementConfig${counter}['parent'] = component[Symbol.for('slots')].filter(slot => slot.ref === '${templateObject.slot}').shift() ||
|
|
94
|
+
elementConfig${counter}['parent'] = component[Symbol.for('slots')].filter(slot => slot.ref === '${templateObject.slot}').shift() || parent
|
|
95
95
|
`)
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -258,6 +258,7 @@ const generateComponentCode = function (
|
|
|
258
258
|
}
|
|
259
259
|
// if (!options.forloop) {
|
|
260
260
|
// renderCode.push(`
|
|
261
|
+
// // console.log('here', component, rootComponent)
|
|
261
262
|
// component = rootComponent
|
|
262
263
|
// `)
|
|
263
264
|
// }
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* SPDX-License-Identifier: Apache-2.0
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import { ImageTexture } from '@lightningjs/renderer'
|
|
18
19
|
import { track, trigger, pauseTracking, resumeTracking } from './effect.js'
|
|
19
20
|
import symbols from '../symbols.js'
|
|
20
21
|
|
|
@@ -32,7 +33,7 @@ const reactiveProxy = (original, _parent = null, _key) => {
|
|
|
32
33
|
// is assigned to a state variable
|
|
33
34
|
if (typeof original === 'object') {
|
|
34
35
|
if (original[symbols.id] !== undefined) return original
|
|
35
|
-
if (original.constructor.name ===
|
|
36
|
+
if (original.constructor.name === ImageTexture.name) return original
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
// if original object is already a proxy, don't create a new one but return the existing one instead
|
package/src/plugins/appstate.js
CHANGED
|
@@ -16,10 +16,11 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { reactive } from '../lib/reactivity/reactive'
|
|
19
|
+
import Settings from '../settings.js'
|
|
19
20
|
|
|
20
21
|
export default {
|
|
21
22
|
name: 'appState',
|
|
22
23
|
plugin(state = {}) {
|
|
23
|
-
return reactive(state)
|
|
24
|
+
return reactive(state, Settings.get('reactivityMode'))
|
|
24
25
|
},
|
|
25
26
|
}
|
package/src/plugins/language.js
CHANGED
|
@@ -19,16 +19,21 @@ import fetchJson from '../helpers/fetchJson'
|
|
|
19
19
|
import { Log } from '../lib/log'
|
|
20
20
|
import { reactive } from '../lib/reactivity/reactive'
|
|
21
21
|
|
|
22
|
+
import Settings from '../settings.js'
|
|
23
|
+
|
|
22
24
|
export default {
|
|
23
25
|
name: 'language',
|
|
24
26
|
plugin(options = {}) {
|
|
25
27
|
let translations = {}
|
|
26
28
|
let dictionary = {}
|
|
27
29
|
|
|
28
|
-
const state = reactive(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
const state = reactive(
|
|
31
|
+
{
|
|
32
|
+
language: '',
|
|
33
|
+
loaded: 0,
|
|
34
|
+
},
|
|
35
|
+
Settings.get('reactivityMode')
|
|
36
|
+
)
|
|
32
37
|
|
|
33
38
|
const setLanguage = (language) => {
|
|
34
39
|
// define the dictionary
|
package/src/plugins/theme.js
CHANGED
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
import { Log } from '../lib/log'
|
|
19
19
|
import { reactive } from '../lib/reactivity/reactive.js'
|
|
20
20
|
|
|
21
|
+
import Settings from '../settings.js'
|
|
22
|
+
|
|
21
23
|
const getValueByDotNotation = (obj, base, path) => {
|
|
22
24
|
const keys = path.split('.')
|
|
23
25
|
|
|
@@ -46,9 +48,12 @@ export default {
|
|
|
46
48
|
plugin(config = {}) {
|
|
47
49
|
let themeMap = {}
|
|
48
50
|
|
|
49
|
-
const state = reactive(
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
const state = reactive(
|
|
52
|
+
{
|
|
53
|
+
current: 'default',
|
|
54
|
+
},
|
|
55
|
+
Settings.get('reactivityMode')
|
|
56
|
+
)
|
|
52
57
|
|
|
53
58
|
let themes = {}
|
|
54
59
|
let base = null
|