@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.
Files changed (57) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/docs/_sidebar.md +1 -0
  3. package/docs/built-in/directives.md +11 -3
  4. package/docs/built-in/for-loop.md +172 -0
  5. package/docs/components/component_state.md +1 -2
  6. package/docs/components/computed_properties.md +3 -4
  7. package/docs/components/methods.md +3 -3
  8. package/docs/components/props.md +1 -1
  9. package/docs/components/user_input.md +2 -2
  10. package/docs/components/watchers.md +1 -1
  11. package/docs/essentials/application_root.md +1 -1
  12. package/docs/essentials/components.md +3 -3
  13. package/docs/essentials/displaying_images.md +2 -2
  14. package/docs/essentials/displaying_text.md +12 -12
  15. package/docs/essentials/element_attributes.md +19 -13
  16. package/docs/essentials/template_syntax.md +8 -8
  17. package/docs/getting_started/file_structure.md +10 -11
  18. package/docs/getting_started/intro.md +3 -3
  19. package/docs/plugins/text-to-speech-announcer.md +2 -2
  20. package/docs/sidebar.json +4 -0
  21. package/docs/transitions_animations/transitions.md +12 -12
  22. package/package.json +2 -2
  23. package/src/application.d.ts +10 -10
  24. package/src/component/base/announcer.js +27 -0
  25. package/src/component/base/events.js +37 -0
  26. package/src/component/base/index.js +29 -0
  27. package/src/component/base/log.js +27 -0
  28. package/src/component/base/methods.js +136 -0
  29. package/src/component/base/router.js +40 -0
  30. package/src/component/base/timeouts_intervals.js +92 -0
  31. package/src/component/base/utils.js +29 -0
  32. package/src/{lib → component}/setup/computed.js +3 -3
  33. package/src/component/setup/index.js +61 -0
  34. package/src/{lib → component}/setup/input.js +4 -4
  35. package/src/{lib → component}/setup/methods.js +3 -3
  36. package/src/{lib → component}/setup/props.js +3 -3
  37. package/src/{lib → component}/setup/routes.js +3 -3
  38. package/src/{lib → component}/setup/state.js +13 -6
  39. package/src/{lib → component}/setup/watch.js +5 -5
  40. package/src/component.d.ts +157 -38
  41. package/src/component.js +145 -154
  42. package/src/components/Circle.js +5 -5
  43. package/src/components/FPScounter.js +57 -89
  44. package/src/components/Image.js +2 -2
  45. package/src/components/RouterView.js +1 -1
  46. package/src/components/Sprite.js +5 -5
  47. package/src/components/Sprite.orig.js +2 -2
  48. package/src/components/Text.js +11 -11
  49. package/src/components/index.js +32 -0
  50. package/src/components/index.orig.js +32 -0
  51. package/src/engines/L3/element.js +44 -35
  52. package/src/engines/L3/launch.js +2 -1
  53. package/src/launch.d.ts +11 -1
  54. package/src/lib/codegenerator/generator.js +7 -6
  55. package/src/router/router.js +0 -7
  56. package/src/lib/setup/base.js +0 -284
  57. /package/src/{lib → component}/setup/props.test.js +0 -0
@@ -210,6 +210,9 @@ const Props = {
210
210
  set clipping(v) {
211
211
  this._props.clipping = v
212
212
  },
213
+ set overflow(v) {
214
+ this._props.clipping = !!!v
215
+ },
213
216
  set fontFamily(v) {
214
217
  this._props.fontFamily = v
215
218
  },
@@ -237,6 +240,10 @@ const Props = {
237
240
  set textAlign(v) {
238
241
  this._props.textAlign = v
239
242
  },
243
+ set rtt(v) {
244
+ this._props.rtt = v
245
+ this._set.add('rtt')
246
+ },
240
247
  }
241
248
 
242
249
  const Element = {
@@ -268,9 +275,12 @@ const Element = {
268
275
  // correct for default white nodes (but not for text nodes)
269
276
  if (!props.__textnode && !this.props._set.has('color')) {
270
277
  this.props._props.color =
271
- this.props._set.has('src') || this.props._set.has('texture') ? 0xffffffff : 0
278
+ this.props._set.has('src') ||
279
+ this.props._set.has('texture') ||
280
+ (this.props._set.has('rtt') && this.props._props.rtt === true)
281
+ ? 0xffffffff
282
+ : 0
272
283
  }
273
-
274
284
  this.node = props.__textnode
275
285
  ? renderer.createTextNode(this.props._props)
276
286
  : renderer.createNode(this.props._props)
@@ -309,7 +319,8 @@ const Element = {
309
319
  }
310
320
  }
311
321
  },
312
- animate(prop, value, transition) {
322
+ async animate(prop, value, transition) {
323
+ // if current value is the same as the value to animate to, instantly resolve
313
324
  if (this.node[prop] === value) return Promise.resolve()
314
325
  // check if a transition is already scheduled or running on the same prop
315
326
  if (this.scheduledTransitions[prop]) {
@@ -342,39 +353,37 @@ const Element = {
342
353
  delay: typeof transition === 'object' ? ('delay' in transition ? transition.delay : 0) : 0,
343
354
  })
344
355
 
345
- // schedule transition
346
- return new Promise((resolve) => {
347
- const startValue = this.node[prop]
348
- this.scheduledTransitions[prop] = {
349
- v: props[prop],
350
- cancel: false,
351
- f,
352
- }
356
+ // capture the current value to be used in the transition start
357
+ const startValue = this.node[prop]
353
358
 
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
- })
372
- .then(resolve)
373
- })
374
- } catch (e) {
375
- Log.error(e)
376
- }
377
- })
359
+ // schedule the transition for this prop, so it can be canceled /
360
+ // removed if another transition for the same prop starts in the mean time
361
+ this.scheduledTransitions[prop] = {
362
+ v: props[prop],
363
+ cancel: false,
364
+ f,
365
+ }
366
+
367
+ // wait until the animation really starts (depending on specified delay)
368
+ const animation = await f.start().waitUntilStarted()
369
+
370
+ // fire transition start callback if specified
371
+ transition.start &&
372
+ typeof transition.start === 'function' &&
373
+ transition.start.call(this.component, this, prop, startValue)
374
+
375
+ // wait until the animation ends
376
+ const finished = await animation.waitUntilStopped()
377
+
378
+ // removed the prop from scheduled transitions
379
+ delete this.scheduledTransitions[prop]
380
+
381
+ // fire transition end callback if specified
382
+ transition.end &&
383
+ typeof transition.end === 'function' &&
384
+ transition.end.call(this.component, this, prop, this.node[prop])
385
+
386
+ return Promise.resolve()
378
387
  },
379
388
  destroy() {
380
389
  Log.debug('Deleting Node', this.nodeId)
@@ -24,7 +24,7 @@ import fontLoader from './fontLoader.js'
24
24
 
25
25
  export let renderer
26
26
 
27
- export default (App, target, settings) => {
27
+ export default (App, target, settings = {}) => {
28
28
  const driver = new MainCoreDriver()
29
29
  // settings.multithreaded === true
30
30
  // ? new ThreadXRenderDriver({
@@ -62,6 +62,7 @@ You can remove the option from your \`src/index.js\`-file. And you can safely re
62
62
  // gpu memory limit, converted from mb to bytes - defaults to 200mb
63
63
  txMemByteThreshold:
64
64
  'gpuMemoryLimit' in settings ? settings.gpuMemoryLimit * 1024 * 1024 : 200 * 1024 * 1024,
65
+ renderMode: 'renderMode' in settings ? settings.renderMode : 'webgl',
65
66
  },
66
67
  target,
67
68
  driver
package/src/launch.d.ts CHANGED
@@ -69,6 +69,7 @@ type Font = WebFont | SdfFont
69
69
  export type DebugLevel = 0 | 1 | 2
70
70
  export type LogTypes = 'info' | 'warn' | 'error' | 'debug'
71
71
  export type ReactivityModes = 'Proxy' | 'defineProperty'
72
+ export type RenderModes = 'webgl' | 'canvas'
72
73
 
73
74
  interface ExtensionLoader {
74
75
  async (stage: Stage): void
@@ -216,7 +217,16 @@ export interface Settings {
216
217
  *
217
218
  * Defaults to `200` (mb)
218
219
  */
219
- gpuMemoryLimit?: number
220
+ gpuMemoryLimit?: number,
221
+ /**
222
+ * Defines which mode the renderer should operate in: `webgl` or `canvas`
223
+ *
224
+ * SDF fonts are not supported in _canvas_ renderMode. Instead, _web_ fonts should
225
+ * be used. Also note that Canvas2d rendering doesnt support the use of shaders.
226
+ *
227
+ * Defaults to `webgl`
228
+ */
229
+ renderMode?: RenderModes
220
230
  }
221
231
 
222
232
  /**
@@ -29,8 +29,10 @@ export default function (templateObject = { children: [] }) {
29
29
  ctx.renderCode.push('return elms')
30
30
 
31
31
  return {
32
- render: new Function('parent', 'component', 'context', ctx.renderCode.join('\n')),
33
- effects: ctx.effectsCode.map((code) => new Function('component', 'elms', 'context', code)),
32
+ render: new Function('parent', 'component', 'context', 'components', ctx.renderCode.join('\n')),
33
+ effects: ctx.effectsCode.map(
34
+ (code) => new Function('component', 'elms', 'context', 'components', code)
35
+ ),
34
36
  context: ctx.context,
35
37
  }
36
38
  }
@@ -119,8 +121,7 @@ const generateComponentCode = function (
119
121
  const cmp${counter} =
120
122
  (context.components && context.components['${
121
123
  templateObject[Symbol.for('componentType')]
122
- }']) ||
123
- component[Symbol.for('components')]['${templateObject[Symbol.for('componentType')]}']
124
+ }']) || components['${templateObject[Symbol.for('componentType')]}']
124
125
  `)
125
126
 
126
127
  if ('key' in templateObject) {
@@ -174,7 +175,7 @@ const generateComponentCode = function (
174
175
  templateObject[Symbol.for('componentType')]
175
176
  }'
176
177
 
177
- ${elm} = (context.components && context.components[componentType] || component[Symbol.for('components')][componentType] || (() => { console.error('component ${
178
+ ${elm} = (context.components && context.components[componentType] || components[componentType] || (() => { console.error('component ${
178
179
  templateObject[Symbol.for('componentType')]
179
180
  } not found')})).call(null, {props: props${counter}}, ${parent}, component)
180
181
  if (${elm}[Symbol.for('slots')][0]) {
@@ -215,7 +216,7 @@ const generateForLoopCode = function (templateObject, parent) {
215
216
  }
216
217
 
217
218
  if (parent) {
218
- ctx.renderCode.push(`parent = ${parent}`)
219
+ ctx.renderCode.push(`let parent = ${parent}`)
219
220
  }
220
221
 
221
222
  const forStartCounter = counter
@@ -253,13 +253,6 @@ const removeView = async (route, view, transition) => {
253
253
  if (route.options && route.options.keepAlive === true) {
254
254
  cacheMap.set(route, { view: view, focus: previousFocus })
255
255
  } else {
256
- // remove and cleanup
257
- for (let i = 0; i < view[symbols.children].length; i++) {
258
- // if (view[symbols.children][i] && view[symbols.children][i].destroy) {
259
- // view[symbols.children][i].destroy()
260
- view[symbols.children][i] = null
261
- // }
262
- }
263
256
  view.destroy()
264
257
  view = null
265
258
  }
@@ -1,284 +0,0 @@
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 Focus from '../../focus.js'
20
- import { to, currentRoute, navigating, back } from '../../router/router.js'
21
- import Image from '../../components/Image.js'
22
- import Circle from '../../components/Circle.js'
23
- import RouterView from '../../components/RouterView.js'
24
- import Sprite from '../../components/Sprite.js'
25
- import Text from '../../components/Text.js'
26
- import FPScounter from '../../components/FPScounter.js'
27
- import eventListeners from '../eventListeners.js'
28
- import { default as log, Log } from '../log.js'
29
- import symbols from '../symbols.js'
30
-
31
- import { trigger } from '../reactivity/effect.js'
32
- import Announcer from '../../announcer/announcer.js'
33
-
34
- const shaderAlias = {
35
- rounded: 'radius',
36
- }
37
-
38
- export default (component, name) => {
39
- Object.defineProperties(component.prototype, {
40
- name: {
41
- value: name,
42
- writable: false,
43
- enumerable: true,
44
- configurable: false,
45
- },
46
- [symbols.identifier]: {
47
- value: component[symbols.identifier],
48
- writable: false,
49
- enumerable: false,
50
- configurable: false,
51
- },
52
- focus: {
53
- value: function (e) {
54
- this[symbols.state].hasFocus = true
55
- Focus.set(this, e)
56
- },
57
- writable: false,
58
- enumerable: true,
59
- configurable: false,
60
- },
61
- unfocus: {
62
- value: function () {
63
- this[symbols.state].hasFocus = false
64
- this.lifecycle.state = 'unfocus'
65
- },
66
- writable: false,
67
- enumerable: true,
68
- configurable: false,
69
- },
70
- destroy: {
71
- value: function () {
72
- this.lifecycle.state = 'destroy'
73
- this.$clearTimeouts()
74
- this.$clearIntervals()
75
- eventListeners.removeListeners(this)
76
- deleteChildren(this[symbols.children])
77
- Log.debug(`Destroyed component ${this.componentId}`)
78
- },
79
- writable: false,
80
- enumerable: true,
81
- configurable: false,
82
- },
83
- select: {
84
- value: function (ref) {
85
- let selected = null
86
- this[symbols.children].forEach((child) => {
87
- if (Array.isArray(child)) {
88
- child.forEach((c) => {
89
- if (c['ref'] === ref) selected = c
90
- })
91
- } else if (Object.getPrototypeOf(child) === Object.prototype) {
92
- Object.keys(child).forEach((k) => {
93
- if (child[k]['ref'] === ref) selected = child[k]
94
- })
95
- } else {
96
- if (child['ref'] === ref) selected = child
97
- }
98
- })
99
-
100
- return selected
101
- },
102
- writable: false,
103
- enumerable: true,
104
- configurable: false,
105
- },
106
- shader: {
107
- value: function (type, args) {
108
- const target = shaderAlias[type] || type
109
- const shaders = renderer.driver.stage.shManager.getRegisteredEffects()
110
-
111
- if (target in shaders) {
112
- return {
113
- type: target,
114
- props: args,
115
- }
116
- } else {
117
- Log.error(`Shader ${type} not found`)
118
- }
119
- },
120
- writable: false,
121
- enumerable: false,
122
- configurable: false,
123
- },
124
- $router: {
125
- value: {
126
- to,
127
- back,
128
- get currentRoute() {
129
- return currentRoute
130
- },
131
- get routes() {
132
- return component.prototype[symbols.routes]
133
- },
134
- get navigating() {
135
- return navigating
136
- },
137
- },
138
- writable: false,
139
- enumerable: true,
140
- configurable: false,
141
- },
142
- [symbols.components]: {
143
- value: {
144
- Image: Image(),
145
- Circle: Circle(),
146
- RouterView: RouterView(),
147
- Sprite: Sprite(),
148
- Text: Text(),
149
- FPScounter: FPScounter(),
150
- },
151
- writable: false,
152
- enumerable: false,
153
- configurable: false,
154
- },
155
- $setTimeout: {
156
- value: function (fn, ms, ...params) {
157
- const timeoutId = setTimeout(
158
- () => {
159
- this[symbols.timeouts] = this[symbols.timeouts].filter((id) => id !== timeoutId)
160
- fn.apply(null, params)
161
- },
162
- ms,
163
- params
164
- )
165
- this[symbols.timeouts].push(timeoutId)
166
- return timeoutId
167
- },
168
- writable: false,
169
- enumerable: true,
170
- configurable: false,
171
- },
172
- $clearTimeout: {
173
- value: function (timeoutId) {
174
- if (this[symbols.timeouts].indexOf(timeoutId) > -1) {
175
- this[symbols.timeouts] = this[symbols.timeouts].filter((id) => id !== timeoutId)
176
- clearTimeout(timeoutId)
177
- }
178
- },
179
- writable: false,
180
- enumerable: true,
181
- configurable: false,
182
- },
183
- $clearTimeouts: {
184
- value: function () {
185
- for (let i = 0; i < this[symbols.timeouts].length; i++) {
186
- clearTimeout(this[symbols.timeouts][i])
187
- }
188
- this[symbols.timeouts] = []
189
- },
190
- writable: false,
191
- enumerable: true,
192
- configurable: false,
193
- },
194
- $setInterval: {
195
- value: function (fn, ms, ...params) {
196
- const intervalId = setInterval(() => fn.apply(null, params), ms, params)
197
- this[symbols.intervals].push(intervalId)
198
- return intervalId
199
- },
200
- writable: false,
201
- enumerable: true,
202
- configurable: false,
203
- },
204
- $clearInterval: {
205
- value: function (intervalId) {
206
- if (this[symbols.intervals].indexOf(intervalId) > -1) {
207
- this[symbols.intervals] = this[symbols.intervals].filter((id) => id !== intervalId)
208
- clearInterval(intervalId)
209
- }
210
- },
211
- writable: false,
212
- enumerable: true,
213
- configurable: false,
214
- },
215
- $clearIntervals: {
216
- value: function () {
217
- for (let i = 0; i < this[symbols.intervals].length; i++) {
218
- clearInterval(this[symbols.intervals][i])
219
- }
220
- this[symbols.intervals] = []
221
- },
222
- writable: false,
223
- enumerable: true,
224
- configurable: false,
225
- },
226
- $emit: {
227
- value: function (event, params) {
228
- eventListeners.executeListeners(event, params)
229
- },
230
- writable: false,
231
- enumerable: true,
232
- configurable: false,
233
- },
234
- $listen: {
235
- value: function (event, callback) {
236
- eventListeners.registerListener(this, event, callback)
237
- },
238
- writable: false,
239
- enumerable: true,
240
- configurable: false,
241
- },
242
- [symbols.renderer]: {
243
- value: renderer,
244
- writable: false,
245
- enumerable: false,
246
- configurable: false,
247
- },
248
- $log: {
249
- value: log('App'),
250
- writable: false,
251
- enumerable: false,
252
- configurable: false,
253
- },
254
- $trigger: {
255
- value: function (key) {
256
- // trigger with force set to true
257
- trigger(this[symbols.originalState], key, true)
258
- },
259
- writable: false,
260
- enumerable: false,
261
- configurable: false,
262
- },
263
- $announcer: {
264
- value: Announcer,
265
- writable: false,
266
- enumerable: false,
267
- configurable: false,
268
- },
269
- })
270
- }
271
-
272
- const deleteChildren = function (children) {
273
- for (let i = 0; i < children.length; i++) {
274
- if (!children[i]) return
275
- if (Array.isArray(children[i])) {
276
- deleteChildren(children[i])
277
- } else if (children[i].destroy) {
278
- children[i].destroy()
279
- }
280
- children[i] = null
281
- }
282
-
283
- children.length = 0
284
- }
File without changes