@lightningjs/blits 1.51.0 → 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/element-test-full.txt +0 -0
- package/index.d.ts +35 -50
- package/package.json +6 -6
- package/scripts/lint.js +17 -0
- package/scripts/prepublishOnly.js +2 -2
- package/scripts/prepush.js +4 -6
- package/src/component/base/methods.js +16 -76
- package/src/component/base/utils.js +18 -4
- package/src/component/setup/props.js +37 -28
- package/src/component/setup/state.js +5 -5
- package/src/component.js +28 -19
- package/src/components/Circle.js +52 -9
- package/src/components/FPScounter.js +224 -88
- package/src/components/RouterView.js +58 -6
- package/src/components/Sprite.js +72 -8
- package/src/constants.js +17 -0
- package/src/engine.js +17 -0
- package/src/engines/L3/element.js +109 -86
- package/src/engines/L3/fontLoader.js +43 -31
- package/src/engines/L3/index.js +17 -0
- package/src/engines/L3/launch.js +1 -0
- package/src/engines/L3/shaderLoader.js +73 -6
- package/src/engines/index.js +17 -0
- package/src/focus/focus.js +7 -7
- package/src/focus/helpers.js +4 -2
- package/src/focus/hover.js +7 -6
- package/src/helpers/fetchJson.js +4 -6
- package/src/launch.js +1 -2
- package/src/lib/codegenerator/generator.js +127 -16
- package/src/lib/colors/colors.js +0 -1
- package/src/lib/lifecycle.js +8 -10
- package/src/lib/log.js +4 -4
- package/src/lib/reactivityguard/computedprops.js +27 -13
- package/src/lib/shaders/shaders.js +164 -0
- package/src/lib/symbols.js +25 -0
- package/src/lib/templateparser/parser.js +6 -2
- package/src/lib/utils.js +53 -0
- package/src/plugin.js +17 -0
- package/src/plugins/storage/localCookie.js +4 -6
- package/src/router/router.js +23 -15
- package/test-output.txt +0 -0
- package/vite/blitsTips.js +57 -0
- package/vite/inject-dev-config.js +17 -0
- package/vite/msdfGenerator.js +52 -6
- package/vscode/data/template-attributes.json +112 -0
|
@@ -1,12 +1,79 @@
|
|
|
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'
|
|
20
|
+
import * as webglShaders from '@lightningjs/renderer/webgl/shaders'
|
|
21
|
+
import * as canvasShaders from '@lightningjs/renderer/canvas/shaders'
|
|
22
|
+
|
|
23
|
+
function registerBlitsDefaultShaders(
|
|
24
|
+
shManager,
|
|
25
|
+
Rounded,
|
|
26
|
+
Border,
|
|
27
|
+
Shadow,
|
|
28
|
+
RoundedWithBorder,
|
|
29
|
+
RoundedWithShadow,
|
|
30
|
+
RoundedWithBorderAndShadow,
|
|
31
|
+
HolePunch,
|
|
32
|
+
RadialGradient,
|
|
33
|
+
LinearGradient
|
|
34
|
+
) {
|
|
35
|
+
shManager.registerShaderType('rounded', Rounded)
|
|
36
|
+
shManager.registerShaderType('border', Border)
|
|
37
|
+
shManager.registerShaderType('shadow', Shadow)
|
|
38
|
+
shManager.registerShaderType('roundedWithBorder', RoundedWithBorder)
|
|
39
|
+
shManager.registerShaderType('roundedWithShadow', RoundedWithShadow)
|
|
40
|
+
shManager.registerShaderType('roundedWithBorderAndShadow', RoundedWithBorderAndShadow)
|
|
41
|
+
shManager.registerShaderType('holePunch', HolePunch)
|
|
42
|
+
shManager.registerShaderType('radialGradient', RadialGradient)
|
|
43
|
+
shManager.registerShaderType('linearGradient', LinearGradient)
|
|
44
|
+
}
|
|
3
45
|
|
|
4
46
|
export default () => {
|
|
5
47
|
const stage = renderer.stage
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
48
|
+
|
|
49
|
+
const {
|
|
50
|
+
Rounded,
|
|
51
|
+
Border,
|
|
52
|
+
Shadow,
|
|
53
|
+
RoundedWithBorder,
|
|
54
|
+
RoundedWithShadow,
|
|
55
|
+
RoundedWithBorderAndShadow,
|
|
56
|
+
HolePunch,
|
|
57
|
+
RadialGradient,
|
|
58
|
+
LinearGradient,
|
|
59
|
+
} = Settings.get('renderMode', 'webgl') === 'webgl' ? webglShaders : canvasShaders
|
|
60
|
+
|
|
61
|
+
registerBlitsDefaultShaders(
|
|
62
|
+
stage.shManager,
|
|
63
|
+
Rounded,
|
|
64
|
+
Border,
|
|
65
|
+
Shadow,
|
|
66
|
+
RoundedWithBorder,
|
|
67
|
+
RoundedWithShadow,
|
|
68
|
+
RoundedWithBorderAndShadow,
|
|
69
|
+
HolePunch,
|
|
70
|
+
RadialGradient,
|
|
71
|
+
LinearGradient
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
const shaders = Settings.get('shaders', [])
|
|
75
|
+
const len = shaders.length
|
|
76
|
+
for (let i = 0; i < len; i++) {
|
|
77
|
+
stage.shManager.registerShaderType(shaders[i].name, shaders[i].type)
|
|
78
|
+
}
|
|
12
79
|
}
|
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'
|
package/src/focus/focus.js
CHANGED
|
@@ -51,7 +51,7 @@ export default {
|
|
|
51
51
|
|
|
52
52
|
// unfocus currently focused components
|
|
53
53
|
if (focusedComponent !== null) {
|
|
54
|
-
if (focusChain[focusChain.length - 1] === component.parent) {
|
|
54
|
+
if (focusChain[focusChain.length - 1] === component[symbols.parent]) {
|
|
55
55
|
focusChain.push(component)
|
|
56
56
|
} else {
|
|
57
57
|
const newFocusChain = getAncestors([component])
|
|
@@ -59,7 +59,7 @@ export default {
|
|
|
59
59
|
while (i--) {
|
|
60
60
|
// don't unfocus when part of the new focus chain
|
|
61
61
|
if (newFocusChain.indexOf(focusChain[i]) > -1) break
|
|
62
|
-
focusChain[i].lifecycle.state = 'unfocus'
|
|
62
|
+
focusChain[i][symbols.lifecycle].state = 'unfocus'
|
|
63
63
|
}
|
|
64
64
|
focusChain = newFocusChain
|
|
65
65
|
}
|
|
@@ -68,7 +68,7 @@ export default {
|
|
|
68
68
|
// ensure that all components in the focus path have focus state
|
|
69
69
|
let i = 0
|
|
70
70
|
while (i < focusChain.length - 1) {
|
|
71
|
-
focusChain[i].lifecycle.state = 'focus'
|
|
71
|
+
focusChain[i][symbols.lifecycle].state = 'focus'
|
|
72
72
|
i++
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -113,8 +113,8 @@ export const getComponentWithInputEvent = (component, key) => {
|
|
|
113
113
|
typeof component[symbols.inputEvents].any === 'function')
|
|
114
114
|
) {
|
|
115
115
|
return component
|
|
116
|
-
} else if (component.parent !== undefined) {
|
|
117
|
-
return getComponentWithInputEvent(component.parent, key)
|
|
116
|
+
} else if (component[symbols.parent] !== undefined) {
|
|
117
|
+
return getComponentWithInputEvent(component[symbols.parent], key)
|
|
118
118
|
} else return null
|
|
119
119
|
}
|
|
120
120
|
|
|
@@ -126,11 +126,11 @@ export const getComponentWithInputEvent = (component, key) => {
|
|
|
126
126
|
const setFocus = (component, event) => {
|
|
127
127
|
Log.info(
|
|
128
128
|
'\nFocus chain:\n',
|
|
129
|
-
focusChain.map((c, index) => '\t'.repeat(index) + '↳ ' + c
|
|
129
|
+
focusChain.map((c, index) => '\t'.repeat(index) + '↳ ' + c.$componentId).join('\n')
|
|
130
130
|
)
|
|
131
131
|
|
|
132
132
|
focusedComponent = component
|
|
133
|
-
component.lifecycle.state = 'focus'
|
|
133
|
+
component[symbols.lifecycle].state = 'focus'
|
|
134
134
|
|
|
135
135
|
if (event instanceof KeyboardEvent) {
|
|
136
136
|
const internalEvent = new KeyboardEvent('keydown', event)
|
package/src/focus/helpers.js
CHANGED
|
@@ -15,14 +15,16 @@
|
|
|
15
15
|
* SPDX-License-Identifier: Apache-2.0
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import symbols from '../lib/symbols.js'
|
|
19
|
+
|
|
18
20
|
/**
|
|
19
21
|
* Recursive function that retrieves the ancestors of a component
|
|
20
22
|
* @param {Array} components
|
|
21
23
|
* @returns array components
|
|
22
24
|
*/
|
|
23
25
|
export const getAncestors = (components) => {
|
|
24
|
-
if (components[0].parent !== undefined) {
|
|
25
|
-
components.unshift(components[0].parent)
|
|
26
|
+
if (components[0][symbols.parent] !== undefined) {
|
|
27
|
+
components.unshift(components[0][symbols.parent])
|
|
26
28
|
return getAncestors(components)
|
|
27
29
|
}
|
|
28
30
|
return components
|
package/src/focus/hover.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import { Log } from '../lib/log.js'
|
|
19
19
|
import { getAncestors } from './helpers.js'
|
|
20
|
+
import symbols from '../lib/symbols.js'
|
|
20
21
|
|
|
21
22
|
let hoveredComponent = null
|
|
22
23
|
let hoverChain = []
|
|
@@ -37,7 +38,7 @@ export default {
|
|
|
37
38
|
|
|
38
39
|
// unhover currently hovered components
|
|
39
40
|
if (hoveredComponent !== null) {
|
|
40
|
-
if (hoverChain[hoverChain.length - 1] === component
|
|
41
|
+
if (hoverChain[hoverChain.length - 1] === component.$parent) {
|
|
41
42
|
hoverChain.push(component)
|
|
42
43
|
} else {
|
|
43
44
|
const newhoverChain = getAncestors([component])
|
|
@@ -47,7 +48,7 @@ export default {
|
|
|
47
48
|
if (newhoverChain.indexOf(hoverChain[i]) > -1) break
|
|
48
49
|
// skip if component is destroyed
|
|
49
50
|
if (hoverChain[i].eol !== true) {
|
|
50
|
-
hoverChain[i].lifecycle.state = 'unhover'
|
|
51
|
+
hoverChain[i][symbols.lifecycle].state = 'unhover'
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
hoverChain = newhoverChain
|
|
@@ -59,7 +60,7 @@ export default {
|
|
|
59
60
|
while (i < hoverChain.length - 1) {
|
|
60
61
|
// skip if component is destroyed
|
|
61
62
|
if (hoverChain[i].eol !== true) {
|
|
62
|
-
hoverChain[i].lifecycle.state = 'hover'
|
|
63
|
+
hoverChain[i][symbols.lifecycle].state = 'hover'
|
|
63
64
|
}
|
|
64
65
|
i++
|
|
65
66
|
}
|
|
@@ -70,7 +71,7 @@ export default {
|
|
|
70
71
|
if (hoveredComponent === null) return
|
|
71
72
|
for (let i = 0; i < hoverChain.length; i++) {
|
|
72
73
|
if (hoverChain[i].eol !== true) {
|
|
73
|
-
hoverChain[i].lifecycle.state = 'unhover'
|
|
74
|
+
hoverChain[i][symbols.lifecycle].state = 'unhover'
|
|
74
75
|
}
|
|
75
76
|
}
|
|
76
77
|
hoveredComponent = null
|
|
@@ -85,9 +86,9 @@ export default {
|
|
|
85
86
|
const setHover = (component) => {
|
|
86
87
|
Log.info(
|
|
87
88
|
'\nHover chain:\n',
|
|
88
|
-
hoverChain.map((c, index) => '\t'.repeat(index) + '↳ ' + c
|
|
89
|
+
hoverChain.map((c, index) => '\t'.repeat(index) + '↳ ' + c.$componentId).join('\n')
|
|
89
90
|
)
|
|
90
91
|
|
|
91
92
|
hoveredComponent = component
|
|
92
|
-
component.lifecycle.state = 'hover'
|
|
93
|
+
component[symbols.lifecycle].state = 'hover'
|
|
93
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
|
@@ -41,9 +41,8 @@ import blitsPackageInfo from '../package.json' with { type: 'json' }
|
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* @typedef {import('@lightningjs/renderer').RendererMain} RendererMain
|
|
44
|
-
* @type {RendererMain}
|
|
44
|
+
* @type {RendererMain | {}}
|
|
45
45
|
*/
|
|
46
|
-
// @ts-ignore - We ignore this because it will be replaced by the renderer once the app is launched
|
|
47
46
|
export let renderer = {}
|
|
48
47
|
export const stage = {}
|
|
49
48
|
|
|
@@ -18,10 +18,13 @@
|
|
|
18
18
|
let counter
|
|
19
19
|
let isDev
|
|
20
20
|
|
|
21
|
+
import { elementAttributes } from '../../engines/L3/element.js'
|
|
22
|
+
|
|
21
23
|
export default function (templateObject = { children: [] }, devMode = false) {
|
|
22
24
|
const ctx = {
|
|
23
25
|
renderCode: [
|
|
24
26
|
'const elms = []',
|
|
27
|
+
`const validAttributes = ${JSON.stringify(elementAttributes)}`,
|
|
25
28
|
'const elementConfigs = []',
|
|
26
29
|
'const forloops = []',
|
|
27
30
|
'const props = []',
|
|
@@ -81,7 +84,7 @@ export default function (templateObject = { children: [] }, devMode = false) {
|
|
|
81
84
|
forloops.length = 0
|
|
82
85
|
props.length = 0
|
|
83
86
|
skips.length = 0
|
|
84
|
-
}}
|
|
87
|
+
}, skips}
|
|
85
88
|
`)
|
|
86
89
|
|
|
87
90
|
return {
|
|
@@ -97,7 +100,16 @@ export default function (templateObject = { children: [] }, devMode = false) {
|
|
|
97
100
|
),
|
|
98
101
|
effects: ctx.effectsCode.map(
|
|
99
102
|
(code) =>
|
|
100
|
-
new Function(
|
|
103
|
+
new Function(
|
|
104
|
+
'component',
|
|
105
|
+
'elms',
|
|
106
|
+
'context',
|
|
107
|
+
'components',
|
|
108
|
+
'rootComponent',
|
|
109
|
+
'skips',
|
|
110
|
+
'effect',
|
|
111
|
+
code
|
|
112
|
+
)
|
|
101
113
|
),
|
|
102
114
|
context: ctx.context,
|
|
103
115
|
}
|
|
@@ -228,13 +240,43 @@ const generateElementCode = function (
|
|
|
228
240
|
}
|
|
229
241
|
})
|
|
230
242
|
|
|
243
|
+
if (templateObject[Symbol.for('tagContent')] !== undefined) {
|
|
244
|
+
const val = templateObject[Symbol.for('tagContent')]
|
|
245
|
+
|
|
246
|
+
// Check if the string contains interpolation (`{{ }}`).
|
|
247
|
+
const regex = /\{\{\s*.+?\s*\}\}/
|
|
248
|
+
const containsInterpolation = regex.test(val)
|
|
249
|
+
|
|
250
|
+
if (containsInterpolation === false) {
|
|
251
|
+
// Inline text is treated as static content when interpolation is not defined.
|
|
252
|
+
renderCode.push(`elementConfigs[${counter}]['content'] = '${val}'`)
|
|
253
|
+
} else {
|
|
254
|
+
const output = parseTagContent(val, options.component)
|
|
255
|
+
renderCode.push(`elementConfigs[${counter}]['content'] = ${output}`)
|
|
256
|
+
|
|
257
|
+
const variableRegEx = /\{\{\s*(?=[^}]*\$).+?\s*\}\}/
|
|
258
|
+
// Check if the interpolation contains $ variable
|
|
259
|
+
const isReactive = variableRegEx.test(val)
|
|
260
|
+
if (isReactive === true) {
|
|
261
|
+
this.effectsCode.push(`
|
|
262
|
+
${elm}.set('content', ${output})
|
|
263
|
+
`)
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
231
268
|
if (options.holder === true) {
|
|
232
269
|
renderCode.push(`
|
|
233
270
|
skips[${counter}] = []
|
|
234
|
-
if(typeof cmps[${counter}] !== 'undefined') {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
271
|
+
if(typeof cmps[${counter}] !== 'undefined' && cmps[${counter}][Symbol.for('config')].props !== undefined) {
|
|
272
|
+
// attributes that are a prop should be removed from element config (even if it's a know element prop)
|
|
273
|
+
let props = cmps[${counter}][Symbol.for('config')].props
|
|
274
|
+
if(Array.isArray(props) === false) props = Object.keys(cmps[${counter}][Symbol.for('config')].props)
|
|
275
|
+
for(let k = 0; k < props.length; k++) {
|
|
276
|
+
const key = props[k]
|
|
277
|
+
if(validAttributes.indexOf(key) !== -1) continue
|
|
278
|
+
delete elementConfigs[${counter}][key]
|
|
279
|
+
skips[${counter}].push(key)
|
|
238
280
|
}
|
|
239
281
|
}
|
|
240
282
|
`)
|
|
@@ -571,9 +613,9 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
571
613
|
}
|
|
572
614
|
|
|
573
615
|
// separate effects that only rely on variables in the itteration
|
|
574
|
-
const innerScopeEffects = ctx.effectsCode.filter(
|
|
575
|
-
|
|
576
|
-
)
|
|
616
|
+
const innerScopeEffects = ctx.effectsCode.filter((effect) => {
|
|
617
|
+
return [...effect.matchAll(scopeRegex)].length === 0
|
|
618
|
+
})
|
|
577
619
|
|
|
578
620
|
// separate effects that (also) rely on variables in the outer scope
|
|
579
621
|
const outerScopeEffects = ctx.effectsCode.filter(
|
|
@@ -622,11 +664,21 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
622
664
|
const forEndCounter = counter
|
|
623
665
|
|
|
624
666
|
for (let i = forStartCounter; i <= forEndCounter; i++) {
|
|
625
|
-
|
|
667
|
+
if (i == forStartCounter) {
|
|
668
|
+
destroyCode.push(`
|
|
626
669
|
elms[${i}][key] && elms[${i}][key].destroy()
|
|
627
670
|
elms[${i}][key] = null
|
|
628
671
|
delete elms[${i}][key]
|
|
629
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
|
+
}
|
|
630
682
|
}
|
|
631
683
|
destroyCode.push(`
|
|
632
684
|
}
|
|
@@ -791,12 +843,12 @@ const cast = (val = '', key = false, component = 'component.') => {
|
|
|
791
843
|
castedValue = parseFloat(val)
|
|
792
844
|
if (val.endsWith('%')) {
|
|
793
845
|
const map = {
|
|
794
|
-
w: '
|
|
795
|
-
width: '
|
|
796
|
-
x: '
|
|
797
|
-
h: '
|
|
798
|
-
height: '
|
|
799
|
-
y: '
|
|
846
|
+
w: 'w',
|
|
847
|
+
width: 'w',
|
|
848
|
+
x: 'w',
|
|
849
|
+
h: 'h',
|
|
850
|
+
height: 'h',
|
|
851
|
+
y: 'h',
|
|
800
852
|
}
|
|
801
853
|
const base = map[key]
|
|
802
854
|
if (base) {
|
|
@@ -849,6 +901,65 @@ const cast = (val = '', key = false, component = 'component.') => {
|
|
|
849
901
|
return castedValue
|
|
850
902
|
}
|
|
851
903
|
|
|
904
|
+
function escapeSingleQuotes(str) {
|
|
905
|
+
return str.replace(/(\\*)'/g, (match, backslashes) => {
|
|
906
|
+
// If the number of backslashes is odd, quote is already escaped
|
|
907
|
+
if (backslashes.length % 2 === 1) {
|
|
908
|
+
return match
|
|
909
|
+
}
|
|
910
|
+
// Otherwise, escape the quote
|
|
911
|
+
return backslashes + "\\'"
|
|
912
|
+
})
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
const parseTagContent = (val = '', component = 'component.') => {
|
|
916
|
+
// unescaped single quotes must be escaped while preserving escaped backslashes
|
|
917
|
+
let escapedVal = escapeSingleQuotes(val)
|
|
918
|
+
|
|
919
|
+
const dynamicParts = /\{\{\s*.+?\s*\}\}/g
|
|
920
|
+
const matches = [...escapedVal.matchAll(dynamicParts)]
|
|
921
|
+
|
|
922
|
+
if (matches.length > 0) {
|
|
923
|
+
const isValStartsWithBrace = escapedVal.startsWith('{{')
|
|
924
|
+
const isValEndsWithBrace = escapedVal.endsWith('}}')
|
|
925
|
+
for (let matchObj of matches) {
|
|
926
|
+
const { 0: match, index } = matchObj
|
|
927
|
+
const isMatchAtStart = index === 0
|
|
928
|
+
const isMatchAtLast = val[index + match.length] === undefined ? true : false
|
|
929
|
+
|
|
930
|
+
let parsedMatch = match
|
|
931
|
+
|
|
932
|
+
const replaceDollar = /\$(\$(?=\$)|\$?)/g
|
|
933
|
+
const dollarMatches = [...parsedMatch.matchAll(replaceDollar)]
|
|
934
|
+
if (dollarMatches.length > 0) {
|
|
935
|
+
parsedMatch = parsedMatch.replace(replaceDollar, (match, group1) => {
|
|
936
|
+
if (group1 === '') {
|
|
937
|
+
return component
|
|
938
|
+
} else if (group1 === '$') {
|
|
939
|
+
return component + '$'
|
|
940
|
+
}
|
|
941
|
+
})
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
parsedMatch = parsedMatch.replace('{{', '(').replace('}}', ')')
|
|
945
|
+
if (isMatchAtStart === false) {
|
|
946
|
+
parsedMatch = `"+${parsedMatch}`
|
|
947
|
+
}
|
|
948
|
+
if (isMatchAtLast === false) {
|
|
949
|
+
parsedMatch = `${parsedMatch}+"`
|
|
950
|
+
}
|
|
951
|
+
escapedVal = escapedVal.replace(match, parsedMatch)
|
|
952
|
+
}
|
|
953
|
+
if (isValStartsWithBrace === false) {
|
|
954
|
+
escapedVal = '"' + escapedVal
|
|
955
|
+
}
|
|
956
|
+
if (isValEndsWithBrace === false) {
|
|
957
|
+
escapedVal = escapedVal + '"'
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
return escapedVal
|
|
961
|
+
}
|
|
962
|
+
|
|
852
963
|
const isReactiveKey = (str) => str.startsWith(':')
|
|
853
964
|
|
|
854
965
|
const parseInlineContent = (val, component) => {
|
package/src/lib/colors/colors.js
CHANGED
package/src/lib/lifecycle.js
CHANGED
|
@@ -31,8 +31,8 @@ const states = [
|
|
|
31
31
|
'ready', // fired when component instantiated, reactivity setup done and template spawned
|
|
32
32
|
'focus', // fired when receiving focus (can occur multiple times)
|
|
33
33
|
'unfocus', // fired when losing focus (can occur multiple times)
|
|
34
|
-
'hover', // fired when
|
|
35
|
-
'unhover', // fired when
|
|
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)
|
|
36
36
|
'destroy', // fired when component is destroyed and removed
|
|
37
37
|
'attach', // fired when entering the viewport margin and attached to the render tree
|
|
38
38
|
'detach', // fired when leaving the viewport margin and detached from the render tree
|
|
@@ -77,7 +77,7 @@ export default {
|
|
|
77
77
|
set state(v) {
|
|
78
78
|
if ((states.indexOf(v) > -1 && v !== this.current) || v === 'refocus') {
|
|
79
79
|
Log.debug(
|
|
80
|
-
`Setting lifecycle state from ${this.current} to ${v} for ${this.component
|
|
80
|
+
`Setting lifecycle state from ${this.current} to ${v} for ${this.component.$componentId}`
|
|
81
81
|
)
|
|
82
82
|
this.previous = this.current
|
|
83
83
|
this.current = v
|
|
@@ -86,19 +86,17 @@ export default {
|
|
|
86
86
|
privateEmit(v, this.component[symbols.identifier], this.component)
|
|
87
87
|
// emit 'public' hook
|
|
88
88
|
emit(v, this.component[symbols.identifier], this.component)
|
|
89
|
-
// update the built-in hasFocus state variable
|
|
90
|
-
if (v === 'focus') this.component[symbols.state].hasFocus = true
|
|
91
|
-
if (v === 'unfocus') this.component[symbols.state].hasFocus = false
|
|
89
|
+
// update the built-in $hasFocus state variable
|
|
92
90
|
if (v === 'focus' || v === 'unfocus') {
|
|
93
91
|
if (inspectorEnabled === null) {
|
|
94
92
|
inspectorEnabled = Settings.get('inspector', false)
|
|
95
93
|
}
|
|
96
94
|
}
|
|
97
95
|
// update the built-in isHovered state variable
|
|
98
|
-
if (v === 'hover') this.component[symbols.state]
|
|
99
|
-
if (v === 'unhover') this.component[symbols.state]
|
|
96
|
+
if (v === 'hover') this.component[symbols.state].$isHovered = true
|
|
97
|
+
if (v === 'unhover') this.component[symbols.state].$isHovered = false
|
|
100
98
|
if (v === 'focus') {
|
|
101
|
-
this.component[symbols.state]
|
|
99
|
+
this.component[symbols.state].$hasFocus = true
|
|
102
100
|
if (
|
|
103
101
|
inspectorEnabled === true &&
|
|
104
102
|
this.component[symbols.holder] &&
|
|
@@ -108,7 +106,7 @@ export default {
|
|
|
108
106
|
}
|
|
109
107
|
}
|
|
110
108
|
if (v === 'unfocus') {
|
|
111
|
-
this.component[symbols.state]
|
|
109
|
+
this.component[symbols.state].$hasFocus = false
|
|
112
110
|
if (
|
|
113
111
|
inspectorEnabled === true &&
|
|
114
112
|
this.component[symbols.holder] &&
|
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',
|
|
@@ -293,24 +293,38 @@ export default (code) => {
|
|
|
293
293
|
const extractThisReferences = (funcBody) => {
|
|
294
294
|
const thisRefs = new Set()
|
|
295
295
|
|
|
296
|
-
//
|
|
297
|
-
const refRegex = /this
|
|
296
|
+
// Match full property chains, including optional chaining
|
|
297
|
+
const refRegex = /this(?:\.[$\w]+|\?\.[$\w]+)+/g
|
|
298
298
|
let refMatch
|
|
299
299
|
|
|
300
300
|
while ((refMatch = refRegex.exec(funcBody)) !== null) {
|
|
301
301
|
const fullRef = refMatch[0]
|
|
302
302
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
303
|
+
const segmentRegex = /(\??\.)([$\w]+)/g
|
|
304
|
+
let segMatch
|
|
305
|
+
let lastValidRef = 'this'
|
|
306
|
+
|
|
307
|
+
while ((segMatch = segmentRegex.exec(fullRef.substring(4))) !== null) {
|
|
308
|
+
const candidate = 'this' + fullRef.substring(4, 4 + segMatch.index + segMatch[0].length)
|
|
309
|
+
const afterCandidate = funcBody.substring(refMatch.index + candidate.length)
|
|
310
|
+
if (afterCandidate.match(/^\s*\(/)) {
|
|
311
|
+
break
|
|
312
|
+
}
|
|
313
|
+
lastValidRef = candidate
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (lastValidRef !== 'this') {
|
|
317
|
+
thisRefs.add(lastValidRef)
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Remove shorter prefixes when a longer chain already covers them
|
|
322
|
+
for (const ref of [...thisRefs]) {
|
|
323
|
+
for (const other of thisRefs) {
|
|
324
|
+
if (other !== ref && other.startsWith(ref + '.')) {
|
|
325
|
+
thisRefs.delete(ref)
|
|
326
|
+
break
|
|
327
|
+
}
|
|
314
328
|
}
|
|
315
329
|
}
|
|
316
330
|
|