@lightningjs/blits 1.4.3 → 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 CHANGED
@@ -1,5 +1,13 @@
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
+
3
11
  ## v1.4.3
4
12
 
5
13
  _26 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.4.3",
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.2.0",
50
+ "@lightningjs/renderer": "^2.3.0",
51
51
  "execa": "^8.0.1",
52
52
  "kolorist": "^1.8.0",
53
53
  "ora": "^7.0.1",
@@ -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
  }
@@ -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] = null
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])
@@ -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: [SdfTextRenderer, CanvasTextRenderer],
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
  },