@lightningjs/blits 1.45.0 → 2.0.0-beta.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 +0 -11
- package/README.md +0 -2
- package/index.d.ts +23 -86
- package/package.json +5 -24
- package/scripts/prepublishOnly.js +1 -4
- 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 +4 -4
- package/src/component.js +25 -16
- package/src/components/Circle.js +49 -7
- package/src/components/FPScounter.js +226 -88
- package/src/components/RouterView.js +50 -5
- package/src/components/Sprite.js +61 -20
- package/src/engines/L3/element.js +109 -86
- package/src/engines/L3/fontLoader.js +26 -31
- package/src/engines/L3/shaderLoader.js +56 -6
- package/src/focus.js +9 -9
- package/src/launch.js +1 -2
- package/src/lib/codegenerator/generator.js +117 -16
- package/src/lib/colors/colors.js +0 -1
- package/src/lib/lifecycle.js +3 -3
- package/src/lib/precompiler/precompiler.js +14 -23
- package/src/lib/reactivityguard/computedprops.js +1 -6
- package/src/lib/shaders/shaders.js +163 -0
- package/src/lib/symbols.js +8 -0
- package/src/lib/templateparser/parser.js +6 -2
- package/src/lib/utils.js +36 -0
- package/src/router/router.js +7 -7
- package/vite/blitsTips.js +57 -0
- package/vite/msdfGenerator.js +52 -6
- package/vite/preCompiler.js +5 -15
- package/vscode/data/template-attributes.json +112 -0
- package/src/plugins/appstate.d.ts +0 -29
- package/src/plugins/index.d.ts +0 -29
- package/src/plugins/language.d.ts +0 -34
- package/src/plugins/storage/storage.d.ts +0 -29
- package/src/plugins/theme.d.ts +0 -35
|
@@ -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
|
}
|
|
@@ -220,13 +232,43 @@ const generateElementCode = function (
|
|
|
220
232
|
}
|
|
221
233
|
})
|
|
222
234
|
|
|
235
|
+
if (templateObject[Symbol.for('tagContent')] !== undefined) {
|
|
236
|
+
const val = templateObject[Symbol.for('tagContent')]
|
|
237
|
+
|
|
238
|
+
// Check if the string contains interpolation (`{{ }}`).
|
|
239
|
+
const regex = /\{\{\s*.+?\s*\}\}/
|
|
240
|
+
const containsInterpolation = regex.test(val)
|
|
241
|
+
|
|
242
|
+
if (containsInterpolation === false) {
|
|
243
|
+
// Inline text is treated as static content when interpolation is not defined.
|
|
244
|
+
renderCode.push(`elementConfigs[${counter}]['content'] = '${val}'`)
|
|
245
|
+
} else {
|
|
246
|
+
const output = parseTagContent(val, options.component)
|
|
247
|
+
renderCode.push(`elementConfigs[${counter}]['content'] = ${output}`)
|
|
248
|
+
|
|
249
|
+
const variableRegEx = /\{\{\s*(?=[^}]*\$).+?\s*\}\}/
|
|
250
|
+
// Check if the interpolation contains $ variable
|
|
251
|
+
const isReactive = variableRegEx.test(val)
|
|
252
|
+
if (isReactive === true) {
|
|
253
|
+
this.effectsCode.push(`
|
|
254
|
+
${elm}.set('content', ${output})
|
|
255
|
+
`)
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
223
260
|
if (options.holder === true) {
|
|
224
261
|
renderCode.push(`
|
|
225
262
|
skips[${counter}] = []
|
|
226
|
-
if(typeof cmps[${counter}] !== 'undefined') {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
263
|
+
if(typeof cmps[${counter}] !== 'undefined' && cmps[${counter}][Symbol.for('config')].props !== undefined) {
|
|
264
|
+
// attributes that are a prop should be removed from element config (even if it's a know element prop)
|
|
265
|
+
let props = cmps[${counter}][Symbol.for('config')].props
|
|
266
|
+
if(Array.isArray(props) === false) props = Object.keys(cmps[${counter}][Symbol.for('config')].props)
|
|
267
|
+
for(let k = 0; k < props.length; k++) {
|
|
268
|
+
const key = props[k]
|
|
269
|
+
if(validAttributes.indexOf(key) !== -1) continue
|
|
270
|
+
delete elementConfigs[${counter}][key]
|
|
271
|
+
skips[${counter}].push(key)
|
|
230
272
|
}
|
|
231
273
|
}
|
|
232
274
|
`)
|
|
@@ -409,7 +451,7 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
409
451
|
.replace(')', '')
|
|
410
452
|
.split(/\s*,\s*/)
|
|
411
453
|
|
|
412
|
-
const scopeRegex = new RegExp(`(scope\\.(?!${item}\\.|${index}|key)(
|
|
454
|
+
const scopeRegex = new RegExp(`(scope\\.(?!${item}\\.|${index}|key)(\\$?\\w+))`, 'gi')
|
|
413
455
|
|
|
414
456
|
// local context
|
|
415
457
|
const ctx = {
|
|
@@ -540,9 +582,9 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
540
582
|
}
|
|
541
583
|
|
|
542
584
|
// separate effects that only rely on variables in the itteration
|
|
543
|
-
const innerScopeEffects = ctx.effectsCode.filter(
|
|
544
|
-
|
|
545
|
-
)
|
|
585
|
+
const innerScopeEffects = ctx.effectsCode.filter((effect) => {
|
|
586
|
+
return [...effect.matchAll(scopeRegex)].length === 0
|
|
587
|
+
})
|
|
546
588
|
|
|
547
589
|
// separate effects that (also) rely on variables in the outer scope
|
|
548
590
|
const outerScopeEffects = ctx.effectsCode.filter(
|
|
@@ -760,12 +802,12 @@ const cast = (val = '', key = false, component = 'component.') => {
|
|
|
760
802
|
castedValue = parseFloat(val)
|
|
761
803
|
if (val.endsWith('%')) {
|
|
762
804
|
const map = {
|
|
763
|
-
w: '
|
|
764
|
-
width: '
|
|
765
|
-
x: '
|
|
766
|
-
h: '
|
|
767
|
-
height: '
|
|
768
|
-
y: '
|
|
805
|
+
w: 'w',
|
|
806
|
+
width: 'w',
|
|
807
|
+
x: 'w',
|
|
808
|
+
h: 'h',
|
|
809
|
+
height: 'h',
|
|
810
|
+
y: 'h',
|
|
769
811
|
}
|
|
770
812
|
const base = map[key]
|
|
771
813
|
if (base) {
|
|
@@ -813,6 +855,65 @@ const cast = (val = '', key = false, component = 'component.') => {
|
|
|
813
855
|
return castedValue
|
|
814
856
|
}
|
|
815
857
|
|
|
858
|
+
function escapeSingleQuotes(str) {
|
|
859
|
+
return str.replace(/(\\*)'/g, (match, backslashes) => {
|
|
860
|
+
// If the number of backslashes is odd, quote is already escaped
|
|
861
|
+
if (backslashes.length % 2 === 1) {
|
|
862
|
+
return match
|
|
863
|
+
}
|
|
864
|
+
// Otherwise, escape the quote
|
|
865
|
+
return backslashes + "\\'"
|
|
866
|
+
})
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
const parseTagContent = (val = '', component = 'component.') => {
|
|
870
|
+
// unescaped single quotes must be escaped while preserving escaped backslashes
|
|
871
|
+
let escapedVal = escapeSingleQuotes(val)
|
|
872
|
+
|
|
873
|
+
const dynamicParts = /\{\{\s*.+?\s*\}\}/g
|
|
874
|
+
const matches = [...escapedVal.matchAll(dynamicParts)]
|
|
875
|
+
|
|
876
|
+
if (matches.length > 0) {
|
|
877
|
+
const isValStartsWithBrace = escapedVal.startsWith('{{')
|
|
878
|
+
const isValEndsWithBrace = escapedVal.endsWith('}}')
|
|
879
|
+
for (let matchObj of matches) {
|
|
880
|
+
const { 0: match, index } = matchObj
|
|
881
|
+
const isMatchAtStart = index === 0
|
|
882
|
+
const isMatchAtLast = val[index + match.length] === undefined ? true : false
|
|
883
|
+
|
|
884
|
+
let parsedMatch = match
|
|
885
|
+
|
|
886
|
+
const replaceDollar = /\$(\$(?=\$)|\$?)/g
|
|
887
|
+
const dollarMatches = [...parsedMatch.matchAll(replaceDollar)]
|
|
888
|
+
if (dollarMatches.length > 0) {
|
|
889
|
+
parsedMatch = parsedMatch.replace(replaceDollar, (match, group1) => {
|
|
890
|
+
if (group1 === '') {
|
|
891
|
+
return component
|
|
892
|
+
} else if (group1 === '$') {
|
|
893
|
+
return component + '$'
|
|
894
|
+
}
|
|
895
|
+
})
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
parsedMatch = parsedMatch.replace('{{', '(').replace('}}', ')')
|
|
899
|
+
if (isMatchAtStart === false) {
|
|
900
|
+
parsedMatch = `"+${parsedMatch}`
|
|
901
|
+
}
|
|
902
|
+
if (isMatchAtLast === false) {
|
|
903
|
+
parsedMatch = `${parsedMatch}+"`
|
|
904
|
+
}
|
|
905
|
+
escapedVal = escapedVal.replace(match, parsedMatch)
|
|
906
|
+
}
|
|
907
|
+
if (isValStartsWithBrace === false) {
|
|
908
|
+
escapedVal = '"' + escapedVal
|
|
909
|
+
}
|
|
910
|
+
if (isValEndsWithBrace === false) {
|
|
911
|
+
escapedVal = escapedVal + '"'
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
return escapedVal
|
|
915
|
+
}
|
|
916
|
+
|
|
816
917
|
const isReactiveKey = (str) => str.startsWith(':')
|
|
817
918
|
|
|
818
919
|
const parseInlineContent = (val, component) => {
|
package/src/lib/colors/colors.js
CHANGED
package/src/lib/lifecycle.js
CHANGED
|
@@ -72,7 +72,7 @@ export default {
|
|
|
72
72
|
set state(v) {
|
|
73
73
|
if ((states.indexOf(v) > -1 && v !== this.current) || v === 'refocus') {
|
|
74
74
|
Log.debug(
|
|
75
|
-
`Setting lifecycle state from ${this.current} to ${v} for ${this.component
|
|
75
|
+
`Setting lifecycle state from ${this.current} to ${v} for ${this.component.$componentId}`
|
|
76
76
|
)
|
|
77
77
|
this.previous = this.current
|
|
78
78
|
this.current = v
|
|
@@ -82,8 +82,8 @@ export default {
|
|
|
82
82
|
// emit 'public' hook
|
|
83
83
|
emit(v, this.component[symbols.identifier], this.component)
|
|
84
84
|
// update the built-in hasFocus state variable
|
|
85
|
-
if (v === 'focus') this.component[symbols.state]
|
|
86
|
-
if (v === 'unfocus') this.component[symbols.state]
|
|
85
|
+
if (v === 'focus') this.component[symbols.state].$hasFocus = true
|
|
86
|
+
if (v === 'unfocus') this.component[symbols.state].$hasFocus = false
|
|
87
87
|
}
|
|
88
88
|
},
|
|
89
89
|
}
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
|
|
18
18
|
import parser from '../templateparser/parser.js'
|
|
19
19
|
import generator from '../codegenerator/generator.js'
|
|
20
|
-
import MagicString from 'magic-string'
|
|
21
20
|
|
|
22
21
|
export default (source, filePath, mode) => {
|
|
23
22
|
if (
|
|
@@ -27,9 +26,12 @@ export default (source, filePath, mode) => {
|
|
|
27
26
|
/\{.*?template\s*:\s*(['"`])((?:\\?.)*?)\1.*?\}/s.test(source) // object with template key
|
|
28
27
|
) {
|
|
29
28
|
const templates = source.matchAll(/(?<!\/\/\s*)template\s*:\s*(['"`])((?:\\?.)*?)\1/gs)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
let newSource = source
|
|
30
|
+
/*
|
|
31
|
+
if there are multiple templates in the file, we need to keep
|
|
32
|
+
track of the offset caused by the previous replacements
|
|
33
|
+
*/
|
|
34
|
+
let offset = 0
|
|
33
35
|
|
|
34
36
|
for (const template of templates) {
|
|
35
37
|
if (template[2]) {
|
|
@@ -37,8 +39,7 @@ export default (source, filePath, mode) => {
|
|
|
37
39
|
|
|
38
40
|
// Only process if it looks like a Blits template
|
|
39
41
|
if (templateContent.match(/^\s*(<!--[\s\S]*?-->|<[A-Za-z][^>]*>)/s)) {
|
|
40
|
-
|
|
41
|
-
const templateStartIndex = template.index
|
|
42
|
+
const templateStartIndex = template.index + offset
|
|
42
43
|
const templateEndIndex = templateStartIndex + template[0].length
|
|
43
44
|
|
|
44
45
|
// Parse the template
|
|
@@ -57,26 +58,16 @@ export default (source, filePath, mode) => {
|
|
|
57
58
|
(fn) => fn.toString()
|
|
58
59
|
)}], context: {}}`
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
s.overwrite(templateStartIndex, templateEndIndex, replacement)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const newSource = s.toString()
|
|
61
|
+
offset += replacement.length - template[0].length
|
|
67
62
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
hires: true,
|
|
74
|
-
source: fileName,
|
|
75
|
-
includeContent: true,
|
|
76
|
-
file: fileName,
|
|
77
|
-
}),
|
|
63
|
+
newSource =
|
|
64
|
+
newSource.substring(0, templateStartIndex) +
|
|
65
|
+
replacement +
|
|
66
|
+
newSource.substring(templateEndIndex)
|
|
67
|
+
}
|
|
78
68
|
}
|
|
79
69
|
}
|
|
70
|
+
return newSource
|
|
80
71
|
}
|
|
81
72
|
return source
|
|
82
73
|
}
|
|
@@ -213,12 +213,7 @@ export default (code) => {
|
|
|
213
213
|
modifiedCode = modifiedCode.replace(mod.original, mod.replacement)
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
|
|
217
|
-
// Vite will automatically chain this with the next plugin's source map (preCompiler)
|
|
218
|
-
return {
|
|
219
|
-
code: modifiedCode,
|
|
220
|
-
map: { mappings: '' },
|
|
221
|
-
}
|
|
216
|
+
return { code: modifiedCode }
|
|
222
217
|
}
|
|
223
218
|
|
|
224
219
|
return null
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 Comcast Cable Communications Management, LLC
|
|
3
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
* you may not use this file except in compliance with the License.
|
|
5
|
+
* You may obtain a copy of the License at
|
|
6
|
+
*
|
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
*
|
|
9
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
* See the License for the specific language governing permissions and
|
|
13
|
+
* limitations under the License.
|
|
14
|
+
*
|
|
15
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { renderer } from '../../engines/L3/launch.js'
|
|
19
|
+
import { parseToObject, isObjectString, isArrayString } from '../utils.js'
|
|
20
|
+
import colors from '../colors/colors.js'
|
|
21
|
+
|
|
22
|
+
const parseBorder = (border, props = {}, prefixed = false) => {
|
|
23
|
+
const prefix = prefixed === true ? 'border-' : ''
|
|
24
|
+
if (isNaN(border) === false) {
|
|
25
|
+
props[prefix + 'w'] = border
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
if (Array.isArray(border) === true) {
|
|
29
|
+
props[prefix + 'w'] = border
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
if (isArrayString(border) === true) {
|
|
33
|
+
props[prefix + 'w'] = JSON.parse(border)
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
if (typeof border === 'object' || isObjectString(border) === true) {
|
|
37
|
+
border = typeof border === 'string' ? parseToObject(border) : border
|
|
38
|
+
for (const key in border) {
|
|
39
|
+
props[prefix + key] = border[key]
|
|
40
|
+
}
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const parseShadow = (shadow, props = {}, prefixed = false) => {
|
|
46
|
+
const prefix = prefixed === true ? 'shadow-' : ''
|
|
47
|
+
if (Array.isArray(shadow) === true) {
|
|
48
|
+
props[prefix + 'projection'] = shadow
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
if (isArrayString(shadow) === true) {
|
|
52
|
+
props[prefix + 'projection'] = JSON.parse(shadow)
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
if (typeof shadow === 'object' || isObjectString(shadow) === true) {
|
|
56
|
+
shadow = typeof shadow === 'string' ? parseToObject(shadow) : shadow
|
|
57
|
+
for (const key in shadow) {
|
|
58
|
+
props[prefix + key] = shadow[key]
|
|
59
|
+
}
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const parseRounded = (rounded, props = {}) => {
|
|
65
|
+
if (isNaN(rounded) === false) {
|
|
66
|
+
props.radius = rounded
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
if (Array.isArray(rounded) === true) {
|
|
70
|
+
props.radius = rounded
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
if (isArrayString(rounded) === true) {
|
|
74
|
+
props.radius = JSON.parse(rounded)
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
if (typeof rounded === 'object' || isObjectString(rounded) === true) {
|
|
78
|
+
rounded = typeof rounded === 'string' ? parseToObject(rounded) : rounded
|
|
79
|
+
for (const key in rounded) {
|
|
80
|
+
props[key] = rounded[key]
|
|
81
|
+
}
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export default {
|
|
87
|
+
createElementProps(v) {
|
|
88
|
+
let { border, shadow, rounded } = v
|
|
89
|
+
const props = {}
|
|
90
|
+
const hasRounded = rounded !== undefined
|
|
91
|
+
const hasBorder = border !== undefined
|
|
92
|
+
const hasShadow = shadow !== undefined
|
|
93
|
+
|
|
94
|
+
if (border !== undefined) {
|
|
95
|
+
parseBorder(border, props, hasRounded || hasShadow)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (shadow !== undefined) {
|
|
99
|
+
parseShadow(shadow, props, hasRounded || hasBorder)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (hasRounded === true) {
|
|
103
|
+
parseRounded(rounded, props)
|
|
104
|
+
}
|
|
105
|
+
return props
|
|
106
|
+
},
|
|
107
|
+
createElementShader(v) {
|
|
108
|
+
let { border, shadow, rounded } = v
|
|
109
|
+
const props = this.createElementProps(v)
|
|
110
|
+
const hasShadow = shadow !== undefined
|
|
111
|
+
const hasBorder = border !== undefined
|
|
112
|
+
const hasRounded = rounded !== undefined
|
|
113
|
+
|
|
114
|
+
if (hasBorder === true && hasShadow === true) {
|
|
115
|
+
return renderer.createShader('roundedWithBorderAndShadow', props)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (hasRounded === true) {
|
|
119
|
+
if (hasBorder === true) {
|
|
120
|
+
return renderer.createShader('roundedWithBorder', props)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (hasShadow === true) {
|
|
124
|
+
return renderer.createShader('roundedWithShadow', props)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return renderer.createShader('rounded', props)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (hasRounded === false && hasBorder === true) {
|
|
131
|
+
return renderer.createShader('border', props)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
//only possible result left
|
|
135
|
+
return renderer.createShader('shadow', props)
|
|
136
|
+
},
|
|
137
|
+
parseProp(v) {
|
|
138
|
+
if (typeof v === 'number') {
|
|
139
|
+
return v
|
|
140
|
+
}
|
|
141
|
+
if (typeof v === 'string') {
|
|
142
|
+
return colors.normalize(v)
|
|
143
|
+
}
|
|
144
|
+
if (Array.isArray(v) === true) {
|
|
145
|
+
return v.map((i) => this.parseProp(i))
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
parseProps(v) {
|
|
149
|
+
if (typeof v === 'string') {
|
|
150
|
+
v = parseToObject(v)
|
|
151
|
+
}
|
|
152
|
+
const keys = Object.keys(v)
|
|
153
|
+
const length = keys.length
|
|
154
|
+
for (let i = 0; i < length; i++) {
|
|
155
|
+
const key = keys[i]
|
|
156
|
+
if (key === 'type') {
|
|
157
|
+
continue
|
|
158
|
+
}
|
|
159
|
+
v[key] = this.parseProp(v[key])
|
|
160
|
+
}
|
|
161
|
+
return v
|
|
162
|
+
},
|
|
163
|
+
}
|
package/src/lib/symbols.js
CHANGED
|
@@ -20,12 +20,14 @@
|
|
|
20
20
|
* @property {symbol} isProxy
|
|
21
21
|
* @property {symbol} launched
|
|
22
22
|
* @property {symbol} level
|
|
23
|
+
* @property {symbol} lifecycle
|
|
23
24
|
* @property {symbol} methodKeys
|
|
24
25
|
* @property {symbol} originalState
|
|
25
26
|
* @property {symbol} propKeys
|
|
26
27
|
* @property {symbol} raw
|
|
27
28
|
* @property {symbol} ready
|
|
28
29
|
* @property {symbol} renderer
|
|
30
|
+
* @property {symbol} rootParent
|
|
29
31
|
* @property {symbol} routes
|
|
30
32
|
* @property {symbol} routerHooks
|
|
31
33
|
* @property {symbol} settings
|
|
@@ -42,6 +44,7 @@
|
|
|
42
44
|
* @property {symbol} config
|
|
43
45
|
* @property {symbol} isSlot
|
|
44
46
|
* @property {symbol} props
|
|
47
|
+
* @property {symbol} parent
|
|
45
48
|
* @property {symbol} slots
|
|
46
49
|
* @property {symbol} componentType
|
|
47
50
|
* @property {symbol} isComponent
|
|
@@ -73,12 +76,15 @@ export default {
|
|
|
73
76
|
isProxy: Symbol('isProxy'),
|
|
74
77
|
launched: Symbol('launched'),
|
|
75
78
|
level: Symbol('level'),
|
|
79
|
+
lifecycle: Symbol('lifecycle'),
|
|
76
80
|
methodKeys: Symbol('methodKeys'),
|
|
77
81
|
originalState: Symbol('originalState'),
|
|
82
|
+
parent: Symbol('parent'),
|
|
78
83
|
propKeys: Symbol('propKeys'),
|
|
79
84
|
raw: Symbol('raw'),
|
|
80
85
|
ready: Symbol('ready'),
|
|
81
86
|
renderer: Symbol('renderer'),
|
|
87
|
+
rootParent: Symbol('rootParent'),
|
|
82
88
|
routes: Symbol('routes'),
|
|
83
89
|
routerHooks: Symbol('routerHooks'),
|
|
84
90
|
settings: Symbol('settings'),
|
|
@@ -113,4 +119,6 @@ export default {
|
|
|
113
119
|
effects: Symbol.for('effects'),
|
|
114
120
|
// Symbol 'removeGlobalEffects' utilized within generated code
|
|
115
121
|
removeGlobalEffects: Symbol.for('removeGlobalEffects'),
|
|
122
|
+
// Symbol 'removeGlobalEffects' utilized within generated code
|
|
123
|
+
tagContent: Symbol.for('tagContent'),
|
|
116
124
|
}
|
|
@@ -143,7 +143,7 @@ export default (template = '', componentName, parentComponent, filePath = null)
|
|
|
143
143
|
if (currentTag[symbols.type] === 'opening') {
|
|
144
144
|
const tagContent = template.slice(cursor, template.indexOf('<', cursor))
|
|
145
145
|
if (tagContent) {
|
|
146
|
-
currentTag.
|
|
146
|
+
currentTag[Symbol.for('tagContent')] = tagContent
|
|
147
147
|
cursor += tagContent.length
|
|
148
148
|
}
|
|
149
149
|
}
|
|
@@ -189,7 +189,11 @@ export default (template = '', componentName, parentComponent, filePath = null)
|
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
// process color values
|
|
192
|
-
if (
|
|
192
|
+
if (
|
|
193
|
+
['color', ':color', ':border', 'border', 'shadow', ':shadow', 'shader', ':shader'].includes(
|
|
194
|
+
name
|
|
195
|
+
)
|
|
196
|
+
) {
|
|
193
197
|
return processColors(name, value)
|
|
194
198
|
}
|
|
195
199
|
return { name, value }
|
package/src/lib/utils.js
CHANGED
|
@@ -25,3 +25,39 @@ export const screenResolutions = {
|
|
|
25
25
|
'2160p': 2,
|
|
26
26
|
2160: 2,
|
|
27
27
|
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Checks if a value is a transition object.
|
|
31
|
+
* @param {any} value - The value to check.
|
|
32
|
+
* @returns {boolean} True if the value is a transition object, false otherwise.
|
|
33
|
+
*/
|
|
34
|
+
export const isTransition = (value) => {
|
|
35
|
+
return value !== null && typeof value === 'object' && 'transition' in value === true
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Checks if a string is an object string (starts and ends with curly braces).
|
|
40
|
+
* @param {string} str - The string to check.
|
|
41
|
+
* @returns {boolean} True if the string is an object string, false otherwise.
|
|
42
|
+
*/
|
|
43
|
+
export const isObjectString = (str) => {
|
|
44
|
+
return typeof str === 'string' && str.startsWith('{') && str.endsWith('}')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Checks if a string is an array string (starts and ends with brackets).
|
|
49
|
+
* @param {string} str - The string to check.
|
|
50
|
+
* @returns {boolean} True if the string is an object string, false otherwise.
|
|
51
|
+
*/
|
|
52
|
+
export const isArrayString = (str) => {
|
|
53
|
+
return typeof str === 'string' && str.startsWith('[') && str.endsWith(']')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Parses a string into an object, converting single quotes to double and adding quotes to keys.
|
|
58
|
+
* @param {string} str - The string to parse.
|
|
59
|
+
* @returns {object} The parsed object.
|
|
60
|
+
*/
|
|
61
|
+
export const parseToObject = (str) => {
|
|
62
|
+
return JSON.parse(str.replace(/'/g, '"').replace(/([\w-_]+)\s*:/g, '"$1":'))
|
|
63
|
+
}
|
package/src/router/router.js
CHANGED
|
@@ -245,17 +245,17 @@ export const navigate = async function () {
|
|
|
245
245
|
Announcer.clear()
|
|
246
246
|
state.navigating = true
|
|
247
247
|
let reuse = false
|
|
248
|
-
if (preventHashChangeNavigation === false && this.parent[symbols.routes]) {
|
|
248
|
+
if (preventHashChangeNavigation === false && this[symbols.parent][symbols.routes]) {
|
|
249
249
|
let previousRoute = currentRoute //? Object.assign({}, currentRoute) : undefined
|
|
250
|
-
let route = matchHash(getHash(document.location.hash), this.parent[symbols.routes])
|
|
250
|
+
let route = matchHash(getHash(document.location.hash), this[symbols.parent][symbols.routes])
|
|
251
251
|
|
|
252
252
|
currentRoute = route
|
|
253
253
|
|
|
254
254
|
if (route) {
|
|
255
255
|
const currentPath = currentRoute.path
|
|
256
256
|
let beforeEachResult
|
|
257
|
-
if (this.parent[symbols.routerHooks]) {
|
|
258
|
-
const hooks = this.parent[symbols.routerHooks]
|
|
257
|
+
if (this[symbols.parent][symbols.routerHooks]) {
|
|
258
|
+
const hooks = this[symbols.parent][symbols.routerHooks]
|
|
259
259
|
if (hooks.beforeEach) {
|
|
260
260
|
try {
|
|
261
261
|
beforeEachResult = await hooks.beforeEach.call(this.parent, route, previousRoute)
|
|
@@ -502,9 +502,9 @@ export const navigate = async function () {
|
|
|
502
502
|
}
|
|
503
503
|
} else {
|
|
504
504
|
Log.error(`Route ${route.hash} not found`)
|
|
505
|
-
const routerHooks = this.parent[symbols.routerHooks]
|
|
505
|
+
const routerHooks = this[symbols.parent][symbols.routerHooks]
|
|
506
506
|
if (routerHooks && typeof routerHooks.error === 'function') {
|
|
507
|
-
routerHooks.error.call(this.parent, `Route ${route.hash} not found`)
|
|
507
|
+
routerHooks.error.call(this[symbols.parent], `Route ${route.hash} not found`)
|
|
508
508
|
}
|
|
509
509
|
}
|
|
510
510
|
}
|
|
@@ -626,7 +626,7 @@ export const back = function () {
|
|
|
626
626
|
}
|
|
627
627
|
// Construct new path to backtrack to
|
|
628
628
|
path = path.replace(hashEnd, '')
|
|
629
|
-
const route = matchHash(getHash(path), this.parent[symbols.routes])
|
|
629
|
+
const route = matchHash(getHash(path), this[symbols.parent][symbols.routes])
|
|
630
630
|
|
|
631
631
|
if (route && backtrack) {
|
|
632
632
|
to(route.path, route.data, route.options)
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
+
const tips = ['tip1', 'tip2', 'tip3']
|
|
19
|
+
|
|
20
|
+
let hmrCount = 0
|
|
21
|
+
let lastTipLines = 0
|
|
22
|
+
const HMR_THRESHOLD = 4
|
|
23
|
+
|
|
24
|
+
function showTip() {
|
|
25
|
+
const tip = tips[Math.floor(Math.random() * tips.length)]
|
|
26
|
+
|
|
27
|
+
// Clear previous tip (move up and erase lines)
|
|
28
|
+
if (lastTipLines > 0) {
|
|
29
|
+
process.stdout.write(`\x1B[${lastTipLines}A`)
|
|
30
|
+
for (let i = 0; i < lastTipLines; i++) {
|
|
31
|
+
process.stdout.write('\x1B[2K\x1B[1E') // clear line + move down
|
|
32
|
+
}
|
|
33
|
+
process.stdout.write(`\x1B[${lastTipLines}A`)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Print new tip
|
|
37
|
+
const lines = [`💡 Blits Tip: ${tip}`, '']
|
|
38
|
+
lastTipLines = lines.length
|
|
39
|
+
process.stdout.write(lines.join('\n') + '\n')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default function blitsTipsPlugin() {
|
|
43
|
+
return {
|
|
44
|
+
name: 'vite:blits-tips',
|
|
45
|
+
apply: 'serve',
|
|
46
|
+
|
|
47
|
+
configureServer(server) {
|
|
48
|
+
server.watcher.on('change', () => {
|
|
49
|
+
hmrCount++
|
|
50
|
+
if (hmrCount >= HMR_THRESHOLD) {
|
|
51
|
+
showTip()
|
|
52
|
+
hmrCount = 0
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
}
|