@lightningjs/blits 0.8.1 → 0.9.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 +20 -0
- package/boilerplate/js/default/src/index.js +2 -8
- package/docs/README.md +0 -21
- package/docs/_sidebar.md +25 -13
- package/docs/built-in/directives.md +44 -0
- package/docs/{component_state.md → components/component_state.md} +37 -5
- package/docs/components/computed_properties.md +48 -0
- package/docs/{lifecycle_events.md → components/lifecycle_events.md} +4 -2
- package/docs/components/methods.md +47 -0
- package/docs/components/props.md +58 -0
- package/docs/{user_input.md → components/user_input.md} +31 -26
- package/docs/components/utilities.md +4 -0
- package/docs/components/watchers.md +36 -0
- package/docs/essentials/application_root.md +21 -0
- package/docs/{components.md → essentials/components.md} +17 -5
- package/docs/{displaying_images.md → essentials/displaying_images.md} +7 -7
- package/docs/essentials/displaying_text.md +77 -0
- package/docs/{element_attributes.md → essentials/element_attributes.md} +17 -12
- package/docs/essentials/template_syntax.md +85 -0
- package/docs/getting_started/file_structure.md +61 -0
- package/docs/getting_started/getting_started.md +47 -0
- package/docs/{introduction.md → getting_started/intro.md} +2 -1
- package/docs/sidebar.json +70 -26
- package/docs/transitions_animations/transitions.md +132 -0
- package/package.json +2 -2
- package/src/component.js +12 -3
- package/src/element.js +8 -5
- package/src/fontLoader.js +20 -21
- package/src/launch.d.ts +22 -7
- package/src/launch.js +13 -2
- package/src/lib/codegenerator/generator.js +8 -7
- package/src/lib/codegenerator/generator.test.js +11 -16
- package/src/lib/hooks.js +7 -7
- package/src/lib/lifecycle.js +3 -2
- package/src/lib/reactivity/effect.js +23 -0
- package/src/lib/reactivity/reactive.js +59 -46
- package/src/lib/setup/base.js +18 -10
- package/src/lib/setup/state.js +1 -1
- package/src/lib/symbols.js +3 -0
- package/src/router/router.js +6 -6
- package/boilerplate/js/default/src/fontloader.js +0 -4
- package/docs/computed_properties.md +0 -18
- package/docs/getting_started.md +0 -40
- package/docs/props.md +0 -46
- package/docs/template_syntax.md +0 -65
- package/docs/watchers.md +0 -38
- /package/docs/{text-to-speech-announcer.md → plugins/text-to-speech-announcer.md} +0 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Blits - Lightning 3 App Development Framework
|
|
2
|
+
|
|
3
|
+
## Transitions
|
|
4
|
+
|
|
5
|
+
So far we have explored how to create components and draw elements on the screen. But everything has
|
|
6
|
+
been rather static so far.
|
|
7
|
+
|
|
8
|
+
We did learn how to _reactively_ changes values and trigger rerenders based on that. So if you try the example below, you'll see that indeed our golden element changes position. But it just jumps from one place to another:
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
export default Blits('Gold', {
|
|
12
|
+
template: `
|
|
13
|
+
<Element color="gold" w="100" h="100" :x="$x" :y=:"$y" />
|
|
14
|
+
`,
|
|
15
|
+
state() {
|
|
16
|
+
return {
|
|
17
|
+
x: 0,
|
|
18
|
+
y: 0,
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
input: {
|
|
22
|
+
enter() {
|
|
23
|
+
this.x = this.x + 100
|
|
24
|
+
this.y = this.y + 50
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Using _transitions_ we really make our App come alive.
|
|
30
|
+
|
|
31
|
+
### Applying a transition
|
|
32
|
+
|
|
33
|
+
Blits offers an easy and intuitive way to apply transitions. All you need to do is add the `.transition` modifier to a reactive attribute, and now whenever you change the value referenced in the attribute, it will automatically _smooth_ into the new value.
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
export default Blits('Gold', {
|
|
37
|
+
template: `
|
|
38
|
+
<Element color="gold" w="100" h="100" :x.transiton="$x" :y.transition=:"$y" />
|
|
39
|
+
`,
|
|
40
|
+
state() {
|
|
41
|
+
return {
|
|
42
|
+
x: 0,
|
|
43
|
+
y: 0,
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
input: {
|
|
47
|
+
enter() {
|
|
48
|
+
this.x = this.x + 100
|
|
49
|
+
this.y = this.y + 50
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
If we try out the modified example above, you'll notice how difference adding a simple transition makes.
|
|
55
|
+
|
|
56
|
+
When the `.transition`-modifier is added to a reactive attribute, a default `ease-in` transition with a duration of `300ms` is applied
|
|
57
|
+
|
|
58
|
+
### Customizing transitions
|
|
59
|
+
|
|
60
|
+
While the default transition will look pretty good out of the box and is great for quickly improving the look of your App, you may want to customize specific transitions.
|
|
61
|
+
|
|
62
|
+
Blits gives you full control over your transitions, with a simple to use format, right inside your template.
|
|
63
|
+
|
|
64
|
+
Instead of referencing your component's state variable directly, you can also supply an inlien `object literal` in the attribute with a `.transition`-modifier. This will allow you to pass a number of options to change the way the transition will work.
|
|
65
|
+
|
|
66
|
+
The transition object must have a `value` key, which references the state variable (or prop or computed property) that triggers the transition.
|
|
67
|
+
|
|
68
|
+
Further more you can specify:
|
|
69
|
+
|
|
70
|
+
- `duration` - the duration of the transition in `ms`
|
|
71
|
+
- `delay` - the time in `ms` after which the transition should initiate
|
|
72
|
+
- `easing` - the easing function of the transition. Can be one of the defaults easing options listed below, or a custom `cubic-bezier` definitions (i.e. `cubic-bezier(0,1.35,.99,-0.07)`).
|
|
73
|
+
|
|
74
|
+
```xml
|
|
75
|
+
<Element color="gold" w="100" h="100"
|
|
76
|
+
:x.transiton="{value: $x, duration: 300, easing: 'ease-in-back', delay: 400}"
|
|
77
|
+
:y.transition=:"{value: $x, duration: 300, easing: 'cubic-bezier(1,-0.64,0.39,1.44)'}">
|
|
78
|
+
</Element>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Besides a reference to the `value`, you can also use dynamic values for the other keys in the transition object. This way you'll be able to dynamically control the delay, duration or easing function.
|
|
82
|
+
|
|
83
|
+
```xml
|
|
84
|
+
<Element color="gold" w="100" h="100"
|
|
85
|
+
:x.transiton="{value: $x, duration: $dynamicDuration, delay: $dynamicDelay}">
|
|
86
|
+
</Element>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### Available easing functions
|
|
90
|
+
|
|
91
|
+
- `ease-in`
|
|
92
|
+
- `ease-out`
|
|
93
|
+
- `ease-in-out`
|
|
94
|
+
- `ease-in-sine`
|
|
95
|
+
- `ease-out-sine`
|
|
96
|
+
- `ease-in-out-sine`
|
|
97
|
+
- `ease-in-cubic`
|
|
98
|
+
- `ease-out-cubic`
|
|
99
|
+
- `ease-in-out-cubic`
|
|
100
|
+
- `ease-in-circ`
|
|
101
|
+
- `ease-out-circ`
|
|
102
|
+
- `ease-in-out-circ`
|
|
103
|
+
- `ease-in-back`
|
|
104
|
+
- `ease-out-back`
|
|
105
|
+
- `ease-in-out-back`
|
|
106
|
+
|
|
107
|
+
### Listening to transition events
|
|
108
|
+
|
|
109
|
+
Sometimes you may want to perform an action when a transition ends or when it starts.
|
|
110
|
+
|
|
111
|
+
You can easily hook into these transiti)on events by adding a `start` and `end` key to the transition object. Both value should be a function (or a reference to a `method` on your component).
|
|
112
|
+
|
|
113
|
+
The `start` function will be called when the transition actually starts (after a possible specified delay) and the `end` function is called as soon as the transitions is finished.
|
|
114
|
+
|
|
115
|
+
```js
|
|
116
|
+
export default Blits('Gold', {
|
|
117
|
+
template: `
|
|
118
|
+
<Element color="gold" w="100" h="100"
|
|
119
|
+
:x.transiton="{value: $x, start: $transitionBegin, end: $transitionEnd}"
|
|
120
|
+
/>
|
|
121
|
+
`,
|
|
122
|
+
///
|
|
123
|
+
methods: {
|
|
124
|
+
transitionBegin() {
|
|
125
|
+
//
|
|
126
|
+
},
|
|
127
|
+
transitionEnd() {
|
|
128
|
+
//
|
|
129
|
+
},
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightningjs/blits",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Blits: The Lightning 3 App Development Framework",
|
|
5
5
|
"bin": "bin/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"tape": "^5.5.0"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@lightningjs/renderer": "^0.7.
|
|
48
|
+
"@lightningjs/renderer": "^0.7.6",
|
|
49
49
|
"@lightningjs/vite-plugin-import-chunk-url": "^0.3.0",
|
|
50
50
|
"execa": "^8.0.1",
|
|
51
51
|
"kolorist": "^1.8.0",
|
package/src/component.js
CHANGED
|
@@ -40,6 +40,8 @@ import lifecycle from './lib/lifecycle.js'
|
|
|
40
40
|
import Settings from './settings.js'
|
|
41
41
|
import symbols from './lib/symbols.js'
|
|
42
42
|
|
|
43
|
+
let counter = 0
|
|
44
|
+
|
|
43
45
|
const stage = {
|
|
44
46
|
element,
|
|
45
47
|
}
|
|
@@ -56,10 +58,12 @@ const Component = (name = required('name'), config = required('config')) => {
|
|
|
56
58
|
config.code = codegenerator.call(config, parser(config.template, name, parentComponent))
|
|
57
59
|
}
|
|
58
60
|
|
|
61
|
+
component[symbols.identifier] = ++counter
|
|
62
|
+
|
|
59
63
|
setupBase(component, name)
|
|
60
64
|
|
|
61
65
|
// setup hooks
|
|
62
|
-
registerHooks(config.hooks,
|
|
66
|
+
registerHooks(config.hooks, component[symbols.identifier])
|
|
63
67
|
|
|
64
68
|
// setup props
|
|
65
69
|
// if (config.props) // because of the default props like id - might change this
|
|
@@ -97,7 +101,9 @@ const Component = (name = required('name'), config = required('config')) => {
|
|
|
97
101
|
setupComponent(parentComponent)
|
|
98
102
|
}
|
|
99
103
|
if (config.hooks && config.hooks.frameTick) {
|
|
100
|
-
renderer.on('frameTick', (r, data) =>
|
|
104
|
+
renderer.on('frameTick', (r, data) =>
|
|
105
|
+
emit('frameTick', component[symbols.identifier], this, [data])
|
|
106
|
+
)
|
|
101
107
|
}
|
|
102
108
|
|
|
103
109
|
this.parent = parentComponent
|
|
@@ -137,7 +143,10 @@ const Component = (name = required('name'), config = required('config')) => {
|
|
|
137
143
|
})
|
|
138
144
|
|
|
139
145
|
Object.defineProperty(this, symbols.originalState, {
|
|
140
|
-
value:
|
|
146
|
+
value: {
|
|
147
|
+
...((config.state && typeof config.state === 'function' && config.state.apply(this)) || {}),
|
|
148
|
+
...{ hasFocus: false },
|
|
149
|
+
},
|
|
141
150
|
writable: false,
|
|
142
151
|
enumerable: false,
|
|
143
152
|
configurable: false,
|
package/src/element.js
CHANGED
|
@@ -194,7 +194,7 @@ const Props = {
|
|
|
194
194
|
this._set.add('alpha')
|
|
195
195
|
},
|
|
196
196
|
set text(v) {
|
|
197
|
-
this._props.text = v
|
|
197
|
+
this._props.text = v.toString()
|
|
198
198
|
},
|
|
199
199
|
set effects(v) {
|
|
200
200
|
this._props.shader = renderer.createShader('DynamicShader', {
|
|
@@ -229,7 +229,7 @@ const Props = {
|
|
|
229
229
|
this._props.overflowSuffix = v === false ? ' ' : v === true ? undefined : v
|
|
230
230
|
},
|
|
231
231
|
set letterSpacing(v) {
|
|
232
|
-
this._props.letterSpacing = v
|
|
232
|
+
this._props.letterSpacing = v || 1
|
|
233
233
|
},
|
|
234
234
|
set lineHeight(v) {
|
|
235
235
|
this._props.lineHeight = v
|
|
@@ -259,12 +259,14 @@ const Element = {
|
|
|
259
259
|
for (const [prop, value] of Object.entries(props)) {
|
|
260
260
|
const descriptor = Object.getOwnPropertyDescriptor(Props, prop)
|
|
261
261
|
if (descriptor && descriptor.set) {
|
|
262
|
-
|
|
262
|
+
if (value !== undefined) {
|
|
263
|
+
this.props[prop] = unpackTransition(value)
|
|
264
|
+
}
|
|
263
265
|
}
|
|
264
266
|
}
|
|
265
267
|
|
|
266
|
-
// correct for default white nodes
|
|
267
|
-
if (!this.props._set.has('color')) {
|
|
268
|
+
// correct for default white nodes (but not for text nodes)
|
|
269
|
+
if (!props.__textnode && !this.props._set.has('color')) {
|
|
268
270
|
this.props._props.color =
|
|
269
271
|
this.props._set.has('src') || this.props._set.has('texture') ? 0xffffffff : 0
|
|
270
272
|
}
|
|
@@ -286,6 +288,7 @@ const Element = {
|
|
|
286
288
|
}
|
|
287
289
|
},
|
|
288
290
|
set(prop, value) {
|
|
291
|
+
if (value === undefined) return
|
|
289
292
|
const propsSet = new Set(this.props._set)
|
|
290
293
|
|
|
291
294
|
this.props._props = {}
|
package/src/fontLoader.js
CHANGED
|
@@ -1,26 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { WebTrFontFace, SdfTrFontFace } from '@lightningjs/renderer/core'
|
|
2
2
|
|
|
3
3
|
import Settings from './settings'
|
|
4
|
+
import { renderer } from './launch'
|
|
4
5
|
|
|
5
|
-
export default
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
stage.fontManager.addFontFace(
|
|
19
|
-
new SdfTrFontFace(font.family, {}, font.type, stage, font.png, font.json)
|
|
20
|
-
)
|
|
21
|
-
} else if (font.type === 'web') {
|
|
22
|
-
stage.fontManager.addFontFace(new WebTrFontFace(font.family, {}, font.file))
|
|
6
|
+
export default () => {
|
|
7
|
+
const stage = renderer.driver.stage
|
|
8
|
+
Settings.get('fonts', []).forEach((font) => {
|
|
9
|
+
if (font.type === 'sdf' || font.type === 'msdf') {
|
|
10
|
+
// automatically map png key to file name
|
|
11
|
+
if (!font.png && font.file) {
|
|
12
|
+
font.png = font.file.replace(/\.[^.]+$/, `.${font.type}.png`)
|
|
13
|
+
}
|
|
14
|
+
// automatically map json to file name
|
|
15
|
+
if (!font.json && font.file) {
|
|
16
|
+
font.json = font.file.replace(/\.[^.]+$/, `.${font.type}.json`)
|
|
23
17
|
}
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
stage.fontManager.addFontFace(
|
|
19
|
+
new SdfTrFontFace(font.family, {}, font.type, stage, font.png, font.json)
|
|
20
|
+
)
|
|
21
|
+
} else if (font.type === 'web') {
|
|
22
|
+
stage.fontManager.addFontFace(new WebTrFontFace(font.family, {}, font.file))
|
|
23
|
+
}
|
|
24
|
+
})
|
|
26
25
|
}
|
package/src/launch.d.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import ApplicationInstance from './application'
|
|
19
|
-
|
|
19
|
+
import {type Stage} from '@lightningjs/renderer'
|
|
20
20
|
interface WebFont {
|
|
21
21
|
/**
|
|
22
22
|
* Name of the font family
|
|
@@ -70,6 +70,9 @@ export type DebugLevel = 0 | 1 | 2
|
|
|
70
70
|
export type LogTypes = 'info' | 'warn' | 'error' | 'debug'
|
|
71
71
|
export type ReactivityModes = 'Proxy' | 'defineProperty'
|
|
72
72
|
|
|
73
|
+
interface ExtensionLoader {
|
|
74
|
+
async (stage: Stage): void
|
|
75
|
+
}
|
|
73
76
|
/**
|
|
74
77
|
* Settings
|
|
75
78
|
*
|
|
@@ -92,11 +95,7 @@ export interface Settings {
|
|
|
92
95
|
/**
|
|
93
96
|
* Debug level for console log messages
|
|
94
97
|
*/
|
|
95
|
-
debugLevel?: DebugLevel | LogTypes[]
|
|
96
|
-
/**
|
|
97
|
-
* Font loader file
|
|
98
|
-
*/
|
|
99
|
-
fontLoader?: any
|
|
98
|
+
debugLevel?: DebugLevel | LogTypes[],
|
|
100
99
|
/**
|
|
101
100
|
* Fonts to be used in the Application
|
|
102
101
|
*/
|
|
@@ -191,7 +190,23 @@ export interface Settings {
|
|
|
191
190
|
*
|
|
192
191
|
* Defaults to `false`
|
|
193
192
|
*/
|
|
194
|
-
inspector?: boolean
|
|
193
|
+
inspector?: boolean,
|
|
194
|
+
/**
|
|
195
|
+
* Add an extra margin to the viewport for earlier pre-loading of elements and components
|
|
196
|
+
*
|
|
197
|
+
* By default the Lightning renderer, only renders elements that are inside the defined viewport.
|
|
198
|
+
* Everything outside of these bounds is removed from the render tree.
|
|
199
|
+
*
|
|
200
|
+
* With the viewportMargin you have the option to _virtually_ increase the viewport area,
|
|
201
|
+
* to expedite the pre-loading of elements and / or delay the unloading of elements depending
|
|
202
|
+
* on their position in the (virtual) viewport
|
|
203
|
+
*
|
|
204
|
+
* The margin can be specified in 4 directions by defining an array [top, right, bottom, left],
|
|
205
|
+
* or as a single number which is then applied to all 4 directions equally.
|
|
206
|
+
*
|
|
207
|
+
* Defaults to `0`
|
|
208
|
+
*/
|
|
209
|
+
viewportMargin?: number | [number, number, number, number]
|
|
195
210
|
}
|
|
196
211
|
|
|
197
212
|
/**
|
package/src/launch.js
CHANGED
|
@@ -21,6 +21,7 @@ import Settings from './settings.js'
|
|
|
21
21
|
import { initLog, Log } from './lib/log.js'
|
|
22
22
|
import { screenResolutions } from './lib/utils.js'
|
|
23
23
|
import colors from './lib/colors/colors.js'
|
|
24
|
+
import fontLoader from './fontLoader.js'
|
|
24
25
|
|
|
25
26
|
export let renderer
|
|
26
27
|
|
|
@@ -36,11 +37,20 @@ export default (App, target, settings) => {
|
|
|
36
37
|
// })
|
|
37
38
|
// : new MainCoreDriver()
|
|
38
39
|
|
|
40
|
+
if ('fontLoader' in settings) {
|
|
41
|
+
Log.warn(
|
|
42
|
+
`
|
|
43
|
+
|
|
44
|
+
Starting version 0.9.0 of Blits, the Launch setting \`fontLoader\` is not supported / required anymore.
|
|
45
|
+
You can remove the option from your \`src/index.js\`-file. And you can safely remove the file \`src/fontLoader.js\` from your project.
|
|
46
|
+
`
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
39
50
|
renderer = new RendererMain(
|
|
40
51
|
{
|
|
41
52
|
appWidth: settings.w || 1920,
|
|
42
53
|
appHeight: settings.h || 1080,
|
|
43
|
-
coreExtensionModule: settings.fontLoader,
|
|
44
54
|
fpsUpdateInterval: settings.fpsInterval || 1000,
|
|
45
55
|
deviceLogicalPixelRatio:
|
|
46
56
|
settings.pixelRatio ||
|
|
@@ -53,6 +63,7 @@ export default (App, target, settings) => {
|
|
|
53
63
|
: window.navigator.hardwareConcurrency || 2,
|
|
54
64
|
clearColor: (settings.canvasColor && colors.normalize(settings.canvasColor)) || 0x00000000,
|
|
55
65
|
enableInspector: settings.inspector || false,
|
|
66
|
+
boundsMargin: settings.viewportMargin || 0,
|
|
56
67
|
},
|
|
57
68
|
target,
|
|
58
69
|
driver
|
|
@@ -68,5 +79,5 @@ export default (App, target, settings) => {
|
|
|
68
79
|
}
|
|
69
80
|
}
|
|
70
81
|
|
|
71
|
-
renderer.init().then((
|
|
82
|
+
renderer.init().then(fontLoader).then(initApp)
|
|
72
83
|
}
|
|
@@ -216,6 +216,8 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
216
216
|
if (parent) {
|
|
217
217
|
ctx.renderCode.push(`parent = ${parent}`)
|
|
218
218
|
}
|
|
219
|
+
|
|
220
|
+
const forCounter = counter
|
|
219
221
|
ctx.renderCode.push(`
|
|
220
222
|
const collection = ${cast(result[2], ':for')}
|
|
221
223
|
const keys = []
|
|
@@ -223,7 +225,7 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
223
225
|
parent = ${parent}
|
|
224
226
|
if(!component.key) keys.length = 0
|
|
225
227
|
const scope = Object.assign(component, {
|
|
226
|
-
key: Math.random(),
|
|
228
|
+
key: Math.random().toString(),
|
|
227
229
|
${index}: __index,
|
|
228
230
|
${item}: collection[__index],
|
|
229
231
|
`)
|
|
@@ -241,7 +243,7 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
241
243
|
|
|
242
244
|
if ('key' in templateObject) {
|
|
243
245
|
ctx.renderCode.push(`
|
|
244
|
-
keys.push(${interpolate(templateObject.key, 'scope.')})
|
|
246
|
+
keys.push(${interpolate(templateObject.key, 'scope.')}.toString())
|
|
245
247
|
`)
|
|
246
248
|
} else {
|
|
247
249
|
ctx.renderCode.push(`
|
|
@@ -269,12 +271,11 @@ const generateForLoopCode = function (templateObject, parent) {
|
|
|
269
271
|
ctx.renderCode.push('}')
|
|
270
272
|
|
|
271
273
|
ctx.renderCode.push(`
|
|
272
|
-
|
|
273
|
-
Object.keys(elms[${
|
|
274
|
+
if(elms[${forCounter}]) {
|
|
275
|
+
Object.keys(elms[${forCounter}]).forEach(key => {
|
|
274
276
|
if(keys.indexOf(key) === -1) {
|
|
275
|
-
elms[${
|
|
276
|
-
|
|
277
|
-
delete elms[${counter}][key]
|
|
277
|
+
elms[${forCounter}][key].destroy && elms[${forCounter}][key].destroy()
|
|
278
|
+
delete elms[1][key]
|
|
278
279
|
}
|
|
279
280
|
})
|
|
280
281
|
}
|
|
@@ -2145,7 +2145,6 @@ test('Generate code for a template with a simple for-loop on an Element', (asser
|
|
|
2145
2145
|
if(elms[1]) {
|
|
2146
2146
|
Object.keys(elms[1]).forEach(key => {
|
|
2147
2147
|
if(keys.indexOf(key) === -1) {
|
|
2148
|
-
elms[1][key].delete && elms[1][key].delete()
|
|
2149
2148
|
elms[1][key].destroy && elms[1][key].destroy()
|
|
2150
2149
|
delete elms[1][key]
|
|
2151
2150
|
}
|
|
@@ -2237,7 +2236,6 @@ test('Generate code for a template with a simple for-loop on an Element with a c
|
|
|
2237
2236
|
if(elms[1]) {
|
|
2238
2237
|
Object.keys(elms[1]).forEach(key => {
|
|
2239
2238
|
if(keys.indexOf(key) === -1) {
|
|
2240
|
-
elms[1][key].delete && elms[1][key].delete()
|
|
2241
2239
|
elms[1][key].destroy && elms[1][key].destroy()
|
|
2242
2240
|
delete elms[1][key]
|
|
2243
2241
|
}
|
|
@@ -2314,25 +2312,24 @@ test('Generate code for a template with a simple for-loop on an Element with a k
|
|
|
2314
2312
|
index: __index,
|
|
2315
2313
|
item: collection[__index],
|
|
2316
2314
|
})
|
|
2317
|
-
keys.push(item.id)
|
|
2315
|
+
keys.push(scope.item.id)
|
|
2318
2316
|
|
|
2319
2317
|
parent = elms[0]
|
|
2320
2318
|
elms[1] = elms[1] || {}
|
|
2321
|
-
if(!elms[1][item.id]) {
|
|
2322
|
-
elms[1][item.id] = this.element({parent: parent || 'root'}, component)
|
|
2319
|
+
if(!elms[1][scope.item.id]) {
|
|
2320
|
+
elms[1][scope.item.id] = this.element({parent: parent || 'root'}, component)
|
|
2323
2321
|
}
|
|
2324
2322
|
|
|
2325
2323
|
const elementConfig1 = {}
|
|
2326
|
-
elementConfig1['key'] =
|
|
2324
|
+
elementConfig1['key'] = scope.item.id
|
|
2327
2325
|
|
|
2328
|
-
if(!elms[1][item.id].nodeId) {
|
|
2329
|
-
elms[1][item.id].populate(elementConfig1)
|
|
2326
|
+
if(!elms[1][scope.item.id].nodeId) {
|
|
2327
|
+
elms[1][scope.item.id].populate(elementConfig1)
|
|
2330
2328
|
}
|
|
2331
2329
|
}
|
|
2332
2330
|
if(elms[1]) {
|
|
2333
2331
|
Object.keys(elms[1]).forEach(key => {
|
|
2334
2332
|
if(keys.indexOf(key) === -1) {
|
|
2335
|
-
elms[1][key].delete && elms[1][key].delete()
|
|
2336
2333
|
elms[1][key].destroy && elms[1][key].destroy()
|
|
2337
2334
|
delete elms[1][key]
|
|
2338
2335
|
}
|
|
@@ -2424,7 +2421,7 @@ test('Generate code for a template with a simple for-loop on a Component with a
|
|
|
2424
2421
|
|
|
2425
2422
|
if(typeof cmp1 !== 'undefined') {
|
|
2426
2423
|
for(let key in cmp1.config.props) {
|
|
2427
|
-
delete
|
|
2424
|
+
delete elementConfig1[cmp1.config.props[key]]
|
|
2428
2425
|
}
|
|
2429
2426
|
}
|
|
2430
2427
|
|
|
@@ -2449,12 +2446,11 @@ test('Generate code for a template with a simple for-loop on a Component with a
|
|
|
2449
2446
|
}
|
|
2450
2447
|
}
|
|
2451
2448
|
}
|
|
2452
|
-
if(elms[
|
|
2453
|
-
Object.keys(elms[
|
|
2449
|
+
if(elms[1]) {
|
|
2450
|
+
Object.keys(elms[1]).forEach(key => {
|
|
2454
2451
|
if(keys.indexOf(key) === -1) {
|
|
2455
|
-
elms[
|
|
2456
|
-
|
|
2457
|
-
delete elms[2][key]
|
|
2452
|
+
elms[1][key].destroy && elms[1][key].destroy()
|
|
2453
|
+
delete elms[1][key]
|
|
2458
2454
|
}
|
|
2459
2455
|
})
|
|
2460
2456
|
}
|
|
@@ -2550,7 +2546,6 @@ test('Generate code for a template with a simple for-loop on an Element with an
|
|
|
2550
2546
|
if(elms[1]) {
|
|
2551
2547
|
Object.keys(elms[1]).forEach(key => {
|
|
2552
2548
|
if(keys.indexOf(key) === -1) {
|
|
2553
|
-
elms[1][key].delete && elms[1][key].delete()
|
|
2554
2549
|
elms[1][key].destroy && elms[1][key].destroy()
|
|
2555
2550
|
delete elms[1][key]
|
|
2556
2551
|
}
|
package/src/lib/hooks.js
CHANGED
|
@@ -19,20 +19,20 @@ import symbols from './symbols.js'
|
|
|
19
19
|
|
|
20
20
|
const cbs = {}
|
|
21
21
|
|
|
22
|
-
export const emit = (hook,
|
|
23
|
-
cbs[
|
|
22
|
+
export const emit = (hook, identifier, scope, data = []) => {
|
|
23
|
+
cbs[identifier] && cbs[identifier][hook] && cbs[identifier][hook].apply(scope, data)
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export const privateEmit = (hook,
|
|
26
|
+
export const privateEmit = (hook, identifier, scope) => {
|
|
27
27
|
const symHook = symbols[hook]
|
|
28
|
-
cbs[
|
|
28
|
+
cbs[identifier] && cbs[identifier][symHook] && cbs[identifier][symHook].apply(scope)
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export const registerHooks = (hooks = {},
|
|
32
|
-
cbs[
|
|
31
|
+
export const registerHooks = (hooks = {}, identifier) => {
|
|
32
|
+
cbs[identifier] = {}
|
|
33
33
|
// Combines enumerable keys and symbol properties of the 'hooks' object
|
|
34
34
|
const hookKeys = [...Object.keys(hooks), ...Object.getOwnPropertySymbols(hooks)]
|
|
35
35
|
hookKeys.forEach((hook) => {
|
|
36
|
-
if (typeof hooks[hook] === 'function') cbs[
|
|
36
|
+
if (typeof hooks[hook] === 'function') cbs[identifier][hook] = hooks[hook]
|
|
37
37
|
})
|
|
38
38
|
}
|
package/src/lib/lifecycle.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import { Log } from './log.js'
|
|
19
19
|
import { emit, privateEmit } from './hooks.js'
|
|
20
|
+
import symbols from './symbols.js'
|
|
20
21
|
|
|
21
22
|
const states = ['init', 'ready', 'focus', 'unfocus', 'destroy']
|
|
22
23
|
|
|
@@ -34,9 +35,9 @@ export default {
|
|
|
34
35
|
this.previous = this.current
|
|
35
36
|
this.current = v
|
|
36
37
|
// emit 'private' hook
|
|
37
|
-
privateEmit(v, this.component.
|
|
38
|
+
privateEmit(v, this.component[symbols.identifier], this.component)
|
|
38
39
|
// emit 'public' hook
|
|
39
|
-
emit(v, this.component.
|
|
40
|
+
emit(v, this.component[symbols.identifier], this.component)
|
|
40
41
|
}
|
|
41
42
|
},
|
|
42
43
|
}
|
|
@@ -16,10 +16,33 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
let currentEffect = null
|
|
19
|
+
|
|
20
|
+
let paused = false
|
|
21
|
+
|
|
22
|
+
export const pauseTracking = () => {
|
|
23
|
+
paused = true
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const resumeTracking = () => {
|
|
27
|
+
paused = false
|
|
28
|
+
for (let i = 0; i < trackQueue.length; i++) {
|
|
29
|
+
const item = trackQueue[i]
|
|
30
|
+
currentEffect = item.currentEffect
|
|
31
|
+
track(item.target, item.key)
|
|
32
|
+
}
|
|
33
|
+
trackQueue.length = 0
|
|
34
|
+
}
|
|
35
|
+
|
|
19
36
|
const objectMap = new WeakMap()
|
|
20
37
|
|
|
38
|
+
const trackQueue = []
|
|
39
|
+
|
|
21
40
|
export const track = (target, key) => {
|
|
22
41
|
if (currentEffect) {
|
|
42
|
+
if (paused) {
|
|
43
|
+
trackQueue.push({ target, key, currentEffect })
|
|
44
|
+
return
|
|
45
|
+
}
|
|
23
46
|
let effectsMap = objectMap.get(target)
|
|
24
47
|
if (!effectsMap) {
|
|
25
48
|
effectsMap = new Map()
|