@lightningjs/blits 2.14.0 → 2.16.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 +27 -0
- package/eslint.config.cjs +2 -0
- package/index.d.ts +1510 -1481
- package/package.json +6 -6
- package/src/application.js +98 -26
- package/src/component/base/index.js +2 -0
- package/src/component/base/methods.js +1 -1
- package/src/component/base/router.js +6 -2
- package/src/component/base/settings.js +68 -0
- package/src/component/setup/computed.js +5 -1
- package/src/component.js +23 -7
- package/src/components/Circle.js +2 -1
- package/src/components/FPScounter.js +32 -21
- package/src/components/RouterView.js +2 -1
- package/src/engines/L3/element.js +1 -1
- 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/keymap.js +27 -0
- package/src/launch.js +18 -20
- package/src/lib/codegenerator/generator.js +25 -2
- package/src/lib/hooks.js +4 -0
- package/src/lib/precompiler/precompiler.js +26 -1
- package/src/lib/reactivity/effect.js +140 -14
- package/src/lib/reactivity/reactive.js +11 -4
- package/src/router/router.js +20 -3
- package/src/settings.js +5 -0
- package/vite/index.js +3 -0
- package/vite/injectVersions.js +58 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightningjs/blits",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.16.0",
|
|
4
4
|
"description": "Blits: The Lightning 3 App Development Framework",
|
|
5
5
|
"bin": "bin/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"test": "c8 npm run test:run | tap-diff",
|
|
61
|
-
"test:run": "node -r global-jsdom/register node_modules/tape/bin/tape \"scripts/**/*.test.js\" \"src/**/*.test.js\"",
|
|
62
|
-
"test:run:failures": "node -r global-jsdom/register node_modules/tape/bin/tape \"scripts/**/*.test.js\" \"src/**/*.test.js\" | tap-filter test-fail | tap-diff",
|
|
61
|
+
"test:run": "node -r global-jsdom/register node_modules/tape/bin/tape \"scripts/**/*.test.js\" \"src/**/*.test.js\" \"vite/**/*.test.js\"",
|
|
62
|
+
"test:run:failures": "node -r global-jsdom/register node_modules/tape/bin/tape \"scripts/**/*.test.js\" \"src/**/*.test.js\" \"vite/**/*.test.js\" | tap-filter test-fail | tap-diff",
|
|
63
63
|
"lint": "node scripts/lint.js",
|
|
64
64
|
"lint:fix": "node scripts/lint.js fix",
|
|
65
65
|
"prepublishOnly": "node scripts/prepublishOnly.js",
|
|
@@ -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",
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
"tape": "^5.9.0"
|
|
104
104
|
},
|
|
105
105
|
"dependencies": {
|
|
106
|
-
"@lightningjs/renderer": "
|
|
106
|
+
"@lightningjs/renderer": "3.11.0",
|
|
107
107
|
"magic-string": "^1.4.1"
|
|
108
108
|
},
|
|
109
109
|
"repository": {
|
package/src/application.js
CHANGED
|
@@ -24,16 +24,79 @@ import symbols from './lib/symbols.js'
|
|
|
24
24
|
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
|
+
import { keyMap, setKeyMap } from './keymap.js'
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
export { keyMap } from './keymap.js'
|
|
30
|
+
|
|
31
|
+
// Reacts to Blits-only settings changed at runtime via `this.$settings.set()`.
|
|
32
|
+
Settings.onRuntimeSettingChange = (key, value) => {
|
|
33
|
+
if (key === 'keymap') {
|
|
34
|
+
initKeyMap()
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (key === 'inputThrottle') {
|
|
39
|
+
inputThrottleMs = value
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (key === 'mouseMoveThrottle') {
|
|
44
|
+
mouseMoveThrottleMs = value
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (
|
|
49
|
+
key === 'announcerOptions' &&
|
|
50
|
+
liveAppInstance &&
|
|
51
|
+
liveAppInstance.$announcer &&
|
|
52
|
+
value &&
|
|
53
|
+
typeof value === 'object'
|
|
54
|
+
) {
|
|
55
|
+
liveAppInstance.$announcer.configure(value)
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (key === 'enableMouse') {
|
|
60
|
+
enableMouseFlag = value
|
|
61
|
+
if (liveInput !== null && liveViewport !== null) {
|
|
62
|
+
if (value === true && mouseListenersAttached === false) {
|
|
63
|
+
liveInput.addEventListener('mousemove', mouseMoveHandlerRef)
|
|
64
|
+
liveInput.addEventListener('click', mouseClickHandlerRef)
|
|
65
|
+
liveViewport.addEventListener('resize', updateCanvasRectRef)
|
|
66
|
+
liveViewport.addEventListener('scroll', updateCanvasRectRef)
|
|
67
|
+
mouseListenersAttached = true
|
|
68
|
+
} else if (value === false && mouseListenersAttached === true) {
|
|
69
|
+
liveInput.removeEventListener('mousemove', mouseMoveHandlerRef)
|
|
70
|
+
liveInput.removeEventListener('click', mouseClickHandlerRef)
|
|
71
|
+
liveViewport.removeEventListener('resize', updateCanvasRectRef)
|
|
72
|
+
liveViewport.removeEventListener('scroll', updateCanvasRectRef)
|
|
73
|
+
mouseListenersAttached = false
|
|
74
|
+
Hover.clear()
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** @type {any} Active App component instance, set during App init */
|
|
81
|
+
let liveAppInstance = null
|
|
82
|
+
/** @type {any} Platform input target, set during App init */
|
|
83
|
+
let liveInput = null
|
|
84
|
+
/** @type {any} Platform viewport target, set during App init */
|
|
85
|
+
let liveViewport = null
|
|
86
|
+
let mouseListenersAttached = false
|
|
87
|
+
/** @type {((e: any) => void)|null} */
|
|
88
|
+
let mouseMoveHandlerRef = null
|
|
89
|
+
/** @type {(() => void)|null} */
|
|
90
|
+
let mouseClickHandlerRef = null
|
|
91
|
+
/** @type {(() => void)|null} */
|
|
92
|
+
let updateCanvasRectRef = null
|
|
93
|
+
|
|
94
|
+
let inputThrottleMs = 0
|
|
95
|
+
let mouseMoveThrottleMs = 100
|
|
96
|
+
let enableMouseFlag = false
|
|
34
97
|
|
|
35
98
|
export const initKeyMap = () => {
|
|
36
|
-
|
|
99
|
+
setKeyMap({ ...DEFAULT_KEYMAP, ...Settings.get('keymap', {}) })
|
|
37
100
|
}
|
|
38
101
|
|
|
39
102
|
const Application = (config) => {
|
|
@@ -66,6 +129,7 @@ const Application = (config) => {
|
|
|
66
129
|
}
|
|
67
130
|
|
|
68
131
|
config.hooks[symbols.init] = function () {
|
|
132
|
+
liveAppInstance = this
|
|
69
133
|
// set the initial activation state of the announcer based on launch setting
|
|
70
134
|
this.$announcer.toggle(Settings.get('announcer', false))
|
|
71
135
|
// configure global default utterance options if provided in settings
|
|
@@ -75,15 +139,15 @@ const Application = (config) => {
|
|
|
75
139
|
}
|
|
76
140
|
// Initialize merged keyMap once during application init
|
|
77
141
|
initKeyMap()
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const mouseEnabled = Settings.get('enableMouse', false)
|
|
83
|
-
const mouseMoveThrottle = Settings.get('mouseMoveThrottle', 100)
|
|
142
|
+
// Initialize fast-path cached settings once during application init
|
|
143
|
+
inputThrottleMs = Settings.get('inputThrottle', 0)
|
|
144
|
+
mouseMoveThrottleMs = Settings.get('mouseMoveThrottle', 100)
|
|
145
|
+
enableMouseFlag = Settings.get('enableMouse', false)
|
|
84
146
|
const { createKeyboardEvent, input, isKeyboardEvent, now = Date.now, viewport } = platform
|
|
147
|
+
liveInput = input
|
|
148
|
+
liveViewport = viewport
|
|
85
149
|
|
|
86
|
-
keyDownHandler = async (e) => {
|
|
150
|
+
keyDownHandler = async (/** @type {any} */ e) => {
|
|
87
151
|
const currentTime = now()
|
|
88
152
|
|
|
89
153
|
const key = keyMap[e.keyCode] || e.keyCode
|
|
@@ -91,11 +155,11 @@ const Application = (config) => {
|
|
|
91
155
|
lastInputKey = key
|
|
92
156
|
// execute immediately when no throttle is specified or event is internal (bubbled up by focus manager)
|
|
93
157
|
// or key is different from the last used key
|
|
94
|
-
if (
|
|
158
|
+
if (inputThrottleMs === 0 || e[symbols.internalEvent] === true || sameKey === false) {
|
|
95
159
|
return await processInput.call(this, e, key)
|
|
96
160
|
}
|
|
97
161
|
|
|
98
|
-
if (currentTime - lastInputTime <
|
|
162
|
+
if (currentTime - lastInputTime < inputThrottleMs) {
|
|
99
163
|
return
|
|
100
164
|
}
|
|
101
165
|
|
|
@@ -115,7 +179,7 @@ const Application = (config) => {
|
|
|
115
179
|
}
|
|
116
180
|
|
|
117
181
|
Focus.input(key, e)
|
|
118
|
-
if (
|
|
182
|
+
if (enableMouseFlag === true) {
|
|
119
183
|
Hover.clear()
|
|
120
184
|
// forget the node under the pointer too, so moving on it hovers it again
|
|
121
185
|
currentNode = undefined
|
|
@@ -130,6 +194,9 @@ const Application = (config) => {
|
|
|
130
194
|
}
|
|
131
195
|
|
|
132
196
|
keyUpHandler = (e) => {
|
|
197
|
+
clearTimeout(holdTimeout)
|
|
198
|
+
Focus.hold = false
|
|
199
|
+
|
|
133
200
|
const entry = keyUpCallbacks.get(e.keyCode)
|
|
134
201
|
if (entry !== undefined) {
|
|
135
202
|
keyUpCallbacks.delete(e.keyCode)
|
|
@@ -137,8 +204,6 @@ const Application = (config) => {
|
|
|
137
204
|
entry.callback()
|
|
138
205
|
}
|
|
139
206
|
}
|
|
140
|
-
clearTimeout(holdTimeout)
|
|
141
|
-
Focus.hold = false
|
|
142
207
|
}
|
|
143
208
|
|
|
144
209
|
let lastMoved = 0
|
|
@@ -154,7 +219,7 @@ const Application = (config) => {
|
|
|
154
219
|
|
|
155
220
|
// limit the amount of move events per time frame
|
|
156
221
|
mouseMoveHandler = (e) => {
|
|
157
|
-
if (e.timeStamp - lastMoved <
|
|
222
|
+
if (e.timeStamp - lastMoved < mouseMoveThrottleMs) return
|
|
158
223
|
lastMoved = e.timeStamp
|
|
159
224
|
|
|
160
225
|
this.$emit('mouse::move', e)
|
|
@@ -166,7 +231,7 @@ const Application = (config) => {
|
|
|
166
231
|
return
|
|
167
232
|
}
|
|
168
233
|
|
|
169
|
-
const stage = renderer.stage
|
|
234
|
+
const stage = /** @type {any} */ (renderer).stage
|
|
170
235
|
if (stage == null) {
|
|
171
236
|
return
|
|
172
237
|
}
|
|
@@ -179,6 +244,7 @@ const Application = (config) => {
|
|
|
179
244
|
|
|
180
245
|
if (node === null) {
|
|
181
246
|
currentComponent = undefined
|
|
247
|
+
currentNode = null
|
|
182
248
|
Hover.clear()
|
|
183
249
|
return
|
|
184
250
|
}
|
|
@@ -215,16 +281,21 @@ const Application = (config) => {
|
|
|
215
281
|
input.addEventListener('keydown', keyDownHandler)
|
|
216
282
|
input.addEventListener('keyup', keyUpHandler)
|
|
217
283
|
inputCleanup = () => {
|
|
218
|
-
input.removeEventListener('keydown', keyDownHandler)
|
|
219
|
-
input.removeEventListener('keyup', keyUpHandler)
|
|
284
|
+
input.removeEventListener('keydown', /** @type {any} */ (keyDownHandler))
|
|
285
|
+
input.removeEventListener('keyup', /** @type {any} */ (keyUpHandler))
|
|
220
286
|
}
|
|
221
287
|
}
|
|
222
|
-
|
|
288
|
+
mouseMoveHandlerRef = mouseMoveHandler
|
|
289
|
+
mouseClickHandlerRef = mouseClickHandler
|
|
290
|
+
updateCanvasRectRef = updateCanvasRect
|
|
291
|
+
|
|
292
|
+
if (enableMouseFlag === true && input !== undefined && viewport !== undefined) {
|
|
223
293
|
updateCanvasRect()
|
|
224
294
|
input.addEventListener('mousemove', mouseMoveHandler)
|
|
225
295
|
input.addEventListener('click', mouseClickHandler)
|
|
226
296
|
viewport.addEventListener('resize', updateCanvasRect)
|
|
227
297
|
viewport.addEventListener('scroll', updateCanvasRect)
|
|
298
|
+
mouseListenersAttached = true
|
|
228
299
|
mouseCleanup = () => {
|
|
229
300
|
input.removeEventListener('mousemove', mouseMoveHandler)
|
|
230
301
|
input.removeEventListener('click', mouseClickHandler)
|
|
@@ -233,8 +304,9 @@ const Application = (config) => {
|
|
|
233
304
|
}
|
|
234
305
|
}
|
|
235
306
|
|
|
236
|
-
//
|
|
237
|
-
|
|
307
|
+
// focus once the component tree is built (microtask: runs right after the
|
|
308
|
+
// current instantiation finishes, without yielding to render-loop frames)
|
|
309
|
+
Promise.resolve().then(() => Focus.set(this))
|
|
238
310
|
}
|
|
239
311
|
|
|
240
312
|
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)
|
|
@@ -27,7 +27,7 @@ import { trigger } from '../../lib/reactivity/effect.js'
|
|
|
27
27
|
import { Log } from '../../lib/log.js'
|
|
28
28
|
import { removeEffects } from '../../lib/reactivity/effect.js'
|
|
29
29
|
import { renderer } from '../../launch.js'
|
|
30
|
-
import { keyMap } from '../../
|
|
30
|
+
import { keyMap } from '../../keymap.js'
|
|
31
31
|
import { platform } from '../../platform.js'
|
|
32
32
|
|
|
33
33
|
const selectCache = new WeakMap()
|
|
@@ -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
|
+
}
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import { Log } from '../../lib/log.js'
|
|
19
19
|
|
|
20
20
|
import symbols from '../../lib/symbols.js'
|
|
21
|
+
import { createComputed } from '../../lib/reactivity/effect.js'
|
|
21
22
|
|
|
22
23
|
export default (component, computeds) => {
|
|
23
24
|
component[symbols.computedKeys] = []
|
|
@@ -40,7 +41,10 @@ export default (component, computeds) => {
|
|
|
40
41
|
component[symbols.computedKeys].push(computed)
|
|
41
42
|
Object.defineProperty(component, computed, {
|
|
42
43
|
get() {
|
|
43
|
-
|
|
44
|
+
// Setup runs on the shared prototype; install the cache on first instance access.
|
|
45
|
+
const get = createComputed(computeds[computed], this, computed)
|
|
46
|
+
Object.defineProperty(this, computed, { get })
|
|
47
|
+
return get()
|
|
44
48
|
},
|
|
45
49
|
})
|
|
46
50
|
}
|
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
|
|
@@ -495,16 +496,24 @@ const Component = (name = required('name'), config = required('config')) => {
|
|
|
495
496
|
base = setupComponent(Object.create(Base), config)
|
|
496
497
|
}
|
|
497
498
|
|
|
498
|
-
//
|
|
499
|
-
if (
|
|
500
|
-
Log.debug(`Generating code for ${name} component`)
|
|
501
|
-
config.code = codegenerator.call(config, parser(config.template, name), devMode)
|
|
502
|
-
}
|
|
499
|
+
// Direct factory calls also prepare runtime code before rendering.
|
|
500
|
+
if (factory.prepare !== undefined) factory.prepare()
|
|
503
501
|
|
|
504
502
|
// create an instance of the component, using base as the prototype (which contains Base)
|
|
505
503
|
return component.call(Object.create(base), options, parentEl, parentComponent, rootComponent)
|
|
506
504
|
}
|
|
507
505
|
|
|
506
|
+
// Precompiled factories have no preparation step. Runtime factories compile once,
|
|
507
|
+
// explicitly before holder creation, then take the same path as precompiled ones.
|
|
508
|
+
if (config.code === undefined) {
|
|
509
|
+
factory.prepare = () => {
|
|
510
|
+
Log.debug(`Generating code for ${name} component`)
|
|
511
|
+
config.code = codegenerator.call(config, parser(config.template, name), devMode)
|
|
512
|
+
factory.needsInteractive = factory.needsInteractive || !!config.code.usesHoverState
|
|
513
|
+
factory.prepare = undefined
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
508
517
|
// store the config on the factory, in order to access the config
|
|
509
518
|
// during the code generation step
|
|
510
519
|
factory[Symbol.for('config')] = config
|
|
@@ -515,6 +524,13 @@ const Component = (name = required('name'), config = required('config')) => {
|
|
|
515
524
|
// To determine whether dynamic component is actual Blits component or not
|
|
516
525
|
factory[symbols.isComponent] = true
|
|
517
526
|
|
|
527
|
+
// Pointer hit testing supports both hover and click-to-focus/input.
|
|
528
|
+
factory.needsInteractive =
|
|
529
|
+
(config.hooks && !!(config.hooks.hover || config.hooks.unhover)) ||
|
|
530
|
+
(config.input &&
|
|
531
|
+
(typeof config.input.enter === 'function' || typeof config.input.any === 'function')) ||
|
|
532
|
+
!!(config.code && config.code.usesHoverState)
|
|
533
|
+
|
|
518
534
|
return factory
|
|
519
535
|
}
|
|
520
536
|
|
package/src/components/Circle.js
CHANGED
|
@@ -66,7 +66,7 @@ export default () =>
|
|
|
66
66
|
'content',
|
|
67
67
|
'placement',
|
|
68
68
|
'inspector-data',
|
|
69
|
-
'
|
|
69
|
+
'interactive',
|
|
70
70
|
]
|
|
71
71
|
const elementConfigs = []
|
|
72
72
|
const forloops = []
|
|
@@ -133,6 +133,7 @@ export default () =>
|
|
|
133
133
|
},
|
|
134
134
|
],
|
|
135
135
|
context: {},
|
|
136
|
+
usesHoverState: false,
|
|
136
137
|
},
|
|
137
138
|
props: { size: 40, bgColor: 'white' },
|
|
138
139
|
computed: {
|
|
@@ -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) {
|
|
@@ -68,7 +72,7 @@ export const FPScounter = Blits.Component('FPScounter', {
|
|
|
68
72
|
'content',
|
|
69
73
|
'placement',
|
|
70
74
|
'inspector-data',
|
|
71
|
-
'
|
|
75
|
+
'interactive',
|
|
72
76
|
]
|
|
73
77
|
const elementConfigs = []
|
|
74
78
|
const forloops = []
|
|
@@ -630,6 +634,7 @@ export const FPScounter = Blits.Component('FPScounter', {
|
|
|
630
634
|
},
|
|
631
635
|
],
|
|
632
636
|
context: {},
|
|
637
|
+
usesHoverState: false,
|
|
633
638
|
},
|
|
634
639
|
state() {
|
|
635
640
|
return {
|
|
@@ -662,28 +667,34 @@ export const FPScounter = Blits.Component('FPScounter', {
|
|
|
662
667
|
avgFps: '---',
|
|
663
668
|
minFps: '---',
|
|
664
669
|
maxFps: '---',
|
|
670
|
+
|
|
671
|
+
data: {
|
|
672
|
+
minFps: 10000,
|
|
673
|
+
maxFps: 0,
|
|
674
|
+
totalFps: 0,
|
|
675
|
+
fpsUpdateCounter: 0,
|
|
676
|
+
avgFps: 0,
|
|
677
|
+
},
|
|
665
678
|
}
|
|
666
679
|
},
|
|
667
680
|
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
|
-
})
|
|
681
|
+
/**
|
|
682
|
+
* @param {number} fps
|
|
683
|
+
*/
|
|
684
|
+
fpsUpdate(fps) {
|
|
685
|
+
// early return when not active or hidden
|
|
686
|
+
if (!this.active || !this.show || this.alpha === 0) return
|
|
687
|
+
|
|
688
|
+
this.data.minFps = Math.min(fps, this.data.minFps)
|
|
689
|
+
this.data.maxFps = Math.max(fps, this.data.maxFps)
|
|
690
|
+
this.data.totalFps += fps
|
|
691
|
+
this.data.fpsUpdateCounter++
|
|
692
|
+
this.data.avgFps = Math.round(this.data.totalFps / this.data.fpsUpdateCounter)
|
|
693
|
+
|
|
694
|
+
this.fps = fps.toString().padStart(3, '0')
|
|
695
|
+
this.avgFps = this.data.avgFps.toString().padStart(3, '0')
|
|
696
|
+
this.minFps = this.data.minFps.toString().padStart(3, '0')
|
|
697
|
+
this.maxFps = this.data.maxFps.toString().padStart(3, '0')
|
|
687
698
|
},
|
|
688
699
|
},
|
|
689
700
|
})
|
|
@@ -78,7 +78,7 @@ export default () =>
|
|
|
78
78
|
'content',
|
|
79
79
|
'placement',
|
|
80
80
|
'inspector-data',
|
|
81
|
-
'
|
|
81
|
+
'interactive',
|
|
82
82
|
]
|
|
83
83
|
const elementConfigs = []
|
|
84
84
|
const forloops = []
|
|
@@ -130,6 +130,7 @@ export default () =>
|
|
|
130
130
|
},
|
|
131
131
|
effects: [],
|
|
132
132
|
context: {},
|
|
133
|
+
usesHoverState: false,
|
|
133
134
|
},
|
|
134
135
|
props: {
|
|
135
136
|
name: '',
|
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
|
}
|