@lightningjs/blits 0.9.4 → 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,12 @@
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
+
3
10
  # v0.9.4
4
11
 
5
12
  _28 mar 2024_
@@ -2,9 +2,3 @@
2
2
 
3
3
  ## Utilities
4
4
 
5
- - focus()
6
- - $router()
7
- - select()
8
- - parent
9
- - Log
10
- - setTimeout
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightningjs/blits",
3
- "version": "0.9.4",
3
+ "version": "0.9.5",
4
4
  "description": "Blits: The Lightning 3 App Development Framework",
5
5
  "bin": "bin/index.js",
6
6
  "exports": {
@@ -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() {
@@ -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,
@@ -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