@lightningjs/blits 0.3.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/.editorconfig +7 -0
- package/.eslintignore +1 -0
- package/.eslintrc.cjs +60 -0
- package/.vscode/extensions.json +6 -0
- package/.vscode/settings.json +9 -0
- package/LICENSE +202 -0
- package/NOTICE +3 -0
- package/README.md +11 -0
- package/bin/index.cjs +25 -0
- package/boilerplate/.editorconfig +7 -0
- package/boilerplate/.eslintignore +3 -0
- package/boilerplate/.eslintrc.js +38 -0
- package/boilerplate/.vscode/extensions.json +7 -0
- package/boilerplate/.vscode/launch.json +12 -0
- package/boilerplate/.vscode/settings.json +9 -0
- package/boilerplate/index.html +11 -0
- package/boilerplate/package.json +36 -0
- package/boilerplate/public/assets/logo.png +0 -0
- package/boilerplate/src/App.js +12 -0
- package/boilerplate/src/components/Loader.js +23 -0
- package/boilerplate/src/index.js +11 -0
- package/boilerplate/src/pages/Home.js +15 -0
- package/boilerplate/src/renderer.js +3 -0
- package/boilerplate/vite.config.js +23 -0
- package/docs/.nojekyll +0 -0
- package/docs/README.md +30 -0
- package/docs/_sidebar.md +9 -0
- package/docs/component_state.md +21 -0
- package/docs/components.md +27 -0
- package/docs/computed_properties.md +18 -0
- package/docs/getting_started.md +40 -0
- package/docs/index.html +47 -0
- package/docs/lifecycle_events.md +46 -0
- package/docs/props.md +44 -0
- package/docs/template_syntax.md +31 -0
- package/docs/user_input.md +64 -0
- package/docs/watchers.md +38 -0
- package/index.js +26 -0
- package/package.json +44 -0
- package/src/application.js +55 -0
- package/src/component.js +192 -0
- package/src/component.test.js +51 -0
- package/src/components/Circle.js +31 -0
- package/src/components/Image.js +33 -0
- package/src/components/RouterView.js +38 -0
- package/src/components/Sprite.js +56 -0
- package/src/components/Text.js +61 -0
- package/src/element.js +236 -0
- package/src/focus.js +65 -0
- package/src/helpers/sequence.js +26 -0
- package/src/launch.js +61 -0
- package/src/lib/codegenerator/generator.js +276 -0
- package/src/lib/codegenerator/generator.test.js +970 -0
- package/src/lib/colors/colors.js +70 -0
- package/src/lib/colors/colors.test.js +190 -0
- package/src/lib/colors/htmlColors.js +168 -0
- package/src/lib/componentId.js +27 -0
- package/src/lib/componentId.test.js +83 -0
- package/src/lib/eventListeners.js +55 -0
- package/src/lib/hooks.js +29 -0
- package/src/lib/log.js +106 -0
- package/src/lib/reactivity/effect.js +54 -0
- package/src/lib/reactivity/effect.test.js +35 -0
- package/src/lib/reactivity/reactive.js +113 -0
- package/src/lib/reactivity/reactive.test.js +27 -0
- package/src/lib/setup/base.js +218 -0
- package/src/lib/setup/computed.js +43 -0
- package/src/lib/setup/input.js +28 -0
- package/src/lib/setup/methods.js +35 -0
- package/src/lib/setup/props.js +53 -0
- package/src/lib/setup/props.test.js +205 -0
- package/src/lib/setup/routes.js +24 -0
- package/src/lib/setup/state.js +45 -0
- package/src/lib/setup/watch.js +33 -0
- package/src/lib/templateparser/parser.js +103 -0
- package/src/lib/templateparser/parser.test.js +769 -0
- package/src/router.js +67 -0
- package/src/settings.js +34 -0
- package/vite/index.js +1 -0
package/src/component.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
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 parser from './lib/templateparser/parser.js'
|
|
19
|
+
import codegenerator from './lib/codegenerator/generator.js'
|
|
20
|
+
|
|
21
|
+
import element from './element.js'
|
|
22
|
+
|
|
23
|
+
import { createHumanReadableId, createInternalId } from './lib/componentId.js'
|
|
24
|
+
import { registerHooks, emit } from './lib/hooks.js'
|
|
25
|
+
|
|
26
|
+
import { reactive } from './lib/reactivity/reactive.js'
|
|
27
|
+
import setupBase from './lib/setup/base.js'
|
|
28
|
+
import setupProps from './lib/setup/props.js'
|
|
29
|
+
import setupMethods from './lib/setup/methods.js'
|
|
30
|
+
import setupState from './lib/setup/state.js'
|
|
31
|
+
import setupComputed from './lib/setup/computed.js'
|
|
32
|
+
import setupInput from './lib/setup/input.js'
|
|
33
|
+
import setupRoutes from './lib/setup/routes.js'
|
|
34
|
+
import setupWatch from './lib/setup/watch.js'
|
|
35
|
+
import { effect } from './lib/reactivity/effect.js'
|
|
36
|
+
import { Log } from './lib/log.js'
|
|
37
|
+
|
|
38
|
+
const stage = {
|
|
39
|
+
element,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const required = (name) => {
|
|
43
|
+
throw new Error(`Parameter ${name} is required`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const Component = (name = required('name'), config = required('config')) => {
|
|
47
|
+
let code = null
|
|
48
|
+
|
|
49
|
+
const setupComponent = (lifecycle) => {
|
|
50
|
+
// code generation
|
|
51
|
+
if (!code) {
|
|
52
|
+
Log.debug(`Generating code for ${name} component`)
|
|
53
|
+
code = codegenerator.call(config, parser(config.template))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
setupBase(component)
|
|
57
|
+
|
|
58
|
+
// setup hooks
|
|
59
|
+
registerHooks(config.hooks, name)
|
|
60
|
+
lifecycle.state = 'beforeSetup'
|
|
61
|
+
|
|
62
|
+
// setup props
|
|
63
|
+
// if (config.props) // because of the default props like id - might change this
|
|
64
|
+
setupProps(component, config.props)
|
|
65
|
+
|
|
66
|
+
// setup methods
|
|
67
|
+
if (config.methods) setupMethods(component, config.methods)
|
|
68
|
+
|
|
69
|
+
// setup state
|
|
70
|
+
if (config.state) setupState(component, config.state)
|
|
71
|
+
|
|
72
|
+
// setup computed
|
|
73
|
+
if (config.computed) setupComputed(component, config.computed)
|
|
74
|
+
|
|
75
|
+
// setup watchers
|
|
76
|
+
if (config.watch) setupWatch(component, config.watch)
|
|
77
|
+
|
|
78
|
+
// setup routes
|
|
79
|
+
if (config.routes) setupRoutes(component, config.routes)
|
|
80
|
+
|
|
81
|
+
// setup input
|
|
82
|
+
if (config.input) setupInput(component, config.input)
|
|
83
|
+
|
|
84
|
+
component.setup = true
|
|
85
|
+
lifecycle.state = 'setup'
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const createLifecycle = (scope) => {
|
|
89
|
+
const states = ['init', 'beforeSetup', 'setup', 'ready', 'focus', 'unfocus', 'destroy']
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
previous: null,
|
|
93
|
+
current: null,
|
|
94
|
+
get state() {
|
|
95
|
+
return this.current
|
|
96
|
+
},
|
|
97
|
+
set state(v) {
|
|
98
|
+
if (states.indexOf(v) > -1 && v !== this.current) {
|
|
99
|
+
Log.debug(
|
|
100
|
+
`Setting lifecycle state from ${this.previous} to ${v} for ${scope.componentId}`
|
|
101
|
+
)
|
|
102
|
+
this.previous = this.current
|
|
103
|
+
// emit 'private' hook
|
|
104
|
+
emit(`___${v}`, name, scope)
|
|
105
|
+
// emit 'public' hook
|
|
106
|
+
emit(v, name, scope)
|
|
107
|
+
this.current = v
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const component = function (opts, parentEl, parentComponent) {
|
|
114
|
+
this.lifecycle = createLifecycle(this)
|
|
115
|
+
|
|
116
|
+
if (!component.setup) {
|
|
117
|
+
setupComponent(this.lifecycle)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
this.parent = parentComponent
|
|
121
|
+
|
|
122
|
+
Object.defineProperties(this, {
|
|
123
|
+
componentId: {
|
|
124
|
+
value: createHumanReadableId(name),
|
|
125
|
+
writable: false,
|
|
126
|
+
enumerable: true,
|
|
127
|
+
configurable: false,
|
|
128
|
+
},
|
|
129
|
+
___id: {
|
|
130
|
+
value: createInternalId(),
|
|
131
|
+
writable: false,
|
|
132
|
+
enumerable: false,
|
|
133
|
+
configurable: false,
|
|
134
|
+
},
|
|
135
|
+
___props: {
|
|
136
|
+
value: reactive(opts.props || {}),
|
|
137
|
+
writable: false,
|
|
138
|
+
enumerable: false,
|
|
139
|
+
configurable: false,
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
Object.defineProperty(this, '___state', {
|
|
144
|
+
value: reactive(
|
|
145
|
+
(config.state && typeof config.state === 'function' && config.state.apply(this)) || {}
|
|
146
|
+
),
|
|
147
|
+
writable: false,
|
|
148
|
+
enumerable: false,
|
|
149
|
+
configurable: false,
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
this.lifecycle.state = 'init'
|
|
153
|
+
|
|
154
|
+
Object.defineProperty(this, '___children', {
|
|
155
|
+
value: code.render.apply(stage, [parentEl, this, code.context]),
|
|
156
|
+
writable: false,
|
|
157
|
+
enumerable: false,
|
|
158
|
+
configurable: false,
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
code.effects.forEach((eff) => {
|
|
162
|
+
effect(() => {
|
|
163
|
+
eff.apply(stage, [this, this.___children, code.context])
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
if (this.___watchers) {
|
|
168
|
+
Object.keys(this.___watchers).forEach((watchKey) => {
|
|
169
|
+
let old = this[watchKey]
|
|
170
|
+
effect(() => {
|
|
171
|
+
if (old !== this[watchKey]) {
|
|
172
|
+
this.___watchers[watchKey].apply(this, [this[watchKey], old])
|
|
173
|
+
old = this[watchKey]
|
|
174
|
+
}
|
|
175
|
+
})
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// next tick
|
|
180
|
+
setTimeout(() => (this.lifecycle.state = 'ready'))
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const factory = (options = {}, parentEl, parentComponent) => {
|
|
184
|
+
return new component(options, parentEl, parentComponent)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
factory.config = config
|
|
188
|
+
|
|
189
|
+
return factory
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export default Component
|
|
@@ -0,0 +1,51 @@
|
|
|
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 test from 'tape'
|
|
19
|
+
import Component from './component.js'
|
|
20
|
+
|
|
21
|
+
test('Type', (assert) => {
|
|
22
|
+
const expected = 'function'
|
|
23
|
+
const actual = typeof Component
|
|
24
|
+
|
|
25
|
+
assert.equal(actual, expected, 'Component should be a function')
|
|
26
|
+
assert.end()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('Component - Factory function', (assert) => {
|
|
30
|
+
const expected = 'function'
|
|
31
|
+
const actual = typeof Component('my component', {})
|
|
32
|
+
|
|
33
|
+
assert.equal(actual, expected, 'Component should be a factory function (i.e. return a function)')
|
|
34
|
+
assert.end()
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('Component - Factory requires a name to be passed', (assert) => {
|
|
38
|
+
assert.throws(() => {
|
|
39
|
+
Component()
|
|
40
|
+
}, 'Thorw an error when no name argument has been passed')
|
|
41
|
+
|
|
42
|
+
assert.end()
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('Component - Factory requires a name to be passed', (assert) => {
|
|
46
|
+
assert.throws(() => {
|
|
47
|
+
Component()
|
|
48
|
+
}, 'Throw an error when no name argument has been passed')
|
|
49
|
+
|
|
50
|
+
assert.end()
|
|
51
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
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 Component from '../component.js'
|
|
19
|
+
|
|
20
|
+
export default () =>
|
|
21
|
+
Component('Circle', {
|
|
22
|
+
template: `
|
|
23
|
+
<Element :color="$color" :w="$size" :h="$size" :effects="[$shader('radius', {radius: $radius})]"></Element>
|
|
24
|
+
`,
|
|
25
|
+
props: [{ key: 'size', default: 40 }, 'color'],
|
|
26
|
+
computed: {
|
|
27
|
+
radius() {
|
|
28
|
+
return this.size / 2
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
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 Component from '../component.js'
|
|
19
|
+
|
|
20
|
+
export default () =>
|
|
21
|
+
Component('Image', {
|
|
22
|
+
template: `
|
|
23
|
+
<Element :imageSource="$imageSource" />`,
|
|
24
|
+
props: ['src'],
|
|
25
|
+
computed: {
|
|
26
|
+
imageSource() {
|
|
27
|
+
if (/^(?:https?:)?\/\//i.test(this.src)) {
|
|
28
|
+
return this.src
|
|
29
|
+
}
|
|
30
|
+
return `${window.location.protocol}//${window.location.host}/${this.src}`
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
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 Component from '../component.js'
|
|
19
|
+
import Router from '../router.js'
|
|
20
|
+
|
|
21
|
+
let handler
|
|
22
|
+
|
|
23
|
+
export default () =>
|
|
24
|
+
Component('RouterView', {
|
|
25
|
+
template: `
|
|
26
|
+
<Element></Element>
|
|
27
|
+
`,
|
|
28
|
+
hooks: {
|
|
29
|
+
ready() {
|
|
30
|
+
handler = () => Router.navigate.apply(this)
|
|
31
|
+
Router.navigate.apply(this)
|
|
32
|
+
window.addEventListener('hashchange', handler)
|
|
33
|
+
},
|
|
34
|
+
destroy() {
|
|
35
|
+
window.removeEventListener('hashchange', handler, false)
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
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 Component from '../component.js'
|
|
19
|
+
|
|
20
|
+
export default () =>
|
|
21
|
+
Component('Sprite', {
|
|
22
|
+
template: `
|
|
23
|
+
<Element w="$w" h="$h" :texture="$texture" />
|
|
24
|
+
`,
|
|
25
|
+
props: ['image', 'map', 'frame', 'w', 'h'],
|
|
26
|
+
state() {
|
|
27
|
+
return {
|
|
28
|
+
spriteTexture: false,
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
computed: {
|
|
32
|
+
texture() {
|
|
33
|
+
const options =
|
|
34
|
+
'frames' in this.map
|
|
35
|
+
? { ...(this.map.defaults || {}), ...this.map.frames[this.frame] }
|
|
36
|
+
: this.map[this.frame]
|
|
37
|
+
|
|
38
|
+
if (this.spriteTexture && options) {
|
|
39
|
+
return this.___renderer.makeTexture('SubTexture', {
|
|
40
|
+
texture: this.spriteTexture,
|
|
41
|
+
x: options.x,
|
|
42
|
+
y: options.y,
|
|
43
|
+
width: options.w,
|
|
44
|
+
height: options.h,
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
hooks: {
|
|
50
|
+
ready() {
|
|
51
|
+
this.spriteTexture = this.___renderer.makeTexture('ImageTexture', {
|
|
52
|
+
src: `${window.location.protocol}//${window.location.host}/${this.image}`,
|
|
53
|
+
})
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
})
|
|
@@ -0,0 +1,61 @@
|
|
|
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 Component from '../component.js'
|
|
19
|
+
|
|
20
|
+
export default () =>
|
|
21
|
+
Component('Text', {
|
|
22
|
+
template: `
|
|
23
|
+
<Element
|
|
24
|
+
__textnode="true"
|
|
25
|
+
:text="$text"
|
|
26
|
+
fontFamily="$font"
|
|
27
|
+
:fontSize="$size"
|
|
28
|
+
:color="$color"
|
|
29
|
+
:style="$style"
|
|
30
|
+
:weight="$weight"
|
|
31
|
+
letterSpacing="$letterspacing"
|
|
32
|
+
stretch="$stretch"
|
|
33
|
+
:w="$w"
|
|
34
|
+
:textAlign="$align"
|
|
35
|
+
/>`,
|
|
36
|
+
props: [
|
|
37
|
+
'content',
|
|
38
|
+
{
|
|
39
|
+
key: 'font',
|
|
40
|
+
default: 'TedNext',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
key: 'size',
|
|
44
|
+
cast: Number,
|
|
45
|
+
default: 32,
|
|
46
|
+
},
|
|
47
|
+
'style',
|
|
48
|
+
'color',
|
|
49
|
+
'weight',
|
|
50
|
+
'letterspacing',
|
|
51
|
+
'stretch',
|
|
52
|
+
'align',
|
|
53
|
+
'w',
|
|
54
|
+
],
|
|
55
|
+
computed: {
|
|
56
|
+
text() {
|
|
57
|
+
return this.slotcontent || this.content || ''
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
hooks: {},
|
|
61
|
+
})
|
package/src/element.js
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
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 './launch.js'
|
|
19
|
+
import colors from './lib/colors/colors.js'
|
|
20
|
+
|
|
21
|
+
import { Log } from './lib/log.js'
|
|
22
|
+
|
|
23
|
+
const isTransition = (value) => {
|
|
24
|
+
return typeof value === 'object' && 'transition' in value
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const isObjectString = (str) => {
|
|
28
|
+
return typeof str === 'string' && str.startsWith('{') && str.endsWith('}')
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const parseToObject = (str) => {
|
|
32
|
+
return JSON.parse(str.replace(/'/g, '"').replace(/([\w-_]+)\s*:/g, '"$1":'))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const transformations = {
|
|
36
|
+
unpackTransition(obj) {
|
|
37
|
+
if (typeof obj === 'object' && obj.constructor.name === 'Object') {
|
|
38
|
+
if ('value' in obj) {
|
|
39
|
+
return obj.value
|
|
40
|
+
} else if ('transition' in obj) {
|
|
41
|
+
return this.unpackTransition(obj.transition)
|
|
42
|
+
} else {
|
|
43
|
+
return obj
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
return obj
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
remap(props) {
|
|
50
|
+
'w' in props && (props.width = props.w)
|
|
51
|
+
delete props.w
|
|
52
|
+
'h' in props && (props.height = props.h)
|
|
53
|
+
delete props.h
|
|
54
|
+
'z' in props && (props.zIndex = props.z)
|
|
55
|
+
delete props.z
|
|
56
|
+
},
|
|
57
|
+
parentId(props) {
|
|
58
|
+
props.parent = props.parentId === 'root' ? renderer.root : renderer.getNodeById(props.parentId)
|
|
59
|
+
delete props.parentId
|
|
60
|
+
},
|
|
61
|
+
color(props) {
|
|
62
|
+
if (
|
|
63
|
+
typeof props.color === 'object' ||
|
|
64
|
+
(isObjectString(props.color) && (props.color = parseToObject(props.color)))
|
|
65
|
+
) {
|
|
66
|
+
const map = {
|
|
67
|
+
top: 'colorTop',
|
|
68
|
+
bottom: 'colorBottom',
|
|
69
|
+
left: 'colorLeft',
|
|
70
|
+
right: 'colorRight',
|
|
71
|
+
}
|
|
72
|
+
Object.entries(props.color).forEach((color) => {
|
|
73
|
+
props[map[color[0]]] = colors.normalize(color[1])
|
|
74
|
+
})
|
|
75
|
+
delete props.mount
|
|
76
|
+
} else {
|
|
77
|
+
props.color = colors.normalize(props.color)
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
mount(props) {
|
|
81
|
+
if (
|
|
82
|
+
typeof props.mount === 'object' ||
|
|
83
|
+
(isObjectString(props.mount) && (props.mount = parseToObject(props.mount)))
|
|
84
|
+
) {
|
|
85
|
+
const map = {
|
|
86
|
+
x: 'mountX',
|
|
87
|
+
y: 'mountY',
|
|
88
|
+
}
|
|
89
|
+
Object.entries(props.mount).forEach((mount) => {
|
|
90
|
+
props[map[mount[0]]] = mount[1]
|
|
91
|
+
})
|
|
92
|
+
delete props.mount
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
pivot(props) {
|
|
96
|
+
if (
|
|
97
|
+
typeof props.pivot === 'object' ||
|
|
98
|
+
(isObjectString(props.pivot) && (props.pivot = parseToObject(props.pivot)))
|
|
99
|
+
) {
|
|
100
|
+
const map = {
|
|
101
|
+
x: 'pivotX',
|
|
102
|
+
y: 'pivotY',
|
|
103
|
+
}
|
|
104
|
+
Object.entries(props.pivot).forEach((pivot) => {
|
|
105
|
+
props[map[pivot[0]]] = pivot[1]
|
|
106
|
+
})
|
|
107
|
+
delete props.pivot
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
show(props) {
|
|
111
|
+
props.alpha = props.show ? 1 : 0
|
|
112
|
+
delete props.show
|
|
113
|
+
},
|
|
114
|
+
rotation(props) {
|
|
115
|
+
props.rotation = props.rotation * (Math.PI / 180)
|
|
116
|
+
},
|
|
117
|
+
text(props) {
|
|
118
|
+
props.text = props.text.toString()
|
|
119
|
+
},
|
|
120
|
+
textureColor(props) {
|
|
121
|
+
if (!('color' in props)) {
|
|
122
|
+
props.color = 'src' in props || 'texture' in props ? '0xffffffff' : '0x00000000'
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
effects(props) {
|
|
126
|
+
props.shader = renderer.makeShader('DynamicShader', {
|
|
127
|
+
effects: props.effects.map((eff) => {
|
|
128
|
+
if (eff.props && eff.props.color) {
|
|
129
|
+
eff.props.color = colors.normalize(eff.props.color)
|
|
130
|
+
}
|
|
131
|
+
return eff
|
|
132
|
+
}),
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
delete props.effects
|
|
136
|
+
},
|
|
137
|
+
src(props, setProperties) {
|
|
138
|
+
if (setProperties.indexOf('color') === -1) {
|
|
139
|
+
props.color = 0xffffffff
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
texture(props, setProperties) {
|
|
143
|
+
this.src(props, setProperties)
|
|
144
|
+
},
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const Element = {
|
|
148
|
+
defaults: {
|
|
149
|
+
rotation: 0,
|
|
150
|
+
},
|
|
151
|
+
populate(data) {
|
|
152
|
+
let props = {
|
|
153
|
+
...this.defaults,
|
|
154
|
+
...this.config,
|
|
155
|
+
...data,
|
|
156
|
+
}
|
|
157
|
+
this.initData = data
|
|
158
|
+
|
|
159
|
+
transformations.remap(props)
|
|
160
|
+
Object.keys(props).forEach((prop) => {
|
|
161
|
+
if (transformations[prop]) {
|
|
162
|
+
props[prop] = transformations.unpackTransition(props[prop])
|
|
163
|
+
transformations[prop](props, this.setProperties)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
this.setProperties.push(prop)
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
transformations.textureColor(props, this.setProperties)
|
|
170
|
+
|
|
171
|
+
this.node = props.__textnode ? renderer.createTextNode(props) : renderer.createNode(props)
|
|
172
|
+
},
|
|
173
|
+
set(prop, value) {
|
|
174
|
+
if (isTransition(value) && this.setProperties.indexOf(prop) > -1) {
|
|
175
|
+
this.animate(prop, value.transition)
|
|
176
|
+
} else {
|
|
177
|
+
const props = {}
|
|
178
|
+
if (prop !== 'texture') {
|
|
179
|
+
props[prop] = transformations.unpackTransition(value)
|
|
180
|
+
} else {
|
|
181
|
+
props[prop] = value
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
transformations.remap(props)
|
|
185
|
+
if (transformations[prop]) {
|
|
186
|
+
transformations[prop](props, this.setProperties)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
Object.keys(props).forEach((prop) => {
|
|
190
|
+
this.node[prop] = props[prop]
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
this.setProperties.indexOf(prop) === -1 && this.setProperties.push(prop)
|
|
194
|
+
},
|
|
195
|
+
delete() {
|
|
196
|
+
Log.debug('Deleting Node', this.nodeId, this.node)
|
|
197
|
+
this.node.parent = null
|
|
198
|
+
},
|
|
199
|
+
get nodeId() {
|
|
200
|
+
return this.node && this.node.id
|
|
201
|
+
},
|
|
202
|
+
get id() {
|
|
203
|
+
return this.initData.id || null
|
|
204
|
+
},
|
|
205
|
+
animate(prop, value) {
|
|
206
|
+
const props = {}
|
|
207
|
+
props[prop] = transformations.unpackTransition(value)
|
|
208
|
+
|
|
209
|
+
transformations.remap(props)
|
|
210
|
+
|
|
211
|
+
if (transformations[prop]) {
|
|
212
|
+
transformations[prop](props)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// works for now
|
|
216
|
+
prop = Object.keys(props).pop()
|
|
217
|
+
|
|
218
|
+
if (this.node[prop] !== props[prop]) {
|
|
219
|
+
const f = this.node.animate(props, {
|
|
220
|
+
duration: typeof value === 'object' ? ('duration' in value ? value.duration : 300) : 300,
|
|
221
|
+
easing:
|
|
222
|
+
typeof value === 'object' ? ('function' in value ? value.function : 'ease') : 'ease',
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
value.delay ? setTimeout(() => f.start(), value.delay) : f.start()
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export default (config) =>
|
|
231
|
+
Object.assign(Object.create(Element), {
|
|
232
|
+
node: null,
|
|
233
|
+
setProperties: [],
|
|
234
|
+
initData: {},
|
|
235
|
+
config,
|
|
236
|
+
})
|