@lightningjs/blits 1.43.2 → 1.44.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,14 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.44.0
4
+
5
+ _20 Nov 2025_
6
+
7
+ - Added `$input` method to facilitate key handling _without_ also passing focus
8
+ - Added support for passing `type` of image in the `src`-attribute (`regular`, `svg`, `compressed` for cases the file type can't be derived from the file name)
9
+ - Bumped Lightning renderer to v2.20.0 with improved support for compressed textures
10
+
11
+
3
12
  ## v1.43.2
4
13
 
5
14
  _13 Nov 2025_
package/index.d.ts CHANGED
@@ -431,6 +431,12 @@ declare module '@lightningjs/blits' {
431
431
  * Set focus to the Component, optionally pass a KeyboardEvent for instant event bubbling
432
432
  */
433
433
  $focus: (event?: KeyboardEvent) => void
434
+ /**
435
+ * Handle a keyboard event on this component without changing focus
436
+ * @param event - The keyboard event to handle
437
+ * @returns Returns true if this component or a parent component handled the event, false otherwise
438
+ */
439
+ $input: (event: KeyboardEvent) => boolean
434
440
  /**
435
441
  * @deprecated
436
442
  * Deprecated: use `this.$focus()` instead
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightningjs/blits",
3
- "version": "1.43.2",
3
+ "version": "1.44.0",
4
4
  "description": "Blits: The Lightning 3 App Development Framework",
5
5
  "bin": "bin/index.js",
6
6
  "exports": {
@@ -55,7 +55,7 @@
55
55
  },
56
56
  "dependencies": {
57
57
  "@lightningjs/msdf-generator": "^1.2.0",
58
- "@lightningjs/renderer": "^2.19.1"
58
+ "@lightningjs/renderer": "^2.20.0"
59
59
  },
60
60
  "repository": {
61
61
  "type": "git",
@@ -20,28 +20,16 @@ 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'
23
- import { DEFAULT_HOLD_TIMEOUT_MS } from './constants.js'
23
+ import { DEFAULT_HOLD_TIMEOUT_MS, DEFAULT_KEYMAP } from './constants.js'
24
24
 
25
- const Application = (config) => {
26
- const defaultKeyMap = {
27
- ArrowLeft: 'left',
28
- ArrowRight: 'right',
29
- ArrowUp: 'up',
30
- ArrowDown: 'down',
31
- Enter: 'enter',
32
- ' ': 'space',
33
- Backspace: 'back',
34
- Escape: 'escape',
35
- 37: 'left',
36
- 39: 'right',
37
- 38: 'up',
38
- 40: 'down',
39
- 13: 'enter',
40
- 32: 'space',
41
- 8: 'back',
42
- 27: 'escape',
43
- }
25
+ /**
26
+ * Merged keyMap (default + custom settings).
27
+ * Initialized once during application init.
28
+ * @type {Object<string, string>}
29
+ */
30
+ export let keyMap = {}
44
31
 
32
+ const Application = (config) => {
45
33
  config.hooks = config.hooks || {}
46
34
 
47
35
  let keyDownHandler
@@ -63,7 +51,8 @@ const Application = (config) => {
63
51
  if (announcerOptions && typeof announcerOptions === 'object') {
64
52
  this.$announcer.configure(announcerOptions)
65
53
  }
66
- const keyMap = { ...defaultKeyMap, ...Settings.get('keymap', {}) }
54
+ // Initialize merged keyMap once during application init
55
+ keyMap = { ...DEFAULT_KEYMAP, ...Settings.get('keymap', {}) }
67
56
 
68
57
  /** @type {number} Input throttle time in milliseconds (0 = disabled) */
69
58
  const throttleMs = Settings.get('inputThrottle', 0)
@@ -17,11 +17,13 @@
17
17
 
18
18
  import symbols from '../../lib/symbols.js'
19
19
  import Focus from '../../focus.js'
20
+ import { keyUpCallbacks, getComponentWithInputEvent } from '../../focus.js'
20
21
  import eventListeners from '../../lib/eventListeners.js'
21
22
  import { trigger } from '../../lib/reactivity/effect.js'
22
23
  import { Log } from '../../lib/log.js'
23
24
  import { removeGlobalEffects } from '../../lib/reactivity/effect.js'
24
25
  import { renderer } from '../../launch.js'
26
+ import { keyMap } from '../../application.js'
25
27
 
26
28
  export default {
27
29
  focus: {
@@ -51,6 +53,41 @@ export default {
51
53
  enumerable: true,
52
54
  configurable: false,
53
55
  },
56
+ $input: {
57
+ /**
58
+ * Handle a keyboard event on this component without changing focus
59
+ * @this {import('../../component').BlitsComponent}
60
+ * @param {KeyboardEvent} event - The keyboard event to handle
61
+ * @returns {boolean} - Returns true if this component or a parent component handled the event, false otherwise
62
+ */
63
+ value: function (event) {
64
+ if (event === null || event === undefined || event instanceof KeyboardEvent === false)
65
+ return false
66
+
67
+ const key = keyMap[event.key] || keyMap[event.keyCode] || event.key || event.keyCode
68
+
69
+ const componentWithInputEvent = getComponentWithInputEvent(this, key)
70
+ if (componentWithInputEvent === null) return false
71
+
72
+ const inputEvents = componentWithInputEvent[symbols.inputEvents] || {}
73
+
74
+ let cb
75
+ if (inputEvents[key]) {
76
+ cb = inputEvents[key].call(componentWithInputEvent, event)
77
+ } else if (inputEvents.any) {
78
+ cb = inputEvents.any.call(componentWithInputEvent, event)
79
+ }
80
+
81
+ if (cb !== undefined && event.code) {
82
+ keyUpCallbacks.set(event.code, cb)
83
+ }
84
+
85
+ return true
86
+ },
87
+ writable: false,
88
+ enumerable: true,
89
+ configurable: false,
90
+ },
54
91
  unfocus: {
55
92
  /**
56
93
  * @this {import('../../component').BlitsComponent}
package/src/constants.js CHANGED
@@ -1,5 +1,24 @@
1
1
  export const DEFAULT_HOLD_TIMEOUT_MS = 50
2
2
 
3
+ export const DEFAULT_KEYMAP = {
4
+ ArrowLeft: 'left',
5
+ ArrowRight: 'right',
6
+ ArrowUp: 'up',
7
+ ArrowDown: 'down',
8
+ Enter: 'enter',
9
+ ' ': 'space',
10
+ Backspace: 'back',
11
+ Escape: 'escape',
12
+ 37: 'left',
13
+ 39: 'right',
14
+ 38: 'up',
15
+ 40: 'down',
16
+ 13: 'enter',
17
+ 32: 'space',
18
+ 8: 'back',
19
+ 27: 'escape',
20
+ }
21
+
3
22
  export const SCREEN_RESOLUTIONS = {
4
23
  hd: 0.66666667,
5
24
  '720p': 0.66666667,
@@ -168,7 +168,7 @@ const isObjectString = (str) => {
168
168
  * @returns {object} The parsed object.
169
169
  */
170
170
  const parseToObject = (str) => {
171
- return JSON.parse(str.replace(/'/g, '"').replace(/([\w-_]+)\s*:/g, '"$1":'))
171
+ return JSON.parse(str.replace(/'/g, '"').replace(/([{,]\s*)([\w-_]+)(\s*:)/g, '$1"$2"$3'))
172
172
  }
173
173
 
174
174
  /**
@@ -276,7 +276,13 @@ const propsTransformer = {
276
276
  }
277
277
  },
278
278
  set src(v) {
279
- this.props['src'] = v
279
+ if (typeof v === 'object' || (isObjectString(v) === true && (v = parseToObject(v)))) {
280
+ this.props['src'] = v.src
281
+ this.props['imageType'] = v.type
282
+ } else {
283
+ this.props['src'] = v
284
+ }
285
+
280
286
  if (this.raw['color'] === undefined) {
281
287
  this.props['color'] = this.props['src'] ? 0xffffffff : 0x00000000
282
288
  }
package/src/focus.js CHANGED
@@ -118,7 +118,7 @@ const getAncestors = (components) => {
118
118
  * @param {String} key
119
119
  * @returns component
120
120
  */
121
- const getComponentWithInputEvent = (component, key) => {
121
+ export const getComponentWithInputEvent = (component, key) => {
122
122
  if (
123
123
  component[symbols.inputEvents] &&
124
124
  (typeof component[symbols.inputEvents][key] === 'function' ||