@lightningjs/blits 2.14.0 → 2.15.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 +15 -0
- package/index.d.ts +1507 -1481
- package/package.json +3 -3
- package/src/application.js +94 -19
- package/src/component/base/index.js +2 -0
- package/src/component/base/router.js +6 -2
- package/src/component/base/settings.js +68 -0
- package/src/component.js +3 -2
- package/src/components/FPScounter.js +30 -20
- package/src/engines/L3/index.js +39 -1
- package/src/engines/L3/launch.js +1 -15
- package/src/focus/focus.js +4 -0
- package/src/launch.js +10 -1
- package/src/router/router.js +14 -1
- package/src/settings.js +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightningjs/blits",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.0",
|
|
4
4
|
"description": "Blits: The Lightning 3 App Development Framework",
|
|
5
5
|
"bin": "bin/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"bench:compare": "npm --prefix benchmarks run bench:compare --",
|
|
71
71
|
"bench:profile": "npm --prefix benchmarks run bench:profile --",
|
|
72
72
|
"bench:serve": "npm --prefix benchmarks run serve",
|
|
73
|
-
"release": "
|
|
73
|
+
"release": "node scripts/release.js"
|
|
74
74
|
},
|
|
75
75
|
"types": "./index.d.ts",
|
|
76
76
|
"lint-staged": {
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"globals": "^17.12.0",
|
|
96
96
|
"husky": "^9.1.7",
|
|
97
97
|
"jsdom": "^30.1.0",
|
|
98
|
-
"lint-staged": "^
|
|
98
|
+
"lint-staged": "^17.6.0",
|
|
99
99
|
"prettier": "^3.6.2",
|
|
100
100
|
"sinon": "^22.1.0",
|
|
101
101
|
"tap-diff": "^0.1.1",
|
package/src/application.js
CHANGED
|
@@ -25,6 +25,55 @@ import { DEFAULT_HOLD_TIMEOUT_MS, DEFAULT_KEYMAP } from './constants.js'
|
|
|
25
25
|
import { renderer } from './launch.js'
|
|
26
26
|
import { platform } from './platform.js'
|
|
27
27
|
|
|
28
|
+
// Reacts to Blits-only settings changed at runtime via `this.$settings.set()`.
|
|
29
|
+
Settings.onRuntimeSettingChange = (key, value) => {
|
|
30
|
+
if (key === 'keymap') {
|
|
31
|
+
initKeyMap()
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (key === 'inputThrottle') {
|
|
36
|
+
inputThrottleMs = value
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (key === 'mouseMoveThrottle') {
|
|
41
|
+
mouseMoveThrottleMs = value
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (
|
|
46
|
+
key === 'announcerOptions' &&
|
|
47
|
+
liveAppInstance &&
|
|
48
|
+
liveAppInstance.$announcer &&
|
|
49
|
+
value &&
|
|
50
|
+
typeof value === 'object'
|
|
51
|
+
) {
|
|
52
|
+
liveAppInstance.$announcer.configure(value)
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (key === 'enableMouse') {
|
|
57
|
+
enableMouseFlag = value
|
|
58
|
+
if (liveInput !== null && liveViewport !== null) {
|
|
59
|
+
if (value === true && mouseListenersAttached === false) {
|
|
60
|
+
liveInput.addEventListener('mousemove', mouseMoveHandlerRef)
|
|
61
|
+
liveInput.addEventListener('click', mouseClickHandlerRef)
|
|
62
|
+
liveViewport.addEventListener('resize', updateCanvasRectRef)
|
|
63
|
+
liveViewport.addEventListener('scroll', updateCanvasRectRef)
|
|
64
|
+
mouseListenersAttached = true
|
|
65
|
+
} else if (value === false && mouseListenersAttached === true) {
|
|
66
|
+
liveInput.removeEventListener('mousemove', mouseMoveHandlerRef)
|
|
67
|
+
liveInput.removeEventListener('click', mouseClickHandlerRef)
|
|
68
|
+
liveViewport.removeEventListener('resize', updateCanvasRectRef)
|
|
69
|
+
liveViewport.removeEventListener('scroll', updateCanvasRectRef)
|
|
70
|
+
mouseListenersAttached = false
|
|
71
|
+
Hover.clear()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
28
77
|
/**
|
|
29
78
|
* Merged keyMap (default + custom settings).
|
|
30
79
|
* Initialized once during application init.
|
|
@@ -32,6 +81,24 @@ import { platform } from './platform.js'
|
|
|
32
81
|
*/
|
|
33
82
|
export let keyMap = {}
|
|
34
83
|
|
|
84
|
+
/** @type {any} Active App component instance, set during App init */
|
|
85
|
+
let liveAppInstance = null
|
|
86
|
+
/** @type {any} Platform input target, set during App init */
|
|
87
|
+
let liveInput = null
|
|
88
|
+
/** @type {any} Platform viewport target, set during App init */
|
|
89
|
+
let liveViewport = null
|
|
90
|
+
let mouseListenersAttached = false
|
|
91
|
+
/** @type {((e: any) => void)|null} */
|
|
92
|
+
let mouseMoveHandlerRef = null
|
|
93
|
+
/** @type {(() => void)|null} */
|
|
94
|
+
let mouseClickHandlerRef = null
|
|
95
|
+
/** @type {(() => void)|null} */
|
|
96
|
+
let updateCanvasRectRef = null
|
|
97
|
+
|
|
98
|
+
let inputThrottleMs = 0
|
|
99
|
+
let mouseMoveThrottleMs = 100
|
|
100
|
+
let enableMouseFlag = false
|
|
101
|
+
|
|
35
102
|
export const initKeyMap = () => {
|
|
36
103
|
keyMap = { ...DEFAULT_KEYMAP, ...Settings.get('keymap', {}) }
|
|
37
104
|
}
|
|
@@ -66,6 +133,7 @@ const Application = (config) => {
|
|
|
66
133
|
}
|
|
67
134
|
|
|
68
135
|
config.hooks[symbols.init] = function () {
|
|
136
|
+
liveAppInstance = this
|
|
69
137
|
// set the initial activation state of the announcer based on launch setting
|
|
70
138
|
this.$announcer.toggle(Settings.get('announcer', false))
|
|
71
139
|
// configure global default utterance options if provided in settings
|
|
@@ -75,15 +143,15 @@ const Application = (config) => {
|
|
|
75
143
|
}
|
|
76
144
|
// Initialize merged keyMap once during application init
|
|
77
145
|
initKeyMap()
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const mouseEnabled = Settings.get('enableMouse', false)
|
|
83
|
-
const mouseMoveThrottle = Settings.get('mouseMoveThrottle', 100)
|
|
146
|
+
// Initialize fast-path cached settings once during application init
|
|
147
|
+
inputThrottleMs = Settings.get('inputThrottle', 0)
|
|
148
|
+
mouseMoveThrottleMs = Settings.get('mouseMoveThrottle', 100)
|
|
149
|
+
enableMouseFlag = Settings.get('enableMouse', false)
|
|
84
150
|
const { createKeyboardEvent, input, isKeyboardEvent, now = Date.now, viewport } = platform
|
|
151
|
+
liveInput = input
|
|
152
|
+
liveViewport = viewport
|
|
85
153
|
|
|
86
|
-
keyDownHandler = async (e) => {
|
|
154
|
+
keyDownHandler = async (/** @type {any} */ e) => {
|
|
87
155
|
const currentTime = now()
|
|
88
156
|
|
|
89
157
|
const key = keyMap[e.keyCode] || e.keyCode
|
|
@@ -91,11 +159,11 @@ const Application = (config) => {
|
|
|
91
159
|
lastInputKey = key
|
|
92
160
|
// execute immediately when no throttle is specified or event is internal (bubbled up by focus manager)
|
|
93
161
|
// or key is different from the last used key
|
|
94
|
-
if (
|
|
162
|
+
if (inputThrottleMs === 0 || e[symbols.internalEvent] === true || sameKey === false) {
|
|
95
163
|
return await processInput.call(this, e, key)
|
|
96
164
|
}
|
|
97
165
|
|
|
98
|
-
if (currentTime - lastInputTime <
|
|
166
|
+
if (currentTime - lastInputTime < inputThrottleMs) {
|
|
99
167
|
return
|
|
100
168
|
}
|
|
101
169
|
|
|
@@ -115,7 +183,7 @@ const Application = (config) => {
|
|
|
115
183
|
}
|
|
116
184
|
|
|
117
185
|
Focus.input(key, e)
|
|
118
|
-
if (
|
|
186
|
+
if (enableMouseFlag === true) {
|
|
119
187
|
Hover.clear()
|
|
120
188
|
// forget the node under the pointer too, so moving on it hovers it again
|
|
121
189
|
currentNode = undefined
|
|
@@ -130,6 +198,9 @@ const Application = (config) => {
|
|
|
130
198
|
}
|
|
131
199
|
|
|
132
200
|
keyUpHandler = (e) => {
|
|
201
|
+
clearTimeout(holdTimeout)
|
|
202
|
+
Focus.hold = false
|
|
203
|
+
|
|
133
204
|
const entry = keyUpCallbacks.get(e.keyCode)
|
|
134
205
|
if (entry !== undefined) {
|
|
135
206
|
keyUpCallbacks.delete(e.keyCode)
|
|
@@ -137,8 +208,6 @@ const Application = (config) => {
|
|
|
137
208
|
entry.callback()
|
|
138
209
|
}
|
|
139
210
|
}
|
|
140
|
-
clearTimeout(holdTimeout)
|
|
141
|
-
Focus.hold = false
|
|
142
211
|
}
|
|
143
212
|
|
|
144
213
|
let lastMoved = 0
|
|
@@ -154,7 +223,7 @@ const Application = (config) => {
|
|
|
154
223
|
|
|
155
224
|
// limit the amount of move events per time frame
|
|
156
225
|
mouseMoveHandler = (e) => {
|
|
157
|
-
if (e.timeStamp - lastMoved <
|
|
226
|
+
if (e.timeStamp - lastMoved < mouseMoveThrottleMs) return
|
|
158
227
|
lastMoved = e.timeStamp
|
|
159
228
|
|
|
160
229
|
this.$emit('mouse::move', e)
|
|
@@ -166,7 +235,7 @@ const Application = (config) => {
|
|
|
166
235
|
return
|
|
167
236
|
}
|
|
168
237
|
|
|
169
|
-
const stage = renderer.stage
|
|
238
|
+
const stage = /** @type {any} */ (renderer).stage
|
|
170
239
|
if (stage == null) {
|
|
171
240
|
return
|
|
172
241
|
}
|
|
@@ -215,16 +284,21 @@ const Application = (config) => {
|
|
|
215
284
|
input.addEventListener('keydown', keyDownHandler)
|
|
216
285
|
input.addEventListener('keyup', keyUpHandler)
|
|
217
286
|
inputCleanup = () => {
|
|
218
|
-
input.removeEventListener('keydown', keyDownHandler)
|
|
219
|
-
input.removeEventListener('keyup', keyUpHandler)
|
|
287
|
+
input.removeEventListener('keydown', /** @type {any} */ (keyDownHandler))
|
|
288
|
+
input.removeEventListener('keyup', /** @type {any} */ (keyUpHandler))
|
|
220
289
|
}
|
|
221
290
|
}
|
|
222
|
-
|
|
291
|
+
mouseMoveHandlerRef = mouseMoveHandler
|
|
292
|
+
mouseClickHandlerRef = mouseClickHandler
|
|
293
|
+
updateCanvasRectRef = updateCanvasRect
|
|
294
|
+
|
|
295
|
+
if (enableMouseFlag === true && input !== undefined && viewport !== undefined) {
|
|
223
296
|
updateCanvasRect()
|
|
224
297
|
input.addEventListener('mousemove', mouseMoveHandler)
|
|
225
298
|
input.addEventListener('click', mouseClickHandler)
|
|
226
299
|
viewport.addEventListener('resize', updateCanvasRect)
|
|
227
300
|
viewport.addEventListener('scroll', updateCanvasRect)
|
|
301
|
+
mouseListenersAttached = true
|
|
228
302
|
mouseCleanup = () => {
|
|
229
303
|
input.removeEventListener('mousemove', mouseMoveHandler)
|
|
230
304
|
input.removeEventListener('click', mouseClickHandler)
|
|
@@ -233,8 +307,9 @@ const Application = (config) => {
|
|
|
233
307
|
}
|
|
234
308
|
}
|
|
235
309
|
|
|
236
|
-
//
|
|
237
|
-
|
|
310
|
+
// focus once the component tree is built (microtask: runs right after the
|
|
311
|
+
// current instantiation finishes, without yielding to render-loop frames)
|
|
312
|
+
Promise.resolve().then(() => Focus.set(this))
|
|
238
313
|
}
|
|
239
314
|
|
|
240
315
|
return Component('App', config)
|
|
@@ -21,6 +21,7 @@ import events from './events.js'
|
|
|
21
21
|
import router from './router.js'
|
|
22
22
|
import announcer from './announcer.js'
|
|
23
23
|
import utils from './utils.js'
|
|
24
|
+
import settings from './settings.js'
|
|
24
25
|
import symbols from '../../lib/symbols.js'
|
|
25
26
|
import { reactive } from '../../lib/reactivity/reactive.js'
|
|
26
27
|
import Settings from '../../settings.js'
|
|
@@ -29,6 +30,7 @@ export const shared = {
|
|
|
29
30
|
...events,
|
|
30
31
|
...router,
|
|
31
32
|
...announcer,
|
|
33
|
+
...settings,
|
|
32
34
|
$reactive: {
|
|
33
35
|
value: function (target) {
|
|
34
36
|
return reactive(target, Settings.get('reactivityMode'), true)
|
|
@@ -149,9 +149,9 @@ const createRouter = (component, routerViewName) => {
|
|
|
149
149
|
toRouterView(routerView, path, data, options)
|
|
150
150
|
return true
|
|
151
151
|
},
|
|
152
|
-
back() {
|
|
152
|
+
back(steps = 1) {
|
|
153
153
|
const routerView = resolveRouterView(component, routerViewName)
|
|
154
|
-
return routerView === null ? false : back.call(routerView)
|
|
154
|
+
return routerView === null ? false : back.call(routerView, steps)
|
|
155
155
|
},
|
|
156
156
|
get(name) {
|
|
157
157
|
return getRouterFromCache(component, name)
|
|
@@ -172,6 +172,10 @@ const createRouter = (component, routerViewName) => {
|
|
|
172
172
|
get navigating() {
|
|
173
173
|
return state.navigating
|
|
174
174
|
},
|
|
175
|
+
get history() {
|
|
176
|
+
const routerView = resolveRouterView(component, routerViewName)
|
|
177
|
+
return routerView === null ? [] : routerView.history.slice()
|
|
178
|
+
},
|
|
175
179
|
state,
|
|
176
180
|
}
|
|
177
181
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 Comcast Cable Communications Management, LLC
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License.
|
|
5
|
+
* You may obtain a copy of the License at
|
|
6
|
+
*
|
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
* See the License for the specific language governing permissions and
|
|
13
|
+
* limitations under the License.
|
|
14
|
+
*
|
|
15
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import Settings from '../../settings.js'
|
|
19
|
+
import engine from '../../engine.js'
|
|
20
|
+
import { Log } from '../../lib/log.js'
|
|
21
|
+
|
|
22
|
+
// Settings that can be changed at runtime via `this.$settings.set()`.
|
|
23
|
+
const blitsKeys = [
|
|
24
|
+
'keymap',
|
|
25
|
+
'debugLevel',
|
|
26
|
+
'inputThrottle',
|
|
27
|
+
'announcerOptions',
|
|
28
|
+
'enableMouse',
|
|
29
|
+
'mouseMoveThrottle',
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
const rendererKeys = [
|
|
33
|
+
'w',
|
|
34
|
+
'h',
|
|
35
|
+
'screenResolution',
|
|
36
|
+
'renderQuality',
|
|
37
|
+
'pixelRatio',
|
|
38
|
+
'canvasColor',
|
|
39
|
+
'viewportMargin',
|
|
40
|
+
'maxFPS',
|
|
41
|
+
'fpsInterval',
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
const changeableKeys = [...blitsKeys, ...rendererKeys]
|
|
45
|
+
|
|
46
|
+
export default {
|
|
47
|
+
$settings: {
|
|
48
|
+
value: {
|
|
49
|
+
get(key, defaultValue) {
|
|
50
|
+
return Settings.get(key, defaultValue)
|
|
51
|
+
},
|
|
52
|
+
set(key, value) {
|
|
53
|
+
if (changeableKeys.indexOf(key) === -1) {
|
|
54
|
+
Log.warn(`Setting "${key}" can not be changed at runtime`)
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
Settings.set(key, value)
|
|
58
|
+
|
|
59
|
+
if (rendererKeys.indexOf(key) !== -1) {
|
|
60
|
+
engine.updateSetting(key, value)
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
writable: false,
|
|
65
|
+
enumerable: true,
|
|
66
|
+
configurable: false,
|
|
67
|
+
},
|
|
68
|
+
}
|
package/src/component.js
CHANGED
|
@@ -426,8 +426,9 @@ const Component = (name = required('name'), config = required('config')) => {
|
|
|
426
426
|
}
|
|
427
427
|
}
|
|
428
428
|
|
|
429
|
-
//
|
|
430
|
-
|
|
429
|
+
// finally set the lifecycle state to ready (synchronously: instantiation,
|
|
430
|
+
// reactivity setup and template spawn are all complete at this point)
|
|
431
|
+
this[symbols.lifecycle].state = 'ready'
|
|
431
432
|
|
|
432
433
|
// and return this
|
|
433
434
|
return this
|
|
@@ -16,11 +16,15 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import Blits from '../../index.js'
|
|
19
|
-
import { renderer } from '../launch.js'
|
|
20
19
|
import fps_sprite from '../../public/assets/fps_sprite.base64.js'
|
|
21
20
|
|
|
22
21
|
// exporting as named export to allow selective importing
|
|
23
22
|
export const FPScounter = Blits.Component('FPScounter', {
|
|
23
|
+
props: {
|
|
24
|
+
active: true,
|
|
25
|
+
show: true,
|
|
26
|
+
alpha: 1,
|
|
27
|
+
},
|
|
24
28
|
/* eslint-disable no-unused-vars */
|
|
25
29
|
code: {
|
|
26
30
|
render: function anonymous(parent, component, context, components, effect, getRaw, Log) {
|
|
@@ -662,28 +666,34 @@ export const FPScounter = Blits.Component('FPScounter', {
|
|
|
662
666
|
avgFps: '---',
|
|
663
667
|
minFps: '---',
|
|
664
668
|
maxFps: '---',
|
|
669
|
+
|
|
670
|
+
data: {
|
|
671
|
+
minFps: 10000,
|
|
672
|
+
maxFps: 0,
|
|
673
|
+
totalFps: 0,
|
|
674
|
+
fpsUpdateCounter: 0,
|
|
675
|
+
avgFps: 0,
|
|
676
|
+
},
|
|
665
677
|
}
|
|
666
678
|
},
|
|
667
679
|
hooks: {
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
this.maxFps = maxFps.toString().padStart(3, '0')
|
|
686
|
-
})
|
|
680
|
+
/**
|
|
681
|
+
* @param {number} fps
|
|
682
|
+
*/
|
|
683
|
+
fpsUpdate(fps) {
|
|
684
|
+
// early return when not active or hidden
|
|
685
|
+
if (!this.active || !this.show || this.alpha === 0) return
|
|
686
|
+
|
|
687
|
+
this.data.minFps = Math.min(fps, this.data.minFps)
|
|
688
|
+
this.data.maxFps = Math.max(fps, this.data.maxFps)
|
|
689
|
+
this.data.totalFps += fps
|
|
690
|
+
this.data.fpsUpdateCounter++
|
|
691
|
+
this.data.avgFps = Math.round(this.data.totalFps / this.data.fpsUpdateCounter)
|
|
692
|
+
|
|
693
|
+
this.fps = fps.toString().padStart(3, '0')
|
|
694
|
+
this.avgFps = this.data.avgFps.toString().padStart(3, '0')
|
|
695
|
+
this.minFps = this.data.minFps.toString().padStart(3, '0')
|
|
696
|
+
this.maxFps = this.data.maxFps.toString().padStart(3, '0')
|
|
687
697
|
},
|
|
688
698
|
},
|
|
689
699
|
})
|
package/src/engines/L3/index.js
CHANGED
|
@@ -16,9 +16,47 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import Element from './element.js'
|
|
19
|
-
import Launch from './launch.js'
|
|
19
|
+
import Launch, { renderer } from './launch.js'
|
|
20
|
+
import colors from '../../lib/colors/colors.js'
|
|
21
|
+
import { SCREEN_RESOLUTIONS, RENDER_QUALITIES } from '../../constants.js'
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Maps Blits setting keys to renderer runtime options
|
|
25
|
+
*
|
|
26
|
+
* @type {Record<string, (value: any) => Partial<import('@lightningjs/renderer').RendererRuntimeSettings>>}
|
|
27
|
+
*/
|
|
28
|
+
const rendererOptions = {
|
|
29
|
+
// defaults to transparent (same as on launch) for empty or invalid colors
|
|
30
|
+
w: (v) => ({ appWidth: v }),
|
|
31
|
+
h: (v) => ({ appHeight: v }),
|
|
32
|
+
screenResolution: (v) => ({
|
|
33
|
+
deviceLogicalPixelRatio: typeof v === 'string' ? (SCREEN_RESOLUTIONS[v] ?? 1) : v,
|
|
34
|
+
}),
|
|
35
|
+
renderQuality: (v) => ({
|
|
36
|
+
devicePhysicalPixelRatio: RENDER_QUALITIES[v] ?? v ?? 1,
|
|
37
|
+
}),
|
|
38
|
+
canvasColor: (v) => ({ clearColor: Number(colors.normalize(v ?? '', '0x00000000')) }),
|
|
39
|
+
fpsInterval: (v) => ({ fpsUpdateInterval: v }),
|
|
40
|
+
pixelRatio: (v) => ({ deviceLogicalPixelRatio: v }),
|
|
41
|
+
viewportMargin: (v) => ({ boundsMargin: v }),
|
|
42
|
+
maxFPS: (v) => ({ targetFPS: v }),
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Applies a runtime setting to the renderer via RendererMain.setOptions()
|
|
47
|
+
*
|
|
48
|
+
* @param {string} key - Blits setting key (validated by $settings)
|
|
49
|
+
* @param {any} value - New value
|
|
50
|
+
*/
|
|
51
|
+
const updateSetting = (key, value) => {
|
|
52
|
+
const rendererInstance = renderer
|
|
53
|
+
if (rendererInstance && typeof rendererInstance.setOptions === 'function') {
|
|
54
|
+
rendererInstance.setOptions(rendererOptions[key](value))
|
|
55
|
+
}
|
|
56
|
+
}
|
|
20
57
|
|
|
21
58
|
export default {
|
|
22
59
|
Element,
|
|
23
60
|
Launch,
|
|
61
|
+
updateSetting,
|
|
24
62
|
}
|
package/src/engines/L3/launch.js
CHANGED
|
@@ -20,7 +20,6 @@ import { WebGlCoreRenderer, SdfTextRenderer } from '@lightningjs/renderer/webgl'
|
|
|
20
20
|
import { CanvasCoreRenderer, CanvasTextRenderer } from '@lightningjs/renderer/canvas'
|
|
21
21
|
import { Inspector } from '@lightningjs/renderer/inspector'
|
|
22
22
|
|
|
23
|
-
import { Log } from '../../lib/log.js'
|
|
24
23
|
import { SCREEN_RESOLUTIONS, RENDER_QUALITIES } from '../../constants.js'
|
|
25
24
|
import colors from '../../lib/colors/colors.js'
|
|
26
25
|
import fontLoader from './fontLoader.js'
|
|
@@ -85,7 +84,7 @@ const textureMemorySettings = (settings) => {
|
|
|
85
84
|
* @param {Partial<import('../../launch.js').BlitsSettings>} [settings] - The settings for the renderer
|
|
86
85
|
*
|
|
87
86
|
*/
|
|
88
|
-
export default (
|
|
87
|
+
export default (target, settings = {}) => {
|
|
89
88
|
const screenHeight = settings.platform ? settings.platform.screenHeight : platform.screenHeight
|
|
90
89
|
const hardwareConcurrency = settings.platform
|
|
91
90
|
? settings.platform.hardwareConcurrency
|
|
@@ -125,21 +124,8 @@ export default (App, target, settings = {}) => {
|
|
|
125
124
|
target
|
|
126
125
|
)
|
|
127
126
|
|
|
128
|
-
const initApp = () => {
|
|
129
|
-
let app = App()
|
|
130
|
-
app.quit = () => {
|
|
131
|
-
Log.info('Closing App')
|
|
132
|
-
app.destroy()
|
|
133
|
-
app = null
|
|
134
|
-
renderer = null
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
127
|
shaderLoader()
|
|
139
128
|
fontLoader()
|
|
140
|
-
// Defer app initialization until after the current call stack is cleared,
|
|
141
|
-
// allowing the renderer to finish setting up before the app starts creating components
|
|
142
|
-
Promise.resolve().then(initApp)
|
|
143
129
|
|
|
144
130
|
return renderer
|
|
145
131
|
}
|
package/src/focus/focus.js
CHANGED
|
@@ -68,6 +68,10 @@ export default {
|
|
|
68
68
|
while (i--) {
|
|
69
69
|
// don't unfocus when part of the new focus chain
|
|
70
70
|
if (newFocusChain.indexOf(focusChain[i]) > -1) break
|
|
71
|
+
// only unfocus components that actually have focus
|
|
72
|
+
// ($hasFocus, not the lifecycle state which is shared with hover/enter/exit)
|
|
73
|
+
const componentState = focusChain[i][symbols.state]
|
|
74
|
+
if (componentState !== undefined && componentState.$hasFocus === false) continue
|
|
71
75
|
focusChain[i][symbols.lifecycle].state = 'unfocus'
|
|
72
76
|
}
|
|
73
77
|
focusChain = newFocusChain
|
package/src/launch.js
CHANGED
|
@@ -155,8 +155,17 @@ export default (App, target, settings) => {
|
|
|
155
155
|
|
|
156
156
|
stage.element = engine.Element
|
|
157
157
|
|
|
158
|
-
renderer = engine.Launch(
|
|
158
|
+
renderer = engine.Launch(target, settings)
|
|
159
159
|
if (isDev === true) {
|
|
160
160
|
profiler.setRenderer(renderer)
|
|
161
161
|
}
|
|
162
|
+
|
|
163
|
+
// Instantiate the app and wire up the quit function
|
|
164
|
+
let app = App()
|
|
165
|
+
app.quit = () => {
|
|
166
|
+
Log.info('Closing App')
|
|
167
|
+
app.destroy()
|
|
168
|
+
app = null
|
|
169
|
+
renderer = null
|
|
170
|
+
}
|
|
162
171
|
}
|
package/src/router/router.js
CHANGED
|
@@ -590,9 +590,22 @@ export const getSingleRegisteredRouterView = () => {
|
|
|
590
590
|
return singleRouterView
|
|
591
591
|
}
|
|
592
592
|
|
|
593
|
-
export const back = function () {
|
|
593
|
+
export const back = function (steps = 1) {
|
|
594
594
|
if (this.history === undefined) return
|
|
595
|
+
if (steps < 1) steps = 1
|
|
596
|
+
if (steps > this.history.length) steps = this.history.length
|
|
595
597
|
const viewState = getViewState(this.name)
|
|
598
|
+
|
|
599
|
+
// discard the intermediate history entries when navigating back more than 1 step
|
|
600
|
+
for (let i = 1; i < steps; i++) {
|
|
601
|
+
const poppedRoute = this.history.pop()
|
|
602
|
+
// if skipped history item is configured as keepAlive true then invoke destroy on view
|
|
603
|
+
if (poppedRoute.view !== undefined && poppedRoute.view !== null) {
|
|
604
|
+
poppedRoute.view.destroy()
|
|
605
|
+
poppedRoute.focus = null
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
596
609
|
const route = this.history.pop()
|
|
597
610
|
if (route && this.currentRoute !== route) {
|
|
598
611
|
// set indicator that we are navigating back (to prevent adding page to history stack)
|
package/src/settings.js
CHANGED
|
@@ -19,6 +19,8 @@ import symbols from './lib/symbols.js'
|
|
|
19
19
|
|
|
20
20
|
const settings = {
|
|
21
21
|
[symbols.settings]: {},
|
|
22
|
+
// Reacts to Blits-only settings changed at runtime via `this.$settings.set()`.
|
|
23
|
+
onRuntimeSettingChange: null,
|
|
22
24
|
get(key, defaultValue = null) {
|
|
23
25
|
if (key in this[symbols.settings]) {
|
|
24
26
|
return this[symbols.settings][key]
|
|
@@ -33,6 +35,9 @@ const settings = {
|
|
|
33
35
|
})
|
|
34
36
|
} else {
|
|
35
37
|
this[symbols.settings][key] = value
|
|
38
|
+
if (typeof this.onRuntimeSettingChange === 'function') {
|
|
39
|
+
this.onRuntimeSettingChange(key, value)
|
|
40
|
+
}
|
|
36
41
|
}
|
|
37
42
|
},
|
|
38
43
|
}
|