@lightningjs/blits 1.20.1 → 1.21.1
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 +16 -0
- package/index.d.ts +51 -0
- package/package.json +2 -2
- package/src/engines/L3/element.js +1 -1
- package/src/engines/L3/launch.js +22 -3
- package/src/lib/codegenerator/generator.js +22 -2
- package/src/lib/reactivity/effect.js +5 -3
- package/src/lib/reactivity/reactive.js +8 -4
- package/src/router/router.js +37 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.21.1
|
|
4
|
+
|
|
5
|
+
_28 feb 2025_
|
|
6
|
+
|
|
7
|
+
- Changed gpuMemory launch settings to be optional in type definitions
|
|
8
|
+
|
|
9
|
+
## v1.21.0
|
|
10
|
+
|
|
11
|
+
_27 feb 2025_
|
|
12
|
+
|
|
13
|
+
- Added functionality for keeping query params when navigating back in the router
|
|
14
|
+
- Exposed more info in reactive router state
|
|
15
|
+
- Added `range`-attribute to for-loop
|
|
16
|
+
- Fixed issue when setting `alpha` to truthy or false values
|
|
17
|
+
- Upgraded to renderer v2.13.0
|
|
18
|
+
|
|
3
19
|
## v1.20.1
|
|
4
20
|
|
|
5
21
|
_14 feb 2025_
|
package/index.d.ts
CHANGED
|
@@ -799,8 +799,59 @@ declare module '@lightningjs/blits' {
|
|
|
799
799
|
* and cleaned up
|
|
800
800
|
*
|
|
801
801
|
* Defaults to `200` (mb)
|
|
802
|
+
* @deprecated
|
|
803
|
+
* Deprecated: use `gpuMemory` launch setting instead
|
|
802
804
|
*/
|
|
803
805
|
gpuMemoryLimit?: number,
|
|
806
|
+
/**
|
|
807
|
+
* Configures the gpu memory settings used by the renderer
|
|
808
|
+
*/
|
|
809
|
+
gpuMemory?: {
|
|
810
|
+
/**
|
|
811
|
+
* Maximum GPU memory threshold (in `mb`) after which
|
|
812
|
+
* the renderer will immediately start cleaning up textures to free
|
|
813
|
+
* up graphical memory
|
|
814
|
+
*
|
|
815
|
+
* When setting to `0`, texture memory management is disabled
|
|
816
|
+
*
|
|
817
|
+
* @default `200`
|
|
818
|
+
*/
|
|
819
|
+
max?: number,
|
|
820
|
+
/**
|
|
821
|
+
* Target threshold of GPU memory usage, defined as a fraction of
|
|
822
|
+
* the max threshold. The renderer will attempt to keep memory
|
|
823
|
+
* usage below this target by cleaning up non-renderable textures
|
|
824
|
+
*
|
|
825
|
+
* @default `0.8`
|
|
826
|
+
*/
|
|
827
|
+
target?: 0.8,
|
|
828
|
+
/**
|
|
829
|
+
* Interval at which regular texture cleanups occur (in `ms`)
|
|
830
|
+
*
|
|
831
|
+
* @default `5000`
|
|
832
|
+
*/
|
|
833
|
+
cleanupInterval?: 5000,
|
|
834
|
+
/**
|
|
835
|
+
* Baseline GPU memory usage of the App (in `mb`), without rendering any
|
|
836
|
+
* textures. This value will be used as a basis when calculating
|
|
837
|
+
* the total memory usage towards the max and target memory
|
|
838
|
+
* usage
|
|
839
|
+
*
|
|
840
|
+
* @default `25`
|
|
841
|
+
*/
|
|
842
|
+
baseline?: 25,
|
|
843
|
+
/**
|
|
844
|
+
* Whether or not the max threshold should be considered
|
|
845
|
+
* as a strict number that can not be exceeded in any way
|
|
846
|
+
*
|
|
847
|
+
* When set to `true`, new textures won't be created when the
|
|
848
|
+
* max threshold has been reached, until agressive texture cleanup
|
|
849
|
+
* has brought the memory back down
|
|
850
|
+
*
|
|
851
|
+
* @default false
|
|
852
|
+
*/
|
|
853
|
+
strict?: false,
|
|
854
|
+
},
|
|
804
855
|
/**
|
|
805
856
|
* Defines which mode the renderer should operate in: `webgl` or `canvas`
|
|
806
857
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightningjs/blits",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.1",
|
|
4
4
|
"description": "Blits: The Lightning 3 App Development Framework",
|
|
5
5
|
"bin": "bin/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@lightningjs/msdf-generator": "^1.1.1",
|
|
55
|
-
"@lightningjs/renderer": "^2.
|
|
55
|
+
"@lightningjs/renderer": "^2.13.0"
|
|
56
56
|
},
|
|
57
57
|
"repository": {
|
|
58
58
|
"type": "git",
|
package/src/engines/L3/launch.js
CHANGED
|
@@ -42,6 +42,27 @@ const textRenderEngines = (settings) => {
|
|
|
42
42
|
if (renderMode === 'canvas') return [CanvasTextRenderer]
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
const textureMemorySettings = (settings) => {
|
|
46
|
+
const gpuMemory = {
|
|
47
|
+
...{
|
|
48
|
+
max: 200,
|
|
49
|
+
target: 0.8,
|
|
50
|
+
cleanupInterval: 5000,
|
|
51
|
+
baseline: 25,
|
|
52
|
+
strict: false,
|
|
53
|
+
},
|
|
54
|
+
...('gpuMemory' in settings === true ? settings.gpuMemory : {}),
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
criticalThreshold: gpuMemory.max * 1024 * 1024, // convert from mb to bytes
|
|
59
|
+
targetThresholdLevel: gpuMemory.target,
|
|
60
|
+
cleanupInterval: gpuMemory.cleanupInterval,
|
|
61
|
+
baselineMemoryAllocation: gpuMemory.baseline * 1024 * 1024, // convert from mb to bytes
|
|
62
|
+
doNotExceedCriticalThreshold: gpuMemory.strict,
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
45
66
|
export default (App, target, settings = {}) => {
|
|
46
67
|
renderer = new RendererMain(
|
|
47
68
|
{
|
|
@@ -62,13 +83,11 @@ export default (App, target, settings = {}) => {
|
|
|
62
83
|
clearColor: (settings.canvasColor && colors.normalize(settings.canvasColor)) || 0x00000000,
|
|
63
84
|
inspector: settings.inspector === true ? Inspector : undefined,
|
|
64
85
|
boundsMargin: settings.viewportMargin || 0,
|
|
65
|
-
// gpu memory limit, converted from mb to bytes - defaults to 200mb
|
|
66
|
-
txMemByteThreshold:
|
|
67
|
-
'gpuMemoryLimit' in settings ? settings.gpuMemoryLimit * 1024 * 1024 : 200 * 1024 * 1024,
|
|
68
86
|
renderEngine: renderEngine(settings),
|
|
69
87
|
fontEngines: textRenderEngines(settings),
|
|
70
88
|
canvas: settings.canvas,
|
|
71
89
|
textureProcessingTimeLimit: settings.textureProcessingTimeLimit,
|
|
90
|
+
textureMemory: textureMemorySettings(settings),
|
|
72
91
|
},
|
|
73
92
|
target
|
|
74
93
|
)
|
|
@@ -291,6 +291,9 @@ const generateComponentCode = function (
|
|
|
291
291
|
const generateForLoopCode = function (templateObject, parent) {
|
|
292
292
|
const forLoop = templateObject[':for']
|
|
293
293
|
delete templateObject[':for']
|
|
294
|
+
const range = templateObject['range'] || templateObject[':range'] || '{}'
|
|
295
|
+
delete templateObject['range']
|
|
296
|
+
delete templateObject[':range']
|
|
294
297
|
|
|
295
298
|
const key = templateObject['key']
|
|
296
299
|
const forKey = interpolate(key, 'scope.')
|
|
@@ -340,10 +343,19 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
340
343
|
|
|
341
344
|
ctx.renderCode.push(`
|
|
342
345
|
const created${forStartCounter} = []
|
|
346
|
+
|
|
347
|
+
let from${forStartCounter}
|
|
348
|
+
let to${forStartCounter}
|
|
349
|
+
|
|
343
350
|
const forloop${forStartCounter} = (collection = [], elms, created) => {
|
|
344
351
|
const rawCollection = getRaw(collection)
|
|
345
352
|
const keys = new Set()
|
|
346
353
|
let l = rawCollection.length
|
|
354
|
+
|
|
355
|
+
const range = ${interpolate(range)} || {}
|
|
356
|
+
from${forStartCounter} = range['from'] || 0
|
|
357
|
+
to${forStartCounter} = 'to' in range ? range['to'] : rawCollection.length
|
|
358
|
+
|
|
347
359
|
while(l--) {
|
|
348
360
|
const ${item} = rawCollection[l]
|
|
349
361
|
`)
|
|
@@ -354,7 +366,9 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
354
366
|
`)
|
|
355
367
|
}
|
|
356
368
|
ctx.renderCode.push(`
|
|
357
|
-
|
|
369
|
+
if(l < to${forStartCounter} && l >= from${forStartCounter}) {
|
|
370
|
+
keys.add('' + ${interpolate(key, '') || 'l'})
|
|
371
|
+
}
|
|
358
372
|
}
|
|
359
373
|
`)
|
|
360
374
|
|
|
@@ -368,6 +382,7 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
368
382
|
const length = rawCollection.length
|
|
369
383
|
const effects = []
|
|
370
384
|
for(let __index = 0; __index < length; __index++) {
|
|
385
|
+
if(__index < from${forStartCounter} || __index >= to${forStartCounter}) continue
|
|
371
386
|
const scope = Object.create(component)
|
|
372
387
|
parent = ${parent}
|
|
373
388
|
scope['${item}'] = rawCollection[__index]
|
|
@@ -488,6 +503,10 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
488
503
|
effectKey = effectKey.match(/[^.]+$/)[0]
|
|
489
504
|
}
|
|
490
505
|
|
|
506
|
+
// get the reference to range from and to
|
|
507
|
+
const effectKeysRegex = /\$([^,} ]+)/g
|
|
508
|
+
const effectKeys = [...range.matchAll(effectKeysRegex)].map((match) => `'${match[1]}'`)
|
|
509
|
+
|
|
491
510
|
ctx.renderCode.push(`
|
|
492
511
|
let forEffects${forStartCounter}
|
|
493
512
|
effect(() => {
|
|
@@ -497,7 +516,7 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
497
516
|
result[2],
|
|
498
517
|
':for'
|
|
499
518
|
)}, elms, created${forStartCounter})
|
|
500
|
-
}, '${effectKey}' )
|
|
519
|
+
}, ['${effectKey}', ${effectKeys.join(',')}] )
|
|
501
520
|
`)
|
|
502
521
|
|
|
503
522
|
outerScopeEffects.forEach((effect) => {
|
|
@@ -520,6 +539,7 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
520
539
|
effect(() => {
|
|
521
540
|
void ${refs.join(', ')}
|
|
522
541
|
for(let __index = 0; __index < ${interpolate(result[2])}.length; __index++) {
|
|
542
|
+
if(__index < from${forStartCounter} || __index >= to${forStartCounter}) continue
|
|
523
543
|
const scope = {}
|
|
524
544
|
scope['${index}'] = __index
|
|
525
545
|
scope['${item}'] = ${interpolate(result[2])}[__index]
|
|
@@ -49,9 +49,11 @@ export const track = (target, key, global = false) => {
|
|
|
49
49
|
if (paused) {
|
|
50
50
|
return
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
// note: nesting the conditions like this seems to perform better ¯\_(ツ)_/¯
|
|
53
|
+
if (Array.isArray(currentKey) === true) {
|
|
54
|
+
if (currentKey.includes(key) === false) return
|
|
55
|
+
} else if (currentKey !== null && key !== currentKey) return
|
|
56
|
+
|
|
55
57
|
let effectsMap = objectMap.get(target)
|
|
56
58
|
if (!effectsMap) {
|
|
57
59
|
effectsMap = new Map()
|
|
@@ -101,10 +101,14 @@ const reactiveProxy = (original, _parent = null, _key, global) => {
|
|
|
101
101
|
const rawValue = getRaw(value)
|
|
102
102
|
|
|
103
103
|
let result = true
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
let isEqual = false
|
|
105
|
+
|
|
106
|
+
// We need to check that the oldRawValue is also an array before we do the deep equal check
|
|
107
|
+
if (Array.isArray(rawValue) === true && Array.isArray(oldRawValue) === true) {
|
|
108
|
+
isEqual = deepEqualArray(oldRawValue, rawValue)
|
|
109
|
+
} else if (oldRawValue === rawValue) {
|
|
110
|
+
isEqual = true
|
|
111
|
+
}
|
|
108
112
|
|
|
109
113
|
if (isEqual === false) {
|
|
110
114
|
if (typeof value === 'object') {
|
package/src/router/router.js
CHANGED
|
@@ -25,7 +25,13 @@ import Focus from '../focus.js'
|
|
|
25
25
|
import Announcer from '../announcer/announcer.js'
|
|
26
26
|
|
|
27
27
|
export let currentRoute
|
|
28
|
-
export const state = reactive({
|
|
28
|
+
export const state = reactive({
|
|
29
|
+
path: '',
|
|
30
|
+
navigating: false,
|
|
31
|
+
data: null,
|
|
32
|
+
params: null,
|
|
33
|
+
hash: '',
|
|
34
|
+
})
|
|
29
35
|
|
|
30
36
|
const cacheMap = new WeakMap()
|
|
31
37
|
const history = []
|
|
@@ -38,8 +44,9 @@ let previousFocus
|
|
|
38
44
|
export const getHash = () => {
|
|
39
45
|
const hashParts = (document.location.hash || '/').replace(/^#/, '').split('?')
|
|
40
46
|
return {
|
|
41
|
-
|
|
47
|
+
path: hashParts[0],
|
|
42
48
|
queryParams: new URLSearchParams(hashParts[1]),
|
|
49
|
+
hash: document.location.hash,
|
|
43
50
|
}
|
|
44
51
|
}
|
|
45
52
|
|
|
@@ -108,7 +115,6 @@ export const matchHash = (path, routes = []) => {
|
|
|
108
115
|
if (!matchingRoute.data) {
|
|
109
116
|
matchingRoute.data = {}
|
|
110
117
|
}
|
|
111
|
-
currentRoute = matchingRoute
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
return matchingRoute
|
|
@@ -117,9 +123,16 @@ export const matchHash = (path, routes = []) => {
|
|
|
117
123
|
export const navigate = async function () {
|
|
118
124
|
state.navigating = true
|
|
119
125
|
if (this.parent[symbols.routes]) {
|
|
120
|
-
|
|
121
|
-
const { hash, queryParams } = getHash()
|
|
122
|
-
let route = matchHash(
|
|
126
|
+
let previousRoute = currentRoute ? Object.assign({}, currentRoute) : undefined
|
|
127
|
+
const { hash, path, queryParams } = getHash()
|
|
128
|
+
let route = matchHash(path, this.parent[symbols.routes])
|
|
129
|
+
|
|
130
|
+
// Adding the location hash to the route if it exists.
|
|
131
|
+
if (hash !== null) {
|
|
132
|
+
route.hash = hash
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
currentRoute = route
|
|
123
136
|
let beforeHookOutput
|
|
124
137
|
if (route) {
|
|
125
138
|
if (route.hooks) {
|
|
@@ -149,6 +162,7 @@ export const navigate = async function () {
|
|
|
149
162
|
}
|
|
150
163
|
|
|
151
164
|
let holder
|
|
165
|
+
let routeData
|
|
152
166
|
let { view, focus } = cacheMap.get(route) || {}
|
|
153
167
|
|
|
154
168
|
if (!view) {
|
|
@@ -164,13 +178,17 @@ export const navigate = async function () {
|
|
|
164
178
|
queryParamsData[queryParamsEntries[i][0]] = queryParamsEntries[i][1]
|
|
165
179
|
}
|
|
166
180
|
|
|
181
|
+
routeData = {
|
|
182
|
+
...navigationData,
|
|
183
|
+
...route.data,
|
|
184
|
+
...queryParamsData,
|
|
185
|
+
}
|
|
186
|
+
|
|
167
187
|
// merge props with potential route params, navigation data and route data to be injected into the component instance
|
|
168
188
|
const props = {
|
|
169
189
|
...this[symbols.props],
|
|
170
190
|
...route.params,
|
|
171
|
-
...
|
|
172
|
-
...route.data,
|
|
173
|
-
...queryParamsData,
|
|
191
|
+
...routeData,
|
|
174
192
|
}
|
|
175
193
|
|
|
176
194
|
view = await route.component({ props }, holder, this)
|
|
@@ -236,9 +254,14 @@ export const navigate = async function () {
|
|
|
236
254
|
if (oldView) {
|
|
237
255
|
removeView(previousRoute, oldView, route.transition.out)
|
|
238
256
|
}
|
|
257
|
+
|
|
258
|
+
previousRoute = undefined
|
|
239
259
|
}
|
|
240
260
|
|
|
241
261
|
state.path = route.path
|
|
262
|
+
state.params = route.params
|
|
263
|
+
state.hash = hash
|
|
264
|
+
state.data = routeData
|
|
242
265
|
|
|
243
266
|
// apply in transition
|
|
244
267
|
if (route.transition.in) {
|
|
@@ -320,7 +343,8 @@ const setOrAnimate = (node, transition, shouldAnimate = true) => {
|
|
|
320
343
|
export const to = (location, data = {}, options = {}) => {
|
|
321
344
|
navigationData = data
|
|
322
345
|
overrideOptions = options
|
|
323
|
-
|
|
346
|
+
|
|
347
|
+
window.location.hash = location
|
|
324
348
|
}
|
|
325
349
|
|
|
326
350
|
export const back = function () {
|
|
@@ -328,13 +352,8 @@ export const back = function () {
|
|
|
328
352
|
if (route && currentRoute !== route) {
|
|
329
353
|
// set indicator that we are navigating back (to prevent adding page to history stack)
|
|
330
354
|
navigatingBack = true
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
Object.keys(route.params).forEach((item) => {
|
|
334
|
-
targetRoutePath = targetRoutePath.replace(`:${item}`, route.params[item])
|
|
335
|
-
})
|
|
336
|
-
}
|
|
337
|
-
to(targetRoutePath)
|
|
355
|
+
|
|
356
|
+
to(route.hash, route.data, route.options)
|
|
338
357
|
return true
|
|
339
358
|
}
|
|
340
359
|
|
|
@@ -348,6 +367,7 @@ export const back = function () {
|
|
|
348
367
|
|
|
349
368
|
const hashEnd = /(\/:?[\w%\s-]+)$/
|
|
350
369
|
let path = currentRoute.path
|
|
370
|
+
|
|
351
371
|
let level = path.split('/').length
|
|
352
372
|
|
|
353
373
|
// On root return
|