@lightningjs/blits 2.4.1 → 2.6.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 +17 -0
- package/index.d.ts +100 -11
- package/package.json +10 -2
- package/src/announcer/announcer.js +2 -1
- package/src/announcer/speechSynthesis.js +12 -2
- package/src/application.js +40 -20
- package/src/component/base/methods.js +6 -1
- package/src/component.js +7 -0
- package/src/components/Circle.js +3 -0
- package/src/components/FPScounter.js +206 -1330
- package/src/components/RouterView.js +13 -2
- package/src/components/index.js +0 -2
- package/src/engines/L3/element.js +134 -9
- package/src/engines/L3/launch.js +9 -5
- package/src/engines/L3/spriteTexture.js +71 -0
- package/src/focus/focus.js +7 -4
- package/src/launch.js +23 -0
- package/src/lib/codegenerator/generator.js +12 -2
- package/src/lib/reactivityguard/computedprops.js +6 -2
- package/src/lib/symbols.js +4 -0
- package/src/platform.js +117 -0
- package/src/platforms.d.ts +1 -0
- package/src/platforms.js +23 -0
- package/src/plugins/storage/localCookie.js +15 -12
- package/src/router/router.js +4 -2
- package/src/testing/index.d.ts +58 -0
- package/src/testing/index.js +20 -0
- package/src/testing/nodePlatform.js +116 -0
- package/src/testing/renderComponent.js +346 -0
- package/src/components/Sprite.js +0 -256
|
@@ -23,6 +23,7 @@ import Router, {
|
|
|
23
23
|
} from '../router/router.js'
|
|
24
24
|
import symbols from '../lib/symbols.js'
|
|
25
25
|
import Focus from '../focus/focus.js'
|
|
26
|
+
import { platform } from '../platform.js'
|
|
26
27
|
|
|
27
28
|
/** @typedef {{ $input?: (event: any) => boolean, $focus?: (event: any) => void }} RouterViewParent */
|
|
28
29
|
|
|
@@ -46,6 +47,9 @@ export default () =>
|
|
|
46
47
|
'color',
|
|
47
48
|
'src',
|
|
48
49
|
'texture',
|
|
50
|
+
'image',
|
|
51
|
+
'map',
|
|
52
|
+
'frame',
|
|
49
53
|
'fit',
|
|
50
54
|
'rtt',
|
|
51
55
|
'mount',
|
|
@@ -156,11 +160,18 @@ export default () =>
|
|
|
156
160
|
Router.navigate.apply(this)
|
|
157
161
|
}
|
|
158
162
|
|
|
159
|
-
|
|
163
|
+
const viewport = platform.viewport
|
|
164
|
+
if (viewport !== undefined) {
|
|
165
|
+
this.hashchangeViewport = viewport
|
|
166
|
+
viewport.addEventListener('hashchange', this.hashchangeHandler)
|
|
167
|
+
}
|
|
160
168
|
},
|
|
161
169
|
destroy() {
|
|
162
170
|
unregisterRouterView(this)
|
|
163
|
-
|
|
171
|
+
if (this.hashchangeViewport !== undefined) {
|
|
172
|
+
this.hashchangeViewport.removeEventListener('hashchange', this.hashchangeHandler, false)
|
|
173
|
+
this.hashchangeViewport = undefined
|
|
174
|
+
}
|
|
164
175
|
},
|
|
165
176
|
focus() {
|
|
166
177
|
if (this.activeView && Focus.get() === this) {
|
package/src/components/index.js
CHANGED
|
@@ -29,9 +29,14 @@ import { Log } from '../../lib/log.js'
|
|
|
29
29
|
import symbols from '../../lib/symbols.js'
|
|
30
30
|
import Settings from '../../settings.js'
|
|
31
31
|
import shaders from '../../lib/shaders/shaders.js'
|
|
32
|
+
import { resolveSpriteTexture } from './spriteTexture.js'
|
|
32
33
|
|
|
33
34
|
const holderComponentMap = new WeakMap()
|
|
34
35
|
|
|
36
|
+
/** @param {any} frame */
|
|
37
|
+
const spriteFrameKey = (frame) =>
|
|
38
|
+
typeof frame === 'object' && frame !== null ? JSON.stringify(frame) : frame
|
|
39
|
+
|
|
35
40
|
/**
|
|
36
41
|
* Creates a padding object from a value and direction.
|
|
37
42
|
* @param {number|object|string|undefined} padding - The padding value.
|
|
@@ -291,6 +296,24 @@ const propsTransformer = {
|
|
|
291
296
|
this.props['color'] = 0xffffffff
|
|
292
297
|
}
|
|
293
298
|
},
|
|
299
|
+
set image(v) {
|
|
300
|
+
this.raw['image'] = v
|
|
301
|
+
if (this.element[symbols.isSprite] === true && this.element.node) {
|
|
302
|
+
this.element._scheduleNativeSpriteSync()
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
set map(v) {
|
|
306
|
+
this.raw['map'] = v
|
|
307
|
+
if (this.element[symbols.isSprite] === true && this.element.node) {
|
|
308
|
+
this.element._scheduleNativeSpriteSync()
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
set frame(v) {
|
|
312
|
+
this.raw['frame'] = v
|
|
313
|
+
if (this.element[symbols.isSprite] === true && this.element.node) {
|
|
314
|
+
this.element._scheduleNativeSpriteSync()
|
|
315
|
+
}
|
|
316
|
+
},
|
|
294
317
|
set fit(v) {
|
|
295
318
|
const resizeMode = {}
|
|
296
319
|
|
|
@@ -548,6 +571,7 @@ export const elementAttributes = Object.keys(propsTransformer)
|
|
|
548
571
|
const Element = {
|
|
549
572
|
/**
|
|
550
573
|
* Populates the element with data
|
|
574
|
+
* @this {import('../../component.js').BlitsElement}
|
|
551
575
|
* @param {import('../../component.js').BlitsElementProps} props
|
|
552
576
|
*/
|
|
553
577
|
populate(props) {
|
|
@@ -557,6 +581,21 @@ const Element = {
|
|
|
557
581
|
this[symbols.isSlot] = true
|
|
558
582
|
}
|
|
559
583
|
|
|
584
|
+
if (props[symbols.isSprite] === true) {
|
|
585
|
+
this[symbols.isSprite] = true
|
|
586
|
+
this._spriteState = {
|
|
587
|
+
spriteTexture: null,
|
|
588
|
+
currentSrc: null,
|
|
589
|
+
_loadedCb: null,
|
|
590
|
+
_failedCb: null,
|
|
591
|
+
_syncScheduled: false,
|
|
592
|
+
lastTexture: null,
|
|
593
|
+
lastImage: null,
|
|
594
|
+
lastMap: null,
|
|
595
|
+
lastFrameKey: undefined,
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
560
599
|
this.props.element = this
|
|
561
600
|
|
|
562
601
|
this.props['parent'] = props['parent'] || this.config.parent
|
|
@@ -600,16 +639,20 @@ const Element = {
|
|
|
600
639
|
holderComponentMap.set(this.node, this.component)
|
|
601
640
|
}
|
|
602
641
|
|
|
603
|
-
if (
|
|
604
|
-
this.
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
642
|
+
if (this[symbols.isSprite] === true) {
|
|
643
|
+
this._syncNativeSprite()
|
|
644
|
+
} else {
|
|
645
|
+
if (props['@loaded'] !== undefined && typeof props['@loaded'] === 'function') {
|
|
646
|
+
this.node.on('loaded', (el, { type, dimensions }) => {
|
|
647
|
+
props['@loaded']({ w: dimensions.w, h: dimensions.h, type }, this)
|
|
648
|
+
})
|
|
649
|
+
}
|
|
608
650
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
651
|
+
if (props['@error'] !== undefined && typeof props['@error'] === 'function') {
|
|
652
|
+
this.node.on('failed', (el, error) => {
|
|
653
|
+
props['@error'](error, this)
|
|
654
|
+
})
|
|
655
|
+
}
|
|
613
656
|
}
|
|
614
657
|
|
|
615
658
|
if (props.__layout === true) {
|
|
@@ -657,6 +700,78 @@ const Element = {
|
|
|
657
700
|
this.node.data = { ...this.props.props['data'] }
|
|
658
701
|
}
|
|
659
702
|
},
|
|
703
|
+
/**
|
|
704
|
+
* @this {import('../../component.js').BlitsElement}
|
|
705
|
+
*/
|
|
706
|
+
_scheduleNativeSpriteSync() {
|
|
707
|
+
if (this[symbols.isSprite] !== true || !this.node || this.eol === true) return
|
|
708
|
+
const st = this._spriteState
|
|
709
|
+
if (st === undefined) return
|
|
710
|
+
if (st._syncScheduled === true) return
|
|
711
|
+
st._syncScheduled = true
|
|
712
|
+
queueMicrotask(() => {
|
|
713
|
+
st._syncScheduled = false
|
|
714
|
+
if (this.eol === true || !this.node) return
|
|
715
|
+
this._syncNativeSprite()
|
|
716
|
+
})
|
|
717
|
+
},
|
|
718
|
+
/**
|
|
719
|
+
* @this {import('../../component.js').BlitsElement}
|
|
720
|
+
*/
|
|
721
|
+
_syncNativeSprite() {
|
|
722
|
+
if (this[symbols.isSprite] !== true || !this.node) return
|
|
723
|
+
const st = this._spriteState
|
|
724
|
+
if (st === undefined) return
|
|
725
|
+
|
|
726
|
+
const raw = this.props.raw
|
|
727
|
+
const image = raw['image']
|
|
728
|
+
const map = raw['map']
|
|
729
|
+
const frameKey = spriteFrameKey(raw['frame'])
|
|
730
|
+
|
|
731
|
+
if (
|
|
732
|
+
st.lastTexture != null &&
|
|
733
|
+
image === st.lastImage &&
|
|
734
|
+
map === st.lastMap &&
|
|
735
|
+
frameKey === st.lastFrameKey
|
|
736
|
+
) {
|
|
737
|
+
return
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
const imageChanged = image !== st.lastImage
|
|
741
|
+
st.lastImage = image
|
|
742
|
+
st.lastMap = map
|
|
743
|
+
st.lastFrameKey = frameKey
|
|
744
|
+
|
|
745
|
+
const texture = resolveSpriteTexture(this, renderer, st)
|
|
746
|
+
if (texture === st.lastTexture) return
|
|
747
|
+
|
|
748
|
+
st.lastTexture = texture
|
|
749
|
+
this.set('texture', texture)
|
|
750
|
+
|
|
751
|
+
if (imageChanged !== true) return
|
|
752
|
+
|
|
753
|
+
const prevL = st._loadedCb
|
|
754
|
+
const prevF = st._failedCb
|
|
755
|
+
st._loadedCb =
|
|
756
|
+
raw['@loaded'] && typeof raw['@loaded'] === 'function'
|
|
757
|
+
? (payload) => {
|
|
758
|
+
const d = payload?.dimensions
|
|
759
|
+
const w = payload?.w ?? payload?.width ?? d?.width ?? d?.w
|
|
760
|
+
const h = payload?.h ?? payload?.height ?? d?.height ?? d?.h
|
|
761
|
+
raw['@loaded']({ w, h }, this)
|
|
762
|
+
}
|
|
763
|
+
: null
|
|
764
|
+
st._failedCb =
|
|
765
|
+
raw['@error'] && typeof raw['@error'] === 'function'
|
|
766
|
+
? (payload) => raw['@error'](payload, this)
|
|
767
|
+
: null
|
|
768
|
+
if (st.spriteTexture) {
|
|
769
|
+
if (prevL) st.spriteTexture.off('loaded', prevL)
|
|
770
|
+
if (prevF) st.spriteTexture.off('failed', prevF)
|
|
771
|
+
if (st._loadedCb) st.spriteTexture.on('loaded', st._loadedCb)
|
|
772
|
+
if (st._failedCb) st.spriteTexture.on('failed', st._failedCb)
|
|
773
|
+
}
|
|
774
|
+
},
|
|
660
775
|
/**
|
|
661
776
|
* Set an individual property on the node
|
|
662
777
|
*
|
|
@@ -823,6 +938,16 @@ const Element = {
|
|
|
823
938
|
|
|
824
939
|
Log.debug('Deleting Node', this.nodeId)
|
|
825
940
|
|
|
941
|
+
if (this[symbols.isSprite] === true && this._spriteState) {
|
|
942
|
+
const st = this._spriteState
|
|
943
|
+
if (st.spriteTexture) {
|
|
944
|
+
if (st._loadedCb) st.spriteTexture.off('loaded', st._loadedCb)
|
|
945
|
+
if (st._failedCb) st.spriteTexture.off('failed', st._failedCb)
|
|
946
|
+
}
|
|
947
|
+
if (st.subTextures) st.subTextures.clear()
|
|
948
|
+
this._spriteState = null
|
|
949
|
+
}
|
|
950
|
+
|
|
826
951
|
// Clear all pending debounce timeouts
|
|
827
952
|
const debounceProps = Object.keys(this.debounceTimeouts)
|
|
828
953
|
for (let i = 0; i < debounceProps.length; i++) {
|
package/src/engines/L3/launch.js
CHANGED
|
@@ -25,6 +25,7 @@ import { SCREEN_RESOLUTIONS, RENDER_QUALITIES } from '../../constants.js'
|
|
|
25
25
|
import colors from '../../lib/colors/colors.js'
|
|
26
26
|
import fontLoader from './fontLoader.js'
|
|
27
27
|
import shaderLoader from './shaderLoader.js'
|
|
28
|
+
import { platform } from '../../platform.js'
|
|
28
29
|
|
|
29
30
|
/** @type {RendererMain|{}} */
|
|
30
31
|
export let renderer = {}
|
|
@@ -73,6 +74,11 @@ const textureMemorySettings = (settings) => {
|
|
|
73
74
|
*
|
|
74
75
|
*/
|
|
75
76
|
export default (App, target, settings = {}) => {
|
|
77
|
+
const screenHeight = settings.platform ? settings.platform.screenHeight : platform.screenHeight
|
|
78
|
+
const hardwareConcurrency = settings.platform
|
|
79
|
+
? settings.platform.hardwareConcurrency
|
|
80
|
+
: platform.hardwareConcurrency
|
|
81
|
+
|
|
76
82
|
renderer = new RendererMain(
|
|
77
83
|
{
|
|
78
84
|
...{
|
|
@@ -84,12 +90,10 @@ export default (App, target, settings = {}) => {
|
|
|
84
90
|
deviceLogicalPixelRatio:
|
|
85
91
|
settings.pixelRatio ||
|
|
86
92
|
SCREEN_RESOLUTIONS[settings.screenResolution] ||
|
|
87
|
-
SCREEN_RESOLUTIONS[
|
|
93
|
+
SCREEN_RESOLUTIONS[screenHeight] ||
|
|
88
94
|
1,
|
|
89
95
|
numImageWorkers:
|
|
90
|
-
'webWorkersLimit' in settings
|
|
91
|
-
? settings.webWorkersLimit
|
|
92
|
-
: window.navigator.hardwareConcurrency || 2,
|
|
96
|
+
'webWorkersLimit' in settings ? settings.webWorkersLimit : hardwareConcurrency || 2,
|
|
93
97
|
clearColor: (settings.canvasColor && colors.normalize(settings.canvasColor)) || 0x00000000,
|
|
94
98
|
inspector: settings.inspector === true ? Inspector : undefined,
|
|
95
99
|
boundsMargin: settings.viewportMargin || 0,
|
|
@@ -100,7 +104,7 @@ export default (App, target, settings = {}) => {
|
|
|
100
104
|
textureMemory: textureMemorySettings(settings),
|
|
101
105
|
createImageBitmapSupport: 'auto',
|
|
102
106
|
targetFPS: 'maxFPS' in settings ? settings.maxFPS : 0,
|
|
103
|
-
platform:
|
|
107
|
+
platform: settings.rendererPlatform || null,
|
|
104
108
|
},
|
|
105
109
|
...(settings.advanced || {}),
|
|
106
110
|
},
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a sprite sheet frame from map + frame (template Sprite element path on L3).
|
|
3
|
+
* @param {import('../../component.js').BlitsElement} element
|
|
4
|
+
* @param {object} r - renderer
|
|
5
|
+
* @param {any} state - mutated sprite cache (see L3 element _spriteState)
|
|
6
|
+
* @returns {any|null} texture for the node
|
|
7
|
+
*/
|
|
8
|
+
export function resolveSpriteTexture(element, r, state) {
|
|
9
|
+
const image = element.props.raw['image']
|
|
10
|
+
if (image === undefined || image === null) {
|
|
11
|
+
return null
|
|
12
|
+
}
|
|
13
|
+
if (r === null || r === undefined || r.createTexture === undefined) {
|
|
14
|
+
return null
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (
|
|
18
|
+
state.spriteTexture === undefined ||
|
|
19
|
+
state.spriteTexture === null ||
|
|
20
|
+
state.currentSrc !== image
|
|
21
|
+
) {
|
|
22
|
+
state.spriteTexture = r.createTexture('ImageTexture', {
|
|
23
|
+
src: image,
|
|
24
|
+
})
|
|
25
|
+
state.currentSrc = image
|
|
26
|
+
state.subTextures = null
|
|
27
|
+
state.currentMap = null
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const map = element.props.raw['map']
|
|
31
|
+
|
|
32
|
+
if (state.currentMap !== map) {
|
|
33
|
+
state.currentMap = map
|
|
34
|
+
state.subTextures = null
|
|
35
|
+
}
|
|
36
|
+
const frame = element.props.raw['frame']
|
|
37
|
+
|
|
38
|
+
let options = null
|
|
39
|
+
if (map != null && frame != null) {
|
|
40
|
+
if (map.frames != null && map.frames !== undefined && frame in map.frames) {
|
|
41
|
+
options = Object.assign({}, map.defaults || {}, map.frames[frame])
|
|
42
|
+
} else if (frame in map) {
|
|
43
|
+
options = map[frame]
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if ((options === null || options === undefined) && typeof frame === 'object' && frame !== null) {
|
|
48
|
+
options = frame
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (options != null) {
|
|
52
|
+
const key = typeof frame === 'object' ? JSON.stringify(frame) : String(frame)
|
|
53
|
+
if (!state.subTextures) {
|
|
54
|
+
state.subTextures = new Map()
|
|
55
|
+
}
|
|
56
|
+
const cached = state.subTextures.get(key)
|
|
57
|
+
if (cached !== undefined) {
|
|
58
|
+
return cached
|
|
59
|
+
}
|
|
60
|
+
const subTexture = r.createTexture('SubTexture', {
|
|
61
|
+
texture: state.spriteTexture,
|
|
62
|
+
x: options.x,
|
|
63
|
+
y: options.y,
|
|
64
|
+
w: options.w,
|
|
65
|
+
h: options.h,
|
|
66
|
+
})
|
|
67
|
+
state.subTextures.set(key, subTexture)
|
|
68
|
+
return subTexture
|
|
69
|
+
}
|
|
70
|
+
return state.spriteTexture
|
|
71
|
+
}
|
package/src/focus/focus.js
CHANGED
|
@@ -21,7 +21,7 @@ import Settings from '../settings.js'
|
|
|
21
21
|
import { DEFAULT_HOLD_TIMEOUT_MS } from '../constants.js'
|
|
22
22
|
import { Log } from '../lib/log.js'
|
|
23
23
|
import { getAncestors } from './helpers.js'
|
|
24
|
-
import
|
|
24
|
+
import { platform } from '../platform.js'
|
|
25
25
|
|
|
26
26
|
let focusedComponent = null
|
|
27
27
|
let focusChain = []
|
|
@@ -136,8 +136,11 @@ const setFocus = (component, event) => {
|
|
|
136
136
|
focusedComponent = component
|
|
137
137
|
component[symbols.lifecycle].state = 'focus'
|
|
138
138
|
|
|
139
|
-
if (event
|
|
140
|
-
const internalEvent =
|
|
141
|
-
|
|
139
|
+
if (platform.isKeyboardEvent && platform.isKeyboardEvent(event) && platform.dispatchEvent) {
|
|
140
|
+
const internalEvent = platform.createKeyboardEvent
|
|
141
|
+
? platform.createKeyboardEvent('keydown', event)
|
|
142
|
+
: event
|
|
143
|
+
internalEvent[symbols.internalEvent] = true
|
|
144
|
+
platform.dispatchEvent(internalEvent)
|
|
142
145
|
}
|
|
143
146
|
}
|
package/src/launch.js
CHANGED
|
@@ -19,6 +19,7 @@ import Settings from './settings.js'
|
|
|
19
19
|
import { initLog, Log } from './lib/log.js'
|
|
20
20
|
import engine from './engine.js'
|
|
21
21
|
import blitsPackageInfo from '../package.json' with { type: 'json' }
|
|
22
|
+
import { configurePlatform } from './platform.js'
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* @typedef {Object} Font
|
|
@@ -86,10 +87,12 @@ async function rendererVersion() {
|
|
|
86
87
|
* @property {number} [holdTimeout] - Time after which a key press is considered a hold
|
|
87
88
|
* @property {HTMLCanvasElement} [canvas] - Custom canvas object used to render the App
|
|
88
89
|
* @property {number} [textureProcessingTimeLimit] - Max time renderer can process textures in a frame
|
|
90
|
+
* @property {import('@lightningjs/renderer').RendererMainSettings['platform']} [rendererPlatform] - Custom platform used by the renderer
|
|
89
91
|
* @property {Partial<import('@lightningjs/renderer').RendererMainSettings>} [advanced] - Advanced renderer settings
|
|
90
92
|
* @property {boolean} [announcer] - Whether or not the announcer should be activated on initialization
|
|
91
93
|
* @property {boolean} [enableMouse] - Enable mouse support (hover and click-to-focus). Defaults to false.
|
|
92
94
|
* @property {number} [maxFPS] - Maximum FPS
|
|
95
|
+
* @property {function} [platform] - Platform factory for non-browser environments
|
|
93
96
|
*/
|
|
94
97
|
|
|
95
98
|
/**
|
|
@@ -109,10 +112,30 @@ async function rendererVersion() {
|
|
|
109
112
|
* @returns {void}
|
|
110
113
|
*/
|
|
111
114
|
export default (App, target, settings) => {
|
|
115
|
+
let warnLegacyRendererPlatform = false
|
|
116
|
+
|
|
117
|
+
if (settings !== undefined && 'platform' in settings) {
|
|
118
|
+
if (typeof settings.platform === 'function') {
|
|
119
|
+
settings.platform = configurePlatform(settings.platform)
|
|
120
|
+
} else {
|
|
121
|
+
if ('rendererPlatform' in settings === false) {
|
|
122
|
+
settings.rendererPlatform = settings.platform
|
|
123
|
+
}
|
|
124
|
+
delete settings.platform
|
|
125
|
+
warnLegacyRendererPlatform = true
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
112
129
|
Settings.set(settings)
|
|
113
130
|
|
|
114
131
|
initLog()
|
|
115
132
|
|
|
133
|
+
if (warnLegacyRendererPlatform === true) {
|
|
134
|
+
Log.warn(
|
|
135
|
+
'Passing a renderer platform via settings.platform is deprecated. Use settings.rendererPlatform instead.'
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
116
139
|
rendererVersion().then((v) => {
|
|
117
140
|
Log.info('Blits Version ', blitsPackageInfo.version)
|
|
118
141
|
Log.info('Renderer Version ', v)
|
|
@@ -206,6 +206,10 @@ const generateElementCode = function (
|
|
|
206
206
|
renderCode.push(`elementConfigs[${counter}][Symbol.for('isSlot')] = true`)
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
if (templateObject[Symbol.for('componentType')] === 'Sprite') {
|
|
210
|
+
renderCode.push(`elementConfigs[${counter}][Symbol.for('isSprite')] = true`)
|
|
211
|
+
}
|
|
212
|
+
|
|
209
213
|
if (options.holder) {
|
|
210
214
|
renderCode.push(`elementConfigs[${counter}]['holder'] = true`)
|
|
211
215
|
}
|
|
@@ -611,11 +615,16 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
611
615
|
if (
|
|
612
616
|
templateObject[Symbol.for('componentType')] === 'Element' ||
|
|
613
617
|
templateObject[Symbol.for('componentType')] === 'Slot' ||
|
|
614
|
-
templateObject[Symbol.for('componentType')] === 'Text'
|
|
618
|
+
templateObject[Symbol.for('componentType')] === 'Text' ||
|
|
619
|
+
templateObject[Symbol.for('componentType')] === 'Sprite' ||
|
|
620
|
+
templateObject[Symbol.for('componentType')] === 'Layout'
|
|
615
621
|
) {
|
|
616
622
|
if (templateObject[Symbol.for('componentType')] === 'Text') {
|
|
617
623
|
templateObject.__textnode = 'true'
|
|
618
624
|
}
|
|
625
|
+
if (templateObject[Symbol.for('componentType')] === 'Layout') {
|
|
626
|
+
templateObject.__layout = 'true'
|
|
627
|
+
}
|
|
619
628
|
generateElementCode.call(ctx, templateObject, parent, {
|
|
620
629
|
key: 'scope.key',
|
|
621
630
|
component: 'scope.',
|
|
@@ -788,7 +797,8 @@ const generateCode = function (templateObject, parent = false, options = {}) {
|
|
|
788
797
|
childTemplateObject[Symbol.for('componentType')] === 'Element' ||
|
|
789
798
|
childTemplateObject[Symbol.for('componentType')] === 'Slot' ||
|
|
790
799
|
childTemplateObject[Symbol.for('componentType')] === 'Text' ||
|
|
791
|
-
childTemplateObject[Symbol.for('componentType')] === 'Layout'
|
|
800
|
+
childTemplateObject[Symbol.for('componentType')] === 'Layout' ||
|
|
801
|
+
childTemplateObject[Symbol.for('componentType')] === 'Sprite'
|
|
792
802
|
) {
|
|
793
803
|
if (childTemplateObject[Symbol.for('componentType')] === 'Text') {
|
|
794
804
|
childTemplateObject.__textnode = 'true'
|
|
@@ -200,8 +200,12 @@ const processComputedBlock = (configObject) => {
|
|
|
200
200
|
currentPos = skipNonCode(computedObj, currentPos)
|
|
201
201
|
if (currentPos >= computedObj.length - 1) break
|
|
202
202
|
|
|
203
|
-
// Find the next function name (computed properties are `name() { ... }`
|
|
204
|
-
|
|
203
|
+
// Find the next function name (computed properties are `name() { ... }`
|
|
204
|
+
// or long-form `name: function() { ... }`)
|
|
205
|
+
const functionNameMatch = /^(\w+)\s*(?:\(\)|:\s*function\s*\([^)]*\))\s*/.exec(
|
|
206
|
+
computedObj.substring(currentPos)
|
|
207
|
+
)
|
|
208
|
+
|
|
205
209
|
if (!functionNameMatch) {
|
|
206
210
|
const nextPos = skipComputedMember(computedObj, currentPos)
|
|
207
211
|
if (nextPos === -1) break
|
package/src/lib/symbols.js
CHANGED
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
* @property {symbol} components
|
|
62
62
|
* @property {symbol} config
|
|
63
63
|
* @property {symbol} isSlot
|
|
64
|
+
* @property {symbol} isSprite
|
|
64
65
|
* @property {symbol} props
|
|
65
66
|
* @property {symbol} parent
|
|
66
67
|
* @property {symbol} slots
|
|
@@ -68,6 +69,7 @@
|
|
|
68
69
|
* @property {symbol} isComponent
|
|
69
70
|
* @property {symbol} effects
|
|
70
71
|
* @property {symbol} removeGlobalEffects
|
|
72
|
+
* @property {symbol} tagContent
|
|
71
73
|
*/
|
|
72
74
|
|
|
73
75
|
/**
|
|
@@ -126,6 +128,8 @@ export default {
|
|
|
126
128
|
config: Symbol.for('config'),
|
|
127
129
|
// Symbol 'isSlot' utilized within generated code
|
|
128
130
|
isSlot: Symbol.for('isSlot'),
|
|
131
|
+
// Symbol 'isSprite' utilized within generated code (native Sprite on L3 element)
|
|
132
|
+
isSprite: Symbol.for('isSprite'),
|
|
129
133
|
// Symbol 'props' utilized within generated code
|
|
130
134
|
props: Symbol.for('props'),
|
|
131
135
|
// Symbol 'slots' utilized within generated code
|
package/src/platform.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 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
|
+
const globalScope = globalThis
|
|
19
|
+
|
|
20
|
+
const createKeyboardEventFactory = (KeyboardEventConstructor) => {
|
|
21
|
+
if (KeyboardEventConstructor === undefined) return undefined
|
|
22
|
+
|
|
23
|
+
return (type, init = {}) => {
|
|
24
|
+
const event = new KeyboardEventConstructor(type, init)
|
|
25
|
+
if ('keyCode' in init && event.keyCode !== init.keyCode) {
|
|
26
|
+
Object.defineProperty(event, 'keyCode', {
|
|
27
|
+
get: () => init.keyCode,
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
return event
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const browserPlatform = () => {
|
|
35
|
+
const windowRef = globalScope.window
|
|
36
|
+
const documentRef = globalScope.document || (windowRef && windowRef.document)
|
|
37
|
+
const selfRef = globalScope.self || windowRef || globalScope
|
|
38
|
+
const navigatorRef =
|
|
39
|
+
globalScope.navigator || (windowRef && windowRef.navigator) || (selfRef && selfRef.navigator)
|
|
40
|
+
const KeyboardEventConstructor =
|
|
41
|
+
globalScope.KeyboardEvent || (windowRef && windowRef.KeyboardEvent)
|
|
42
|
+
let localStorage
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
localStorage = (windowRef && windowRef.localStorage) || globalScope.localStorage
|
|
46
|
+
} catch {
|
|
47
|
+
localStorage = undefined
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const createKeyboardEvent = createKeyboardEventFactory(KeyboardEventConstructor)
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
input: documentRef,
|
|
54
|
+
viewport: windowRef,
|
|
55
|
+
dispatchEvent:
|
|
56
|
+
documentRef && documentRef.dispatchEvent
|
|
57
|
+
? documentRef.dispatchEvent.bind(documentRef)
|
|
58
|
+
: undefined,
|
|
59
|
+
localStorage,
|
|
60
|
+
getCookie: () => (documentRef && documentRef.cookie) || '',
|
|
61
|
+
setCookie: (value) => {
|
|
62
|
+
if (documentRef !== undefined) documentRef.cookie = value
|
|
63
|
+
},
|
|
64
|
+
historyBack: () => {
|
|
65
|
+
if (windowRef && windowRef.history && windowRef.history.back) windowRef.history.back()
|
|
66
|
+
},
|
|
67
|
+
screenHeight: windowRef && windowRef.innerHeight,
|
|
68
|
+
hardwareConcurrency: navigatorRef && navigatorRef.hardwareConcurrency,
|
|
69
|
+
userAgent: navigatorRef && navigatorRef.userAgent,
|
|
70
|
+
KeyboardEvent: KeyboardEventConstructor,
|
|
71
|
+
isKeyboardEvent:
|
|
72
|
+
KeyboardEventConstructor !== undefined
|
|
73
|
+
? (event) => event instanceof KeyboardEventConstructor
|
|
74
|
+
: undefined,
|
|
75
|
+
createKeyboardEvent,
|
|
76
|
+
SpeechSynthesisUtterance:
|
|
77
|
+
globalScope.SpeechSynthesisUtterance || (windowRef && windowRef.SpeechSynthesisUtterance),
|
|
78
|
+
speechSynthesis:
|
|
79
|
+
(selfRef && selfRef.speechSynthesis) || (windowRef && windowRef.speechSynthesis),
|
|
80
|
+
now:
|
|
81
|
+
globalScope.performance && globalScope.performance.now !== undefined
|
|
82
|
+
? globalScope.performance.now.bind(globalScope.performance)
|
|
83
|
+
: Date.now,
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export let platform = browserPlatform()
|
|
88
|
+
|
|
89
|
+
export const configurePlatform = (customPlatform) => {
|
|
90
|
+
const basePlatform = browserPlatform()
|
|
91
|
+
const resolvedCustomPlatform = customPlatform(basePlatform) || {}
|
|
92
|
+
|
|
93
|
+
platform = {
|
|
94
|
+
...basePlatform,
|
|
95
|
+
...resolvedCustomPlatform,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
platform.KeyboardEvent = platform.KeyboardEvent || basePlatform.KeyboardEvent
|
|
99
|
+
platform.isKeyboardEvent =
|
|
100
|
+
resolvedCustomPlatform.isKeyboardEvent ||
|
|
101
|
+
(platform.KeyboardEvent !== undefined
|
|
102
|
+
? (event) => event instanceof platform.KeyboardEvent
|
|
103
|
+
: basePlatform.isKeyboardEvent)
|
|
104
|
+
platform.createKeyboardEvent =
|
|
105
|
+
resolvedCustomPlatform.createKeyboardEvent ||
|
|
106
|
+
createKeyboardEventFactory(platform.KeyboardEvent) ||
|
|
107
|
+
basePlatform.createKeyboardEvent
|
|
108
|
+
platform.getCookie = platform.getCookie || basePlatform.getCookie
|
|
109
|
+
platform.setCookie = platform.setCookie || basePlatform.setCookie
|
|
110
|
+
platform.historyBack = platform.historyBack || basePlatform.historyBack
|
|
111
|
+
platform.SpeechSynthesisUtterance =
|
|
112
|
+
platform.SpeechSynthesisUtterance || basePlatform.SpeechSynthesisUtterance
|
|
113
|
+
platform.speechSynthesis = platform.speechSynthesis || basePlatform.speechSynthesis
|
|
114
|
+
platform.now = platform.now || basePlatform.now
|
|
115
|
+
|
|
116
|
+
return platform
|
|
117
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { WebPlatform, WebPlatformNext, WebPlatformChrome50, WebPlatformLegacy } from '@lightningjs/renderer/platforms'
|
package/src/platforms.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
export {
|
|
19
|
+
WebPlatform,
|
|
20
|
+
WebPlatformNext,
|
|
21
|
+
WebPlatformChrome50,
|
|
22
|
+
WebPlatformLegacy,
|
|
23
|
+
} from '@lightningjs/renderer/platforms'
|