@lightningjs/blits 0.9.7 → 0.9.9
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 +21 -0
- package/docs/_sidebar.md +1 -0
- package/docs/built-in/directives.md +11 -3
- package/docs/built-in/for-loop.md +172 -0
- package/docs/components/component_state.md +1 -2
- package/docs/components/computed_properties.md +3 -4
- package/docs/components/methods.md +3 -3
- package/docs/components/props.md +1 -1
- package/docs/components/user_input.md +2 -2
- package/docs/components/watchers.md +1 -1
- package/docs/essentials/application_root.md +1 -1
- package/docs/essentials/components.md +3 -3
- package/docs/essentials/displaying_images.md +2 -2
- package/docs/essentials/displaying_text.md +12 -12
- package/docs/essentials/element_attributes.md +19 -13
- package/docs/essentials/template_syntax.md +8 -8
- package/docs/getting_started/file_structure.md +10 -11
- package/docs/getting_started/intro.md +3 -3
- package/docs/plugins/text-to-speech-announcer.md +2 -2
- package/docs/sidebar.json +4 -0
- package/docs/transitions_animations/transitions.md +12 -12
- package/package.json +2 -2
- package/src/application.d.ts +10 -10
- package/src/component/base/announcer.js +27 -0
- package/src/component/base/events.js +37 -0
- package/src/component/base/index.js +29 -0
- package/src/component/base/log.js +27 -0
- package/src/component/base/methods.js +136 -0
- package/src/component/base/router.js +40 -0
- package/src/component/base/timeouts_intervals.js +92 -0
- package/src/component/base/utils.js +29 -0
- package/src/{lib → component}/setup/computed.js +3 -3
- package/src/component/setup/index.js +61 -0
- package/src/{lib → component}/setup/input.js +4 -4
- package/src/{lib → component}/setup/methods.js +3 -3
- package/src/{lib → component}/setup/props.js +3 -3
- package/src/{lib → component}/setup/routes.js +3 -3
- package/src/{lib → component}/setup/state.js +13 -6
- package/src/{lib → component}/setup/watch.js +5 -5
- package/src/component.d.ts +157 -38
- package/src/component.js +145 -154
- package/src/components/Circle.js +5 -5
- package/src/components/FPScounter.js +57 -89
- package/src/components/Image.js +2 -2
- package/src/components/RouterView.js +1 -1
- package/src/components/Sprite.js +5 -5
- package/src/components/Sprite.orig.js +2 -2
- package/src/components/Text.js +11 -11
- package/src/components/index.js +32 -0
- package/src/components/index.orig.js +32 -0
- package/src/engines/L3/element.js +44 -35
- package/src/engines/L3/launch.js +2 -1
- package/src/launch.d.ts +11 -1
- package/src/lib/codegenerator/generator.js +7 -6
- package/src/router/router.js +0 -7
- package/src/lib/setup/base.js +0 -284
- /package/src/{lib → component}/setup/props.test.js +0 -0
package/src/component.js
CHANGED
|
@@ -15,198 +15,156 @@
|
|
|
15
15
|
* SPDX-License-Identifier: Apache-2.0
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import { Log } from './lib/log.js'
|
|
18
19
|
import parser from './lib/templateparser/parser.js'
|
|
19
20
|
import codegenerator from './lib/codegenerator/generator.js'
|
|
20
|
-
|
|
21
|
-
import { stage, renderer } from './launch.js'
|
|
22
|
-
|
|
23
21
|
import { createHumanReadableId, createInternalId } from './lib/componentId.js'
|
|
24
|
-
import {
|
|
25
|
-
|
|
22
|
+
import { emit } from './lib/hooks.js'
|
|
26
23
|
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
24
|
import { effect } from './lib/reactivity/effect.js'
|
|
36
|
-
import
|
|
37
|
-
import
|
|
25
|
+
import Lifecycle from './lib/lifecycle.js'
|
|
26
|
+
import symbols from './lib/symbols.js'
|
|
27
|
+
|
|
28
|
+
import { stage, renderer } from './launch.js'
|
|
29
|
+
|
|
30
|
+
import Base from './component/base/index.js'
|
|
38
31
|
|
|
39
32
|
import Settings from './settings.js'
|
|
40
|
-
import symbols from './lib/symbols.js'
|
|
41
33
|
|
|
42
|
-
|
|
34
|
+
import setupComponent from './component/setup/index.js'
|
|
35
|
+
import components from './components/index.js'
|
|
36
|
+
|
|
37
|
+
// object to store global components
|
|
38
|
+
let globalComponents
|
|
43
39
|
|
|
44
40
|
const required = (name) => {
|
|
45
41
|
throw new Error(`Parameter ${name} is required`)
|
|
46
42
|
}
|
|
47
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Component factory function
|
|
46
|
+
* @param {string} name - The name of the component
|
|
47
|
+
* @param {object} config - The configuration object for the component
|
|
48
|
+
* @returns {function} - A factory function that creates a new component instance
|
|
49
|
+
*
|
|
50
|
+
*/
|
|
48
51
|
const Component = (name = required('name'), config = required('config')) => {
|
|
49
|
-
|
|
50
|
-
// code generation
|
|
51
|
-
if (!config.code) {
|
|
52
|
-
Log.debug(`Generating code for ${name} component`)
|
|
53
|
-
config.code = codegenerator.call(config, parser(config.template, name, parentComponent))
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
component[symbols.identifier] = ++counter
|
|
57
|
-
|
|
58
|
-
setupBase(component, name)
|
|
59
|
-
|
|
60
|
-
// setup hooks
|
|
61
|
-
registerHooks(config.hooks, component[symbols.identifier])
|
|
62
|
-
|
|
63
|
-
// setup props
|
|
64
|
-
// if (config.props) // because of the default props like id - might change this
|
|
65
|
-
setupProps(component, config.props)
|
|
66
|
-
|
|
67
|
-
// setup methods
|
|
68
|
-
if (config.methods) setupMethods(component, config.methods)
|
|
69
|
-
|
|
70
|
-
// setup state
|
|
71
|
-
setupState(component, config.state)
|
|
72
|
-
|
|
73
|
-
// setup computed
|
|
74
|
-
if (config.computed) setupComputed(component, config.computed)
|
|
75
|
-
|
|
76
|
-
// setup watchers
|
|
77
|
-
if (config.watch) setupWatch(component, config.watch)
|
|
78
|
-
|
|
79
|
-
// setup routes
|
|
80
|
-
if (config.routes) setupRoutes(component, config.routes)
|
|
81
|
-
|
|
82
|
-
// setup input
|
|
83
|
-
if (config.input) setupInput(component, config.input)
|
|
84
|
-
|
|
85
|
-
component.setup = true
|
|
86
|
-
}
|
|
52
|
+
let base
|
|
87
53
|
|
|
88
54
|
const component = function (opts, parentEl, parentComponent) {
|
|
89
|
-
|
|
55
|
+
// generate a human readable ID for the component instance (i.e. Blits::ComponentName1)
|
|
56
|
+
this.componentId = createHumanReadableId(name)
|
|
57
|
+
|
|
58
|
+
// instantiate a lifecycle object for this instance
|
|
59
|
+
this.lifecycle = Object.assign(Object.create(Lifecycle), {
|
|
90
60
|
component: this,
|
|
91
61
|
previous: null,
|
|
92
62
|
current: null,
|
|
93
63
|
})
|
|
94
64
|
|
|
95
|
-
|
|
96
|
-
setupComponent(parentComponent)
|
|
97
|
-
}
|
|
98
|
-
if (config.hooks && config.hooks.frameTick) {
|
|
99
|
-
renderer.on('frameTick', (r, data) =>
|
|
100
|
-
emit('frameTick', component[symbols.identifier], this, [data])
|
|
101
|
-
)
|
|
102
|
-
}
|
|
103
|
-
|
|
65
|
+
// set a reference to the parent component
|
|
104
66
|
this.parent = parentComponent
|
|
67
|
+
|
|
68
|
+
// set a reference to the holder / parentElement
|
|
69
|
+
// Components are wrapped in a holder node (used to apply positioning and transforms
|
|
70
|
+
// such as rotation and scale to components)
|
|
105
71
|
this[symbols.holder] = parentEl
|
|
106
72
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
value: createHumanReadableId(name),
|
|
110
|
-
writable: false,
|
|
111
|
-
enumerable: true,
|
|
112
|
-
configurable: false,
|
|
113
|
-
},
|
|
114
|
-
[symbols.id]: {
|
|
115
|
-
value: createInternalId(),
|
|
116
|
-
writable: false,
|
|
117
|
-
enumerable: false,
|
|
118
|
-
configurable: false,
|
|
119
|
-
},
|
|
120
|
-
[symbols.props]: {
|
|
121
|
-
value: reactive(opts.props || {}, Settings.get('reactivityMode')),
|
|
122
|
-
writable: false,
|
|
123
|
-
enumerable: false,
|
|
124
|
-
configurable: false,
|
|
125
|
-
},
|
|
126
|
-
[symbols.timeouts]: {
|
|
127
|
-
value: [],
|
|
128
|
-
writable: true,
|
|
129
|
-
enumerable: false,
|
|
130
|
-
configurable: false,
|
|
131
|
-
},
|
|
132
|
-
[symbols.intervals]: {
|
|
133
|
-
value: [],
|
|
134
|
-
writable: true,
|
|
135
|
-
enumerable: false,
|
|
136
|
-
configurable: false,
|
|
137
|
-
},
|
|
138
|
-
})
|
|
73
|
+
// generate an internal id (simple counter)
|
|
74
|
+
this[symbols.id] = createInternalId()
|
|
139
75
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
...((config.state && typeof config.state === 'function' && config.state.apply(this)) || {}),
|
|
143
|
-
...{ hasFocus: false },
|
|
144
|
-
},
|
|
145
|
-
writable: false,
|
|
146
|
-
enumerable: false,
|
|
147
|
-
configurable: false,
|
|
148
|
-
})
|
|
76
|
+
// set the internal props and make them reactive (based on the reactivity mode)
|
|
77
|
+
this[symbols.props] = reactive(opts.props || {}, Settings.get('reactivityMode'))
|
|
149
78
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
writable: false,
|
|
153
|
-
enumerable: false,
|
|
154
|
-
configurable: false,
|
|
155
|
-
})
|
|
79
|
+
// create an empty array for storing timeouts created by this component (via this.$setTimeout)
|
|
80
|
+
this[symbols.timeouts] = []
|
|
156
81
|
|
|
157
|
-
this
|
|
82
|
+
// create an empty array for storing intervals created by this component (via this.$setInterval)
|
|
83
|
+
this[symbols.intervals] = []
|
|
158
84
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
85
|
+
// apply the state function (passing in the this reference to utilize configured props)
|
|
86
|
+
// and store a reference to this original state
|
|
87
|
+
// hasFocus key is sprinkled in
|
|
88
|
+
this[symbols.originalState] = {
|
|
89
|
+
...((config.state && typeof config.state === 'function' && config.state.apply(this)) || {}),
|
|
90
|
+
...{ hasFocus: false },
|
|
91
|
+
}
|
|
165
92
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
enumerable: false,
|
|
170
|
-
configurable: false,
|
|
171
|
-
})
|
|
93
|
+
// generate a reactive state (using the result of previously execute state function)
|
|
94
|
+
// and store it
|
|
95
|
+
this[symbols.state] = reactive(this[symbols.originalState], Settings.get('reactivityMode'))
|
|
172
96
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
this.lifecycle.state = 'attach'
|
|
176
|
-
})
|
|
177
|
-
}
|
|
97
|
+
// all basic setup has been done now, set the lifecycle to state 'init'
|
|
98
|
+
this.lifecycle.state = 'init'
|
|
178
99
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
100
|
+
// execute the render code that constructs the initial state of the component
|
|
101
|
+
// and store the children result (a flat map of elements and components)
|
|
102
|
+
this[symbols.children] = config.code.render.apply(stage, [
|
|
103
|
+
parentEl,
|
|
104
|
+
this,
|
|
105
|
+
config,
|
|
106
|
+
globalComponents,
|
|
107
|
+
])
|
|
108
|
+
|
|
109
|
+
// create a reference to the wrapper element of the component (i.e. the root Element of the component)
|
|
110
|
+
this[symbols.wrapper] = this[symbols.children][0]
|
|
111
|
+
|
|
112
|
+
// create a reference to an array of children that are slots
|
|
113
|
+
this[symbols.slots] = this[symbols.children].filter((child) => child[symbols.isSlot])
|
|
114
|
+
|
|
115
|
+
// register hooks if component has hooks specified
|
|
116
|
+
if (config.hooks) {
|
|
117
|
+
// frame tick event
|
|
118
|
+
if (config.hooks.frameTick) {
|
|
119
|
+
renderer.on('frameTick', (r, data) =>
|
|
120
|
+
emit('frameTick', this[symbols.identifier], this, [data])
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (config.hooks.idle) {
|
|
125
|
+
renderer.on('idle', () => {
|
|
126
|
+
emit('idle', this[symbols.identifier], this)
|
|
127
|
+
})
|
|
128
|
+
}
|
|
184
129
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
this.
|
|
188
|
-
|
|
189
|
-
|
|
130
|
+
// inBounds event emiting a lifecycle attach event
|
|
131
|
+
if (config.hooks.attach) {
|
|
132
|
+
this[symbols.wrapper].node.on('inBounds', () => {
|
|
133
|
+
this.lifecycle.state = 'attach'
|
|
134
|
+
})
|
|
135
|
+
}
|
|
190
136
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
this.
|
|
194
|
-
|
|
195
|
-
|
|
137
|
+
// outOfBounds event emiting a lifeycle detach event
|
|
138
|
+
if (config.hooks.detach) {
|
|
139
|
+
this[symbols.wrapper].node.on('outOfBounds', (node, { previous }) => {
|
|
140
|
+
if (previous > 0) this.lifecycle.state = 'detach'
|
|
141
|
+
})
|
|
142
|
+
}
|
|
196
143
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
144
|
+
// inViewport event emiting a lifecycle enter event
|
|
145
|
+
if (config.hooks.enter) {
|
|
146
|
+
this[symbols.wrapper].node.on('inViewport', () => {
|
|
147
|
+
this.lifecycle.state = 'enter'
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// outOfViewport event emitting a lifecycle exit event
|
|
152
|
+
if (config.hooks.exit) {
|
|
153
|
+
this[symbols.wrapper].node.on('outOfViewport', () => {
|
|
154
|
+
this.lifecycle.state = 'exit'
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
}
|
|
203
158
|
|
|
159
|
+
// setup (and execute) all the generated side effects based on the
|
|
160
|
+
// reactive bindings define in the template
|
|
204
161
|
config.code.effects.forEach((eff) => {
|
|
205
162
|
effect(() => {
|
|
206
|
-
eff.apply(stage, [this, this[symbols.children], config])
|
|
163
|
+
eff.apply(stage, [this, this[symbols.children], config, globalComponents])
|
|
207
164
|
})
|
|
208
165
|
})
|
|
209
166
|
|
|
167
|
+
// setup watchers if the components has watchers specified
|
|
210
168
|
if (this[symbols.watchers]) {
|
|
211
169
|
Object.keys(this[symbols.watchers]).forEach((watchKey) => {
|
|
212
170
|
let old = this[watchKey]
|
|
@@ -219,14 +177,47 @@ const Component = (name = required('name'), config = required('config')) => {
|
|
|
219
177
|
})
|
|
220
178
|
}
|
|
221
179
|
|
|
222
|
-
//
|
|
180
|
+
// set all symbol based properties to non-enumerable and non-configurable
|
|
181
|
+
Object.getOwnPropertySymbols(this).forEach((property) => {
|
|
182
|
+
Object.defineProperties(this, {
|
|
183
|
+
[property]: {
|
|
184
|
+
enumerable: false,
|
|
185
|
+
configurable: false,
|
|
186
|
+
},
|
|
187
|
+
})
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
// finaly set the lifecycle state to ready (in the next tick)
|
|
223
191
|
setTimeout(() => (this.lifecycle.state = 'ready'))
|
|
192
|
+
|
|
193
|
+
// and return this
|
|
194
|
+
return this
|
|
224
195
|
}
|
|
225
196
|
|
|
226
197
|
const factory = (options = {}, parentEl, parentComponent) => {
|
|
227
|
-
|
|
198
|
+
// setup the component once, using Base as the prototype
|
|
199
|
+
if (!base) {
|
|
200
|
+
Log.debug(`Setting up ${name} component`)
|
|
201
|
+
base = setupComponent(Object.create(Base), config)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// one time code generation (only if precompilation is turned off)
|
|
205
|
+
if (!config.code) {
|
|
206
|
+
Log.debug(`Generating code for ${name} component`)
|
|
207
|
+
config.code = codegenerator.call(config, parser(config.template, name))
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// register global components once
|
|
211
|
+
if (!globalComponents) {
|
|
212
|
+
globalComponents = components()
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// create an instance of the component, using base as the prototype (which contains Base)
|
|
216
|
+
return component.call(Object.create(base), options, parentEl, parentComponent)
|
|
228
217
|
}
|
|
229
218
|
|
|
219
|
+
// store the config on the factory, in order to access the config
|
|
220
|
+
// during the code generation step
|
|
230
221
|
factory.config = config
|
|
231
222
|
|
|
232
223
|
return factory
|
package/src/components/Circle.js
CHANGED
|
@@ -21,7 +21,7 @@ export default () =>
|
|
|
21
21
|
Component('Circle', {
|
|
22
22
|
/* eslint-disable no-unused-vars */
|
|
23
23
|
code: {
|
|
24
|
-
render: function anonymous(parent, component, context) {
|
|
24
|
+
render: function anonymous(parent, component, context, components) {
|
|
25
25
|
const elms = []
|
|
26
26
|
|
|
27
27
|
if (!elms[0]) {
|
|
@@ -36,16 +36,16 @@ export default () =>
|
|
|
36
36
|
return elms
|
|
37
37
|
},
|
|
38
38
|
effects: [
|
|
39
|
-
function anonymous(component, elms, context) {
|
|
39
|
+
function anonymous(component, elms, context, components) {
|
|
40
40
|
elms[0].set('color', component.color)
|
|
41
41
|
},
|
|
42
|
-
function anonymous(component, elms, context) {
|
|
42
|
+
function anonymous(component, elms, context, components) {
|
|
43
43
|
elms[0].set('w', component.size)
|
|
44
44
|
},
|
|
45
|
-
function anonymous(component, elms, context) {
|
|
45
|
+
function anonymous(component, elms, context, components) {
|
|
46
46
|
elms[0].set('h', component.size)
|
|
47
47
|
},
|
|
48
|
-
function anonymous(component, elms, context) {
|
|
48
|
+
function anonymous(component, elms, context, components) {
|
|
49
49
|
elms[0].set('effects', [component.shader('radius', { radius: component.radius })])
|
|
50
50
|
},
|
|
51
51
|
],
|