@lightningjs/blits 2.0.0-beta.1 → 2.0.0-beta.10
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 +83 -0
- package/README.md +2 -0
- package/element-test-full.txt +0 -0
- package/index.d.ts +114 -14
- package/package.json +28 -8
- package/scripts/lint.js +17 -0
- package/scripts/prepublishOnly.js +15 -6
- package/scripts/prepush.js +25 -7
- package/src/announcer/announcer.js +54 -6
- package/src/announcer/speechSynthesis.js +156 -37
- package/src/application.js +98 -3
- package/src/component/base/methods.js +5 -2
- package/src/component/base/router.js +6 -0
- package/src/component/base/timeouts_intervals.js +56 -0
- package/src/component/setup/routes.js +5 -0
- package/src/component/setup/state.js +2 -0
- package/src/component.js +64 -24
- package/src/components/Circle.js +5 -3
- package/src/components/FPScounter.js +1591 -1577
- package/src/components/RouterView.js +141 -124
- package/src/components/Sprite.js +65 -8
- package/src/components/index.js +0 -2
- package/src/constants.js +17 -0
- package/src/engine.js +17 -0
- package/src/engines/L3/element.js +101 -7
- package/src/engines/L3/fontLoader.js +17 -0
- package/src/engines/L3/index.js +17 -0
- package/src/engines/L3/launch.js +4 -1
- package/src/engines/L3/shaderLoader.js +17 -0
- package/src/engines/index.js +17 -0
- package/src/{focus.js → focus/focus.js} +6 -18
- package/src/focus/helpers.js +31 -0
- package/src/focus/hover.js +94 -0
- package/src/helpers/fetchJson.js +4 -6
- package/src/launch.js +1 -0
- package/src/lib/codegenerator/generator.js +55 -9
- package/src/lib/lifecycle.js +34 -3
- package/src/lib/log.js +4 -4
- package/src/lib/precompiler/precompiler.js +23 -14
- package/src/lib/reactivity/effect.js +3 -2
- package/src/lib/reactivityguard/computedprops.js +113 -28
- package/src/lib/shaders/shaders.js +2 -1
- package/src/lib/symbols.js +19 -0
- package/src/lib/utils.js +17 -0
- package/src/plugin.js +17 -0
- package/src/plugins/appstate.d.ts +26 -0
- package/src/plugins/index.d.ts +28 -0
- package/src/plugins/language.d.ts +37 -0
- package/src/plugins/storage/localCookie.js +4 -6
- package/src/plugins/storage/storage.d.ts +31 -0
- package/src/plugins/theme.d.ts +43 -0
- package/src/plugins/theme.js +30 -3
- package/src/router/router.js +78 -14
- package/test-output.txt +0 -0
- package/vite/inject-dev-config.js +17 -0
- package/vite/preCompiler.js +15 -5
- package/vscode/data/template-attributes.json +335 -86
package/src/engines/L3/index.js
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
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
|
+
|
|
1
18
|
import Element from './element.js'
|
|
2
19
|
import Launch from './launch.js'
|
|
3
20
|
|
package/src/engines/L3/launch.js
CHANGED
|
@@ -100,6 +100,7 @@ export default (App, target, settings = {}) => {
|
|
|
100
100
|
textureMemory: textureMemorySettings(settings),
|
|
101
101
|
createImageBitmapSupport: 'auto',
|
|
102
102
|
targetFPS: 'maxFPS' in settings ? settings.maxFPS : 0,
|
|
103
|
+
platform: 'platform' in settings ? settings.platform : null,
|
|
103
104
|
},
|
|
104
105
|
...(settings.advanced || {}),
|
|
105
106
|
},
|
|
@@ -118,7 +119,9 @@ export default (App, target, settings = {}) => {
|
|
|
118
119
|
|
|
119
120
|
shaderLoader()
|
|
120
121
|
fontLoader()
|
|
121
|
-
|
|
122
|
+
// Defer app initialization until after the current call stack is cleared,
|
|
123
|
+
// allowing the renderer to finish setting up before the app starts creating components
|
|
124
|
+
Promise.resolve().then(initApp)
|
|
122
125
|
|
|
123
126
|
return renderer
|
|
124
127
|
}
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 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
|
+
|
|
1
18
|
import Settings from '../../settings.js'
|
|
2
19
|
import { renderer } from './launch.js'
|
|
3
20
|
import * as webglShaders from '@lightningjs/renderer/webgl/shaders'
|
package/src/engines/index.js
CHANGED
|
@@ -1 +1,18 @@
|
|
|
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
|
+
|
|
1
18
|
export { default as L3 } from './L3/index.js'
|
|
@@ -15,11 +15,12 @@
|
|
|
15
15
|
* SPDX-License-Identifier: Apache-2.0
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import symbols from '
|
|
19
|
-
import { state } from '
|
|
20
|
-
import Settings from '
|
|
21
|
-
import { DEFAULT_HOLD_TIMEOUT_MS } from '
|
|
22
|
-
import { Log } from '
|
|
18
|
+
import symbols from '../lib/symbols.js'
|
|
19
|
+
import { state } from '../router/router.js'
|
|
20
|
+
import Settings from '../settings.js'
|
|
21
|
+
import { DEFAULT_HOLD_TIMEOUT_MS } from '../constants.js'
|
|
22
|
+
import { Log } from '../lib/log.js'
|
|
23
|
+
import { getAncestors } from './helpers.js'
|
|
23
24
|
|
|
24
25
|
let focusedComponent = null
|
|
25
26
|
let focusChain = []
|
|
@@ -99,19 +100,6 @@ export default {
|
|
|
99
100
|
},
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
/**
|
|
103
|
-
* Recursive function that retrieves the ancestors of a component
|
|
104
|
-
* @param {Array} components
|
|
105
|
-
* @returns array components
|
|
106
|
-
*/
|
|
107
|
-
const getAncestors = (components) => {
|
|
108
|
-
if (components[0][symbols.parent] !== undefined) {
|
|
109
|
-
components.unshift(components[0][symbols.parent])
|
|
110
|
-
return getAncestors(components)
|
|
111
|
-
}
|
|
112
|
-
return components
|
|
113
|
-
}
|
|
114
|
-
|
|
115
103
|
/**
|
|
116
104
|
* Get the component in the ancestors chain that has a handler for a certain key code
|
|
117
105
|
* @param {Object} component
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 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 symbols from '../lib/symbols.js'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Recursive function that retrieves the ancestors of a component
|
|
22
|
+
* @param {Array} components
|
|
23
|
+
* @returns array components
|
|
24
|
+
*/
|
|
25
|
+
export const getAncestors = (components) => {
|
|
26
|
+
if (components[0][symbols.parent] !== undefined) {
|
|
27
|
+
components.unshift(components[0][symbols.parent])
|
|
28
|
+
return getAncestors(components)
|
|
29
|
+
}
|
|
30
|
+
return components
|
|
31
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 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 { Log } from '../lib/log.js'
|
|
19
|
+
import { getAncestors } from './helpers.js'
|
|
20
|
+
import symbols from '../lib/symbols.js'
|
|
21
|
+
|
|
22
|
+
let hoveredComponent = null
|
|
23
|
+
let hoverChain = []
|
|
24
|
+
|
|
25
|
+
export default {
|
|
26
|
+
get() {
|
|
27
|
+
return hoveredComponent
|
|
28
|
+
},
|
|
29
|
+
set(component) {
|
|
30
|
+
if (component === undefined || component.eol === true) return
|
|
31
|
+
|
|
32
|
+
// early return if already hovered
|
|
33
|
+
if (component === hoveredComponent) return
|
|
34
|
+
|
|
35
|
+
if (hoveredComponent === null) {
|
|
36
|
+
hoverChain = getAncestors([component])
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// unhover currently hovered components
|
|
40
|
+
if (hoveredComponent !== null) {
|
|
41
|
+
if (hoverChain[hoverChain.length - 1] === component.$parent) {
|
|
42
|
+
hoverChain.push(component)
|
|
43
|
+
} else {
|
|
44
|
+
const newhoverChain = getAncestors([component])
|
|
45
|
+
let i = hoverChain.length
|
|
46
|
+
while (i--) {
|
|
47
|
+
// don't unhover when part of the new hover chain
|
|
48
|
+
if (newhoverChain.indexOf(hoverChain[i]) > -1) break
|
|
49
|
+
// skip if component is destroyed
|
|
50
|
+
if (hoverChain[i].eol !== true) {
|
|
51
|
+
hoverChain[i][symbols.lifecycle].state = 'unhover'
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
hoverChain = newhoverChain
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ensure that all components in the hover path have hover state
|
|
59
|
+
let i = 0
|
|
60
|
+
while (i < hoverChain.length - 1) {
|
|
61
|
+
// skip if component is destroyed
|
|
62
|
+
if (hoverChain[i].eol !== true) {
|
|
63
|
+
hoverChain[i][symbols.lifecycle].state = 'hover'
|
|
64
|
+
}
|
|
65
|
+
i++
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
setHover(component)
|
|
69
|
+
},
|
|
70
|
+
clear() {
|
|
71
|
+
if (hoveredComponent === null) return
|
|
72
|
+
for (let i = 0; i < hoverChain.length; i++) {
|
|
73
|
+
if (hoverChain[i].eol !== true) {
|
|
74
|
+
hoverChain[i][symbols.lifecycle].state = 'unhover'
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
hoveredComponent = null
|
|
78
|
+
hoverChain = []
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Set the hover to the Component
|
|
84
|
+
* @param {Object} component - The component to hover
|
|
85
|
+
*/
|
|
86
|
+
const setHover = (component) => {
|
|
87
|
+
Log.info(
|
|
88
|
+
'\nHover chain:\n',
|
|
89
|
+
hoverChain.map((c, index) => '\t'.repeat(index) + '↳ ' + c.$componentId).join('\n')
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
hoveredComponent = component
|
|
93
|
+
component[symbols.lifecycle].state = 'hover'
|
|
94
|
+
}
|
package/src/helpers/fetchJson.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Copyright 2020 Metrological
|
|
6
|
-
*
|
|
7
|
-
* Licensed under the Apache License, Version 2.0 (the License);
|
|
2
|
+
* Copyright 2024 Comcast Cable Communications Management, LLC
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
4
|
* you may not use this file except in compliance with the License.
|
|
9
5
|
* You may obtain a copy of the License at
|
|
10
6
|
*
|
|
@@ -15,6 +11,8 @@
|
|
|
15
11
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
12
|
* See the License for the specific language governing permissions and
|
|
17
13
|
* limitations under the License.
|
|
14
|
+
*
|
|
15
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
18
16
|
*/
|
|
19
17
|
|
|
20
18
|
export default (file) => {
|
package/src/launch.js
CHANGED
|
@@ -88,6 +88,7 @@ async function rendererVersion() {
|
|
|
88
88
|
* @property {number} [textureProcessingTimeLimit] - Max time renderer can process textures in a frame
|
|
89
89
|
* @property {Partial<import('@lightningjs/renderer').RendererMainSettings>} [advanced] - Advanced renderer settings
|
|
90
90
|
* @property {boolean} [announcer] - Whether or not the announcer should be activated on initialization
|
|
91
|
+
* @property {boolean} [enableMouse] - Enable mouse support (hover and click-to-focus). Defaults to false.
|
|
91
92
|
* @property {number} [maxFPS] - Maximum FPS
|
|
92
93
|
*/
|
|
93
94
|
|
|
@@ -163,6 +163,10 @@ const generateElementCode = function (
|
|
|
163
163
|
|
|
164
164
|
renderCode.push(`elementConfigs[${counter}] = {}`)
|
|
165
165
|
|
|
166
|
+
if (counter === 0) {
|
|
167
|
+
renderCode.push(`elementConfigs[${counter}]['___wrapper'] = true `)
|
|
168
|
+
}
|
|
169
|
+
|
|
166
170
|
if (options.forloop) {
|
|
167
171
|
renderCode.push(`if(${elm} === undefined) {`)
|
|
168
172
|
}
|
|
@@ -182,6 +186,10 @@ const generateElementCode = function (
|
|
|
182
186
|
renderCode.push(`elementConfigs[${counter}][Symbol.for('isSlot')] = true`)
|
|
183
187
|
}
|
|
184
188
|
|
|
189
|
+
if (options.holder) {
|
|
190
|
+
renderCode.push(`elementConfigs[${counter}]['holder'] = true`)
|
|
191
|
+
}
|
|
192
|
+
|
|
185
193
|
Object.keys(templateObject).forEach((key) => {
|
|
186
194
|
if (key === 'slot') {
|
|
187
195
|
renderCode.push(`
|
|
@@ -325,9 +333,11 @@ const generateComponentCode = function (
|
|
|
325
333
|
|
|
326
334
|
const children = templateObject.children
|
|
327
335
|
delete templateObject.children
|
|
336
|
+
// Capture holder counter before generating element code (which may process children and increment counter)
|
|
337
|
+
const holderCounter = counter
|
|
328
338
|
generateElementCode.call(this, templateObject, parent, { ...options, ...{ holder: true } })
|
|
329
339
|
|
|
330
|
-
parent = options.key ? `elms[${
|
|
340
|
+
parent = options.key ? `elms[${holderCounter}][${options.key}]` : `elms[${holderCounter}]`
|
|
331
341
|
|
|
332
342
|
counter++
|
|
333
343
|
|
|
@@ -396,6 +406,21 @@ const generateComponentCode = function (
|
|
|
396
406
|
}
|
|
397
407
|
`)
|
|
398
408
|
|
|
409
|
+
if (isDev === true) {
|
|
410
|
+
const templateTagName = templateObject[Symbol.for('componentType')]
|
|
411
|
+
const holderElm = options.key
|
|
412
|
+
? `elms[${holderCounter}][${options.key}]`
|
|
413
|
+
: `elms[${holderCounter}]`
|
|
414
|
+
const componentDisplayName = `typeof componentType === 'string'
|
|
415
|
+
? componentType
|
|
416
|
+
: (componentType?.[Symbol.for('componentType')] || '${templateTagName}')`
|
|
417
|
+
renderCode.push(`
|
|
418
|
+
if (${holderElm} !== undefined && typeof ${holderElm}.setInspectorMetadata === 'function') {
|
|
419
|
+
${holderElm}.setInspectorMetadata({ 'blits-componentType': ${componentDisplayName} })
|
|
420
|
+
}
|
|
421
|
+
`)
|
|
422
|
+
}
|
|
423
|
+
|
|
399
424
|
this.cleanupCode.push(`components[${counter}] = null`)
|
|
400
425
|
|
|
401
426
|
if (options.forloop) {
|
|
@@ -451,7 +476,7 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
451
476
|
.replace(')', '')
|
|
452
477
|
.split(/\s*,\s*/)
|
|
453
478
|
|
|
454
|
-
const scopeRegex = new RegExp(`(scope\\.(?!${item}\\.|${index}|key)(
|
|
479
|
+
const scopeRegex = new RegExp(`(scope\\.(?!${item}\\.|${index}|key)([\\w$]+))`, 'gi')
|
|
455
480
|
|
|
456
481
|
// local context
|
|
457
482
|
const ctx = {
|
|
@@ -524,10 +549,16 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
524
549
|
|
|
525
550
|
component !== null && component[Symbol.for('removeGlobalEffects')](effects[${forStartCounter}])
|
|
526
551
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
const
|
|
530
|
-
|
|
552
|
+
const effectsToRemove = new Set(effects[${forStartCounter}].slice(0))
|
|
553
|
+
if (effectsToRemove.size > 0) {
|
|
554
|
+
const componentEffects = component?.[Symbol.for('effects')] || []
|
|
555
|
+
let writeIndex = 0
|
|
556
|
+
for (let readIndex = 0; readIndex < componentEffects.length; readIndex++) {
|
|
557
|
+
if (!effectsToRemove.has(componentEffects[readIndex])) {
|
|
558
|
+
componentEffects[writeIndex++] = componentEffects[readIndex]
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
componentEffects.length = writeIndex
|
|
531
562
|
}
|
|
532
563
|
|
|
533
564
|
effects[${forStartCounter}].length = 0
|
|
@@ -633,11 +664,21 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
633
664
|
const forEndCounter = counter
|
|
634
665
|
|
|
635
666
|
for (let i = forStartCounter; i <= forEndCounter; i++) {
|
|
636
|
-
|
|
667
|
+
if (i == forStartCounter) {
|
|
668
|
+
destroyCode.push(`
|
|
637
669
|
elms[${i}][key] && elms[${i}][key].destroy()
|
|
638
670
|
elms[${i}][key] = null
|
|
639
671
|
delete elms[${i}][key]
|
|
640
672
|
`)
|
|
673
|
+
} else {
|
|
674
|
+
destroyCode.push(`
|
|
675
|
+
if (elms[${i}][key] && elms[${i}][key].$componentId !== undefined) {
|
|
676
|
+
elms[${i}][key] && elms[${i}][key].destroy()
|
|
677
|
+
}
|
|
678
|
+
elms[${i}][key] = null
|
|
679
|
+
delete elms[${i}][key]
|
|
680
|
+
`)
|
|
681
|
+
}
|
|
641
682
|
}
|
|
642
683
|
destroyCode.push(`
|
|
643
684
|
}
|
|
@@ -825,8 +866,13 @@ const cast = (val = '', key = false, component = 'component.') => {
|
|
|
825
866
|
}
|
|
826
867
|
// @-listener
|
|
827
868
|
else if (key.startsWith('@') && val) {
|
|
828
|
-
const
|
|
829
|
-
|
|
869
|
+
const trimmed = val.trim()
|
|
870
|
+
if (/^\$?\w+$/.test(trimmed)) {
|
|
871
|
+
const c = component.slice(0, -1)
|
|
872
|
+
castedValue = `${c}['${trimmed.replace('$', '')}'] && ${c}['${trimmed.replace('$', '')}'].bind(${c})`
|
|
873
|
+
} else {
|
|
874
|
+
castedValue = interpolate(trimmed, component)
|
|
875
|
+
}
|
|
830
876
|
}
|
|
831
877
|
// dynamic value
|
|
832
878
|
else if (val.startsWith('$')) {
|
package/src/lib/lifecycle.js
CHANGED
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
import { Log } from './log.js'
|
|
19
19
|
import { emit, privateEmit } from './hooks.js'
|
|
20
20
|
import symbols from './symbols.js'
|
|
21
|
+
import Settings from '../settings.js'
|
|
22
|
+
|
|
23
|
+
let inspectorEnabled = null
|
|
21
24
|
|
|
22
25
|
/**
|
|
23
26
|
* List of valid lifecycle states for a component.
|
|
@@ -28,6 +31,8 @@ const states = [
|
|
|
28
31
|
'ready', // fired when component instantiated, reactivity setup done and template spawned
|
|
29
32
|
'focus', // fired when receiving focus (can occur multiple times)
|
|
30
33
|
'unfocus', // fired when losing focus (can occur multiple times)
|
|
34
|
+
'hover', // fired when pointer enters the component (mouse support only; can occur multiple times)
|
|
35
|
+
'unhover', // fired when pointer leaves the component (mouse support only; can occur multiple times)
|
|
31
36
|
'destroy', // fired when component is destroyed and removed
|
|
32
37
|
'attach', // fired when entering the viewport margin and attached to the render tree
|
|
33
38
|
'detach', // fired when leaving the viewport margin and detached from the render tree
|
|
@@ -81,9 +86,35 @@ export default {
|
|
|
81
86
|
privateEmit(v, this.component[symbols.identifier], this.component)
|
|
82
87
|
// emit 'public' hook
|
|
83
88
|
emit(v, this.component[symbols.identifier], this.component)
|
|
84
|
-
// update the built-in hasFocus state variable
|
|
85
|
-
if (v === 'focus'
|
|
86
|
-
|
|
89
|
+
// update the built-in $hasFocus state variable
|
|
90
|
+
if (v === 'focus' || v === 'unfocus') {
|
|
91
|
+
if (inspectorEnabled === null) {
|
|
92
|
+
inspectorEnabled = Settings.get('inspector', false)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// update the built-in isHovered state variable
|
|
96
|
+
if (v === 'hover') this.component[symbols.state].$isHovered = true
|
|
97
|
+
if (v === 'unhover') this.component[symbols.state].$isHovered = false
|
|
98
|
+
if (v === 'focus') {
|
|
99
|
+
this.component[symbols.state].$hasFocus = true
|
|
100
|
+
if (
|
|
101
|
+
inspectorEnabled === true &&
|
|
102
|
+
this.component[symbols.holder] &&
|
|
103
|
+
typeof this.component[symbols.holder].setInspectorMetadata === 'function'
|
|
104
|
+
) {
|
|
105
|
+
this.component[symbols.holder].setInspectorMetadata({ 'blits-hasFocus': true })
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (v === 'unfocus') {
|
|
109
|
+
this.component[symbols.state].$hasFocus = false
|
|
110
|
+
if (
|
|
111
|
+
inspectorEnabled === true &&
|
|
112
|
+
this.component[symbols.holder] &&
|
|
113
|
+
typeof this.component[symbols.holder].setInspectorMetadata === 'function'
|
|
114
|
+
) {
|
|
115
|
+
this.component[symbols.holder].setInspectorMetadata({ 'blits-hasFocus': false })
|
|
116
|
+
}
|
|
117
|
+
}
|
|
87
118
|
}
|
|
88
119
|
},
|
|
89
120
|
}
|
package/src/lib/log.js
CHANGED
|
@@ -46,7 +46,7 @@ const logger = (context) => {
|
|
|
46
46
|
return (
|
|
47
47
|
((level >= 1 || (Array.isArray(level) && level.indexOf('info') > -1)) &&
|
|
48
48
|
console.info.bind(
|
|
49
|
-
|
|
49
|
+
console,
|
|
50
50
|
`%c ⚡️ ${context} %c ${time()}`,
|
|
51
51
|
'background-color: #0284c7; color: white; padding: 3px 6px 3px 1px; border-radius: 3px',
|
|
52
52
|
'color: ##94a3b8;'
|
|
@@ -61,7 +61,7 @@ const logger = (context) => {
|
|
|
61
61
|
return (
|
|
62
62
|
((level >= 1 || (Array.isArray(level) && level.indexOf('warn') > -1)) &&
|
|
63
63
|
console.warn.bind(
|
|
64
|
-
|
|
64
|
+
console,
|
|
65
65
|
`%c ⚡️ ${context} %c ${time()}`,
|
|
66
66
|
'background-color: #fbbf24; color: white; padding: 3px 6px 3px 1px; border-radius: 3px',
|
|
67
67
|
'color: ##94a3b8;'
|
|
@@ -76,7 +76,7 @@ const logger = (context) => {
|
|
|
76
76
|
return (
|
|
77
77
|
((level >= 1 || (Array.isArray(level) && level.indexOf('error') > -1)) &&
|
|
78
78
|
console.error.bind(
|
|
79
|
-
|
|
79
|
+
console,
|
|
80
80
|
`%c ⚡️ ${context} %c ${time()}`,
|
|
81
81
|
'background-color: #dc2626; color: white; padding: 3px 6px 3px 1px; border-radius: 3px',
|
|
82
82
|
'color: ##94a3b8;'
|
|
@@ -91,7 +91,7 @@ const logger = (context) => {
|
|
|
91
91
|
return (
|
|
92
92
|
((level >= 2 || (Array.isArray(level) && level.indexOf('debug') > -1)) &&
|
|
93
93
|
console.debug.bind(
|
|
94
|
-
|
|
94
|
+
console,
|
|
95
95
|
`%c ⚡️ ${context} %c (${new Date().toLocaleTimeString([], {
|
|
96
96
|
hour: '2-digit',
|
|
97
97
|
minute: '2-digit',
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import parser from '../templateparser/parser.js'
|
|
19
19
|
import generator from '../codegenerator/generator.js'
|
|
20
|
+
import MagicString from 'magic-string'
|
|
20
21
|
|
|
21
22
|
export default (source, filePath, mode) => {
|
|
22
23
|
if (
|
|
@@ -26,12 +27,9 @@ export default (source, filePath, mode) => {
|
|
|
26
27
|
/\{.*?template\s*:\s*(['"`])((?:\\?.)*?)\1.*?\}/s.test(source) // object with template key
|
|
27
28
|
) {
|
|
28
29
|
const templates = source.matchAll(/(?<!\/\/\s*)template\s*:\s*(['"`])((?:\\?.)*?)\1/gs)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
track of the offset caused by the previous replacements
|
|
33
|
-
*/
|
|
34
|
-
let offset = 0
|
|
30
|
+
|
|
31
|
+
// Use MagicString to track changes
|
|
32
|
+
const s = new MagicString(source)
|
|
35
33
|
|
|
36
34
|
for (const template of templates) {
|
|
37
35
|
if (template[2]) {
|
|
@@ -39,7 +37,8 @@ export default (source, filePath, mode) => {
|
|
|
39
37
|
|
|
40
38
|
// Only process if it looks like a Blits template
|
|
41
39
|
if (templateContent.match(/^\s*(<!--[\s\S]*?-->|<[A-Za-z][^>]*>)/s)) {
|
|
42
|
-
|
|
40
|
+
// Use original indices - MagicString handles position tracking automatically
|
|
41
|
+
const templateStartIndex = template.index
|
|
43
42
|
const templateEndIndex = templateStartIndex + template[0].length
|
|
44
43
|
|
|
45
44
|
// Parse the template
|
|
@@ -58,16 +57,26 @@ export default (source, filePath, mode) => {
|
|
|
58
57
|
(fn) => fn.toString()
|
|
59
58
|
)}], context: {}}`
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
newSource =
|
|
64
|
-
newSource.substring(0, templateStartIndex) +
|
|
65
|
-
replacement +
|
|
66
|
-
newSource.substring(templateEndIndex)
|
|
60
|
+
// MagicString tracks all changes automatically, no offset needed
|
|
61
|
+
s.overwrite(templateStartIndex, templateEndIndex, replacement)
|
|
67
62
|
}
|
|
68
63
|
}
|
|
69
64
|
}
|
|
70
|
-
|
|
65
|
+
|
|
66
|
+
const newSource = s.toString()
|
|
67
|
+
|
|
68
|
+
if (newSource !== source) {
|
|
69
|
+
const fileName = filePath.split(/[\\/]/).pop()
|
|
70
|
+
return {
|
|
71
|
+
code: newSource,
|
|
72
|
+
map: s.generateMap({
|
|
73
|
+
hires: true,
|
|
74
|
+
source: fileName,
|
|
75
|
+
includeContent: true,
|
|
76
|
+
file: fileName,
|
|
77
|
+
}),
|
|
78
|
+
}
|
|
79
|
+
}
|
|
71
80
|
}
|
|
72
81
|
return source
|
|
73
82
|
}
|
|
@@ -32,9 +32,10 @@ const objectMap = new WeakMap()
|
|
|
32
32
|
const globalEffectsMap = new Map()
|
|
33
33
|
|
|
34
34
|
export const removeGlobalEffects = (effectsToRemove) => {
|
|
35
|
-
if (globalEffectsMap.size === 0) return
|
|
35
|
+
if (globalEffectsMap.size === 0 || effectsToRemove.length === 0) return
|
|
36
|
+
const effectsToRemoveSet = new Set(effectsToRemove)
|
|
36
37
|
for (const [effect, target] of globalEffectsMap) {
|
|
37
|
-
if (
|
|
38
|
+
if (!effectsToRemoveSet.has(effect)) continue
|
|
38
39
|
const effectsSet = objectMap.get(target)
|
|
39
40
|
if (effectsSet === undefined) continue
|
|
40
41
|
for (const set of effectsSet.values()) {
|