@lightningjs/blits 0.9.3 → 0.9.5

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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ # v0.9.5
4
+
5
+ _29 mar 2024_
6
+
7
+ - Fixed cancelling of scheduled / running transitions when starting a new transition on the same prop (broke in v0.7.1).
8
+ - Added viewport relates lifecycle hooks
9
+
10
+ # v0.9.4
11
+
12
+ _28 mar 2024_
13
+
14
+ - Upgraded Lightning renderer to v0.8.0
15
+ - Fixed issue with reactivity in a forloop when initial array is empty
16
+ - Introduced new `gpuMemoryLimit` launch setting
17
+
18
+
3
19
  # v0.9.3
4
20
 
5
21
  _25 mar 2024_
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightningjs/blits",
3
- "version": "0.9.3",
3
+ "version": "0.9.5",
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.6",
48
+ "@lightningjs/renderer": "^0.8.0",
49
49
  "@lightningjs/vite-plugin-import-chunk-url": "^0.3.0",
50
50
  "execa": "^8.0.1",
51
51
  "kolorist": "^1.8.0",
@@ -113,11 +113,13 @@ declare namespace Component {
113
113
  ready?: (this: ComponentInstance) => void
114
114
  /**
115
115
  * Triggers when the Component receives focus.
116
+ *
116
117
  * This event can fire multiple times during the component's lifecycle
117
118
  */
118
119
  focus?: (this: ComponentInstance) => void
119
120
  /**
120
121
  * Triggers when the Component loses focus.
122
+ *
121
123
  * This event can fire multiple times during the component's lifecycle
122
124
  */
123
125
  unfocus?: (this: ComponentInstance) => void
@@ -130,7 +132,31 @@ declare namespace Component {
130
132
  *
131
133
  * Note: This hook will fire continuously, multiple times per second!
132
134
  */
133
- frameTick?: (this: ComponentInstance) => void
135
+ frameTick?: (this: ComponentInstance) => void,
136
+ /**
137
+ * Fires when the component enters the viewport _margin_ and is attached to the render tree
138
+ *
139
+ * This event can fire multiple times during the component's lifecycle
140
+ */
141
+ attach?: (this: ComponentInstance) => void,
142
+ /**
143
+ * Fires when the component leaves the viewport _margin_ and is detached from the render tree
144
+ *
145
+ * This event can fire multiple times during the component's lifecycle
146
+ */
147
+ detach?: (this: ComponentInstance) => void,
148
+ /**
149
+ * Fires when the component enters the visible viewport
150
+ *
151
+ * This event can fire multiple times during the component's lifecycle
152
+ */
153
+ enter?: (this: ComponentInstance) => void,
154
+ /**
155
+ * Fires when the component leaves the visible viewport
156
+ *
157
+ * This event can fire multiple times during the component's lifecycle
158
+ */
159
+ exit?: (this: ComponentInstance) => void,
134
160
  }
135
161
 
136
162
  export interface ComponentInstance {
package/src/component.js CHANGED
@@ -102,7 +102,7 @@ const Component = (name = required('name'), config = required('config')) => {
102
102
  }
103
103
 
104
104
  this.parent = parentComponent
105
- this[symbols.wrapper] = parentEl
105
+ this[symbols.holder] = parentEl
106
106
 
107
107
  Object.defineProperties(this, {
108
108
  componentId: {
@@ -163,6 +163,37 @@ const Component = (name = required('name'), config = required('config')) => {
163
163
  configurable: false,
164
164
  })
165
165
 
166
+ Object.defineProperty(this, symbols.wrapper, {
167
+ value: this[symbols.children][0],
168
+ writable: false,
169
+ enumerable: false,
170
+ configurable: false,
171
+ })
172
+
173
+ if (config.hooks && config.hooks.attach) {
174
+ this[symbols.wrapper].node.on('inBounds', () => {
175
+ this.lifecycle.state = 'attach'
176
+ })
177
+ }
178
+
179
+ if (config.hooks && config.hooks.detach) {
180
+ this[symbols.wrapper].node.on('outOfBounds', (node, { previous }) => {
181
+ if (previous > 0) this.lifecycle.state = 'detach'
182
+ })
183
+ }
184
+
185
+ if (config.hooks && config.hooks.enter) {
186
+ this[symbols.wrapper].node.on('inViewport', () => {
187
+ this.lifecycle.state = 'enter'
188
+ })
189
+ }
190
+
191
+ if (config.hooks && config.hooks.enter) {
192
+ this[symbols.wrapper].node.on('outOfViewport', () => {
193
+ this.lifecycle.state = 'exit'
194
+ })
195
+ }
196
+
166
197
  Object.defineProperty(this, symbols.slots, {
167
198
  value: this[symbols.children].filter((child) => child[symbols.isSlot]),
168
199
  writable: false,
@@ -311,11 +311,10 @@ const Element = {
311
311
  },
312
312
  animate(prop, value, transition) {
313
313
  if (this.node[prop] === value) return Promise.resolve()
314
- // check if a transition is already schedule or running on the same prop
314
+ // check if a transition is already scheduled or running on the same prop
315
315
  if (this.scheduledTransitions[prop]) {
316
- // clearTimeout(this.scheduledTransitions[prop].timeout)
317
316
  if (this.scheduledTransitions[prop].f.state === 'running') {
318
- this.scheduledTransitions[prop].f.pause()
317
+ this.scheduledTransitions[prop].f.stop()
319
318
  // fastforward to final value
320
319
  this.node[prop] = this.scheduledTransitions[prop].v
321
320
  }
@@ -348,33 +347,33 @@ const Element = {
348
347
  const startValue = this.node[prop]
349
348
  this.scheduledTransitions[prop] = {
350
349
  v: props[prop],
351
- f: () => {
352
- try {
353
- f.start()
354
- .waitUntilStarted()
355
- .then((animation) => {
356
- // fire transition start callback if specified
357
- transition.start &&
358
- typeof transition.start === 'function' &&
359
- transition.start.call(this.component, this, prop, startValue)
360
- // continue the chain
361
- animation
362
- .waitUntilStopped()
363
- .then(() => delete this.scheduledTransitions[prop])
364
- .then(() => {
365
- // fire transition end callback if specified
366
- transition.end &&
367
- typeof transition.end === 'function' &&
368
- transition.end.call(this.component, this, prop, this.node[prop])
369
- })
370
- .then(resolve)
350
+ cancel: false,
351
+ f,
352
+ }
353
+
354
+ try {
355
+ f.start()
356
+ .waitUntilStarted()
357
+ .then((animation) => {
358
+ // fire transition start callback if specified
359
+ transition.start &&
360
+ typeof transition.start === 'function' &&
361
+ transition.start.call(this.component, this, prop, startValue)
362
+ // continue the chain
363
+ animation
364
+ .waitUntilStopped()
365
+ .then(() => delete this.scheduledTransitions[prop])
366
+ .then(() => {
367
+ // fire transition end callback if specified
368
+ transition.end &&
369
+ typeof transition.end === 'function' &&
370
+ transition.end.call(this.component, this, prop, this.node[prop])
371
371
  })
372
- } catch (e) {
373
- Log.error(e)
374
- }
375
- },
372
+ .then(resolve)
373
+ })
374
+ } catch (e) {
375
+ Log.error(e)
376
376
  }
377
- this.scheduledTransitions[prop].f()
378
377
  })
379
378
  },
380
379
  destroy() {
@@ -59,6 +59,9 @@ You can remove the option from your \`src/index.js\`-file. And you can safely re
59
59
  clearColor: (settings.canvasColor && colors.normalize(settings.canvasColor)) || 0x00000000,
60
60
  enableInspector: settings.inspector || false,
61
61
  boundsMargin: settings.viewportMargin || 0,
62
+ // gpu memory limit, converted from mb to bytes - defaults to 200mb
63
+ txMemByteThreshold:
64
+ 'gpuMemoryLimit' in settings ? settings.gpuMemoryLimit * 1024 * 1024 : 200 * 1024 * 1024,
62
65
  },
63
66
  target,
64
67
  driver
package/src/launch.d.ts CHANGED
@@ -206,7 +206,17 @@ export interface Settings {
206
206
  *
207
207
  * Defaults to `0`
208
208
  */
209
- viewportMargin?: number | [number, number, number, number]
209
+ viewportMargin?: number | [number, number, number, number],
210
+ /**
211
+ * Threshold in `Megabytes` after which all the textures that are currently not visible
212
+ * within the configured viewport margin will be be freed and cleaned up
213
+ *
214
+ * When passed `0` the threshold is disabled and textures will not be actively freed
215
+ * and cleaned up
216
+ *
217
+ * Defaults to `200` (mb)
218
+ */
219
+ gpuMemoryLimit?: number
210
220
  }
211
221
 
212
222
  /**
@@ -219,6 +219,17 @@ const generateForLoopCode = function (templateObject, parent) {
219
219
  }
220
220
 
221
221
  const forCounter = counter
222
+
223
+ // reference all reactive attributes (except those referencing the iterator item),
224
+ // to ensure that reactivity is registered, even when the initial array is empty
225
+ Object.keys(templateObject).forEach((k) => {
226
+ if (isReactiveKey(k) && templateObject[k].indexOf('$' + item) === -1) {
227
+ ctx.renderCode.push(`
228
+ void ${interpolate(templateObject[k], 'component.')}
229
+ `)
230
+ }
231
+ })
232
+
222
233
  ctx.renderCode.push(`
223
234
  const collection = ${cast(result[2], ':for')} || []
224
235
  const keys = []
@@ -19,7 +19,17 @@ import { Log } from './log.js'
19
19
  import { emit, privateEmit } from './hooks.js'
20
20
  import symbols from './symbols.js'
21
21
 
22
- const states = ['init', 'ready', 'focus', 'unfocus', 'destroy']
22
+ const states = [
23
+ 'init', // fired upon component instantiation
24
+ 'ready', // fired when component instantiated, reactivity setup done and template spawned
25
+ 'focus', // fired when receiving focus (can occur multiple times)
26
+ 'unfocus', // fired when losing focus (can occur multiple times)
27
+ 'destroy', // fired when component is destroyed and removed
28
+ 'attach', // fired when entering the viewport margin and attached to the render tree
29
+ 'detach', // fired when leaving the viewport margin and detached from the render tree
30
+ 'enter', // fired when entering the visible viewport
31
+ 'exit', // fired when leaving the visible viewport
32
+ ]
23
33
 
24
34
  export default {
25
35
  previous: null,
@@ -25,7 +25,7 @@ export default (component, computeds) => {
25
25
  for (let computed in computeds) {
26
26
  // test for reserved keys?
27
27
  if (component[symbols.stateKeys] && component[symbols.stateKeys].indexOf(computed) > -1) {
28
- Log.error(`${computed} already exists as a prop`)
28
+ Log.error(`${computed} already exists as a state variable`)
29
29
  } else if (component[symbols.propKeys] && component[symbols.propKeys].indexOf(computed) > -1) {
30
30
  Log.error(`${computed} already exists as a prop`)
31
31
  } else if (
@@ -3,6 +3,7 @@ export default {
3
3
  cursorTagStart: Symbol('cursorTagStart'),
4
4
  computedKeys: Symbol('computedKeys'),
5
5
  destroy: Symbol('destroy'),
6
+ holder: Symbol('holder'),
6
7
  id: Symbol('id'),
7
8
  identifier: Symbol('identifier'),
8
9
  index: Symbol('index'),
@@ -149,7 +149,7 @@ export const navigate = async function () {
149
149
  view = view({ props }, holder, this)
150
150
  }
151
151
  } else {
152
- holder = view[symbols.wrapper]
152
+ holder = view[symbols.holder]
153
153
  }
154
154
 
155
155
  this[symbols.children].push(view)
@@ -223,11 +223,11 @@ const removeView = async (route, view, transition) => {
223
223
  if (Array.isArray(transition)) {
224
224
  for (let i = 0; i < transition.length; i++) {
225
225
  i === transition.length - 1
226
- ? await setOrAnimate(view[symbols.wrapper], transition[i])
227
- : setOrAnimate(view[symbols.wrapper], transition[i])
226
+ ? await setOrAnimate(view[symbols.holder], transition[i])
227
+ : setOrAnimate(view[symbols.holder], transition[i])
228
228
  }
229
229
  } else {
230
- await setOrAnimate(view[symbols.wrapper], transition)
230
+ await setOrAnimate(view[symbols.holder], transition)
231
231
  }
232
232
  }
233
233