@lightningjs/blits 0.9.6 → 0.9.8

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 (48) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/boilerplate/common/eslint/.eslintrc.cjs +1 -1
  3. package/boilerplate/common/git/gitignore +4 -1
  4. package/boilerplate/js/default/.env.example +4 -0
  5. package/boilerplate/js/default/src/pages/Home.js +1 -1
  6. package/boilerplate/js/default/vite.config.js +2 -0
  7. package/docs/_sidebar.md +1 -0
  8. package/docs/built-in/directives.md +11 -3
  9. package/docs/built-in/for-loop.md +172 -0
  10. package/docs/components/component_state.md +1 -2
  11. package/docs/components/computed_properties.md +3 -4
  12. package/docs/components/methods.md +3 -3
  13. package/docs/components/props.md +1 -1
  14. package/docs/components/user_input.md +2 -2
  15. package/docs/components/watchers.md +1 -1
  16. package/docs/essentials/application_root.md +1 -1
  17. package/docs/essentials/components.md +3 -3
  18. package/docs/essentials/displaying_images.md +2 -2
  19. package/docs/essentials/displaying_text.md +12 -12
  20. package/docs/essentials/element_attributes.md +19 -13
  21. package/docs/essentials/template_syntax.md +8 -8
  22. package/docs/getting_started/file_structure.md +10 -11
  23. package/docs/getting_started/intro.md +3 -3
  24. package/docs/plugins/text-to-speech-announcer.md +2 -2
  25. package/docs/sidebar.json +4 -0
  26. package/docs/transitions_animations/transitions.md +10 -10
  27. package/package.json +2 -2
  28. package/src/component.js +1 -1
  29. package/src/components/Circle.js +30 -27
  30. package/src/components/Circle.orig.js +3 -29
  31. package/src/components/FPScounter.js +1078 -1024
  32. package/src/components/FPScounter.orig.js +41 -1024
  33. package/src/components/Image.js +21 -18
  34. package/src/components/Image.orig.js +2 -20
  35. package/src/components/RouterView.js +20 -17
  36. package/src/components/RouterView.orig.js +3 -19
  37. package/src/components/Sprite.js +27 -23
  38. package/src/components/Sprite.orig.js +3 -25
  39. package/src/components/Text.js +57 -53
  40. package/src/components/Text.orig.js +21 -55
  41. package/src/engines/L3/element.js +3 -0
  42. package/src/engines/L3/launch.js +1 -0
  43. package/src/launch.d.ts +11 -1
  44. package/src/lib/reactivity/effect.js +1 -0
  45. package/src/lib/reactivity/reactive.js +10 -1
  46. package/src/lib/setup/base.js +7 -3
  47. package/src/lib/setup/state.js +1 -1
  48. package/src/router/router.js +0 -7
@@ -19,26 +19,29 @@ import Component from '../component.js'
19
19
 
20
20
  export default () =>
21
21
  Component('Image', {
22
- /* eslint-disable no-unused-vars */
23
- code: { render: function anonymous(parent,component,context
24
- ) {
25
- const elms = []
22
+ /* eslint-disable no-unused-vars */
23
+ code: {
24
+ render: function anonymous(parent, component, context) {
25
+ const elms = []
26
26
 
27
- if(!elms[0]) {
28
- elms[0] = this.element({parent: parent || 'root'}, component)
29
- }
30
- const elementConfig0 = {}
31
-
27
+ if (!elms[0]) {
28
+ elms[0] = this.element({ parent: parent || 'root' }, component)
29
+ }
30
+ const elementConfig0 = {}
31
+
32
+ if (!elms[0].nodeId) {
33
+ elms[0].populate(elementConfig0)
34
+ }
32
35
 
33
- if(!elms[0].nodeId) {
34
- elms[0].populate(elementConfig0)
35
- }
36
-
37
- return elms
38
- }, effects: [function anonymous(component,elms,context
39
- ) {
40
- elms[0].set('imageSource', component.imageSource)
41
- }], context: {}},
36
+ return elms
37
+ },
38
+ effects: [
39
+ function anonymous(component, elms, context) {
40
+ elms[0].set('imageSource', component.imageSource)
41
+ },
42
+ ],
43
+ context: {},
44
+ },
42
45
  props: ['src'],
43
46
  computed: {
44
47
  imageSource() {
@@ -19,26 +19,8 @@ import Component from '../component.js'
19
19
 
20
20
  export default () =>
21
21
  Component('Image', {
22
- /* eslint-disable no-unused-vars */
23
- code: { render: function anonymous(parent,component,context
24
- ) {
25
- const elms = []
26
-
27
- if(!elms[0]) {
28
- elms[0] = this.element({parent: parent || 'root'}, component)
29
- }
30
- const elementConfig0 = {}
31
-
32
-
33
- if(!elms[0].nodeId) {
34
- elms[0].populate(elementConfig0)
35
- }
36
-
37
- return elms
38
- }, effects: [function anonymous(component,elms,context
39
- ) {
40
- elms[0].set('imageSource', component.imageSource)
41
- }], context: {}},
22
+ template: `
23
+ <Element :imageSource="$imageSource" />`,
42
24
  props: ['src'],
43
25
  computed: {
44
26
  imageSource() {
@@ -22,25 +22,28 @@ let handler
22
22
 
23
23
  export default () =>
24
24
  Component('RouterView', {
25
- /* eslint-disable no-unused-vars */
26
- code: { render: function anonymous(parent,component,context
27
- ) {
28
- const elms = []
25
+ /* eslint-disable no-unused-vars */
26
+ code: {
27
+ render: function anonymous(parent, component, context) {
28
+ const elms = []
29
29
 
30
- if(!elms[0]) {
31
- elms[0] = this.element({parent: parent || 'root'}, component)
32
- }
33
- const elementConfig0 = {}
34
-
35
- elementConfig0['w'] = parent.node.width * (100 / 100)
36
- elementConfig0['height'] = parent.node.height * (100 / 100)
30
+ if (!elms[0]) {
31
+ elms[0] = this.element({ parent: parent || 'root' }, component)
32
+ }
33
+ const elementConfig0 = {}
37
34
 
38
- if(!elms[0].nodeId) {
39
- elms[0].populate(elementConfig0)
40
- }
41
-
42
- return elms
43
- }, effects: [], context: {}},
35
+ elementConfig0['w'] = parent.node.width * (100 / 100)
36
+ elementConfig0['height'] = parent.node.height * (100 / 100)
37
+
38
+ if (!elms[0].nodeId) {
39
+ elms[0].populate(elementConfig0)
40
+ }
41
+
42
+ return elms
43
+ },
44
+ effects: [],
45
+ context: {},
46
+ },
44
47
  state() {
45
48
  return {
46
49
  activeView: null,
@@ -22,25 +22,9 @@ let handler
22
22
 
23
23
  export default () =>
24
24
  Component('RouterView', {
25
- /* eslint-disable no-unused-vars */
26
- code: { render: function anonymous(parent,component,context
27
- ) {
28
- const elms = []
29
-
30
- if(!elms[0]) {
31
- elms[0] = this.element({parent: parent || 'root'}, component)
32
- }
33
- const elementConfig0 = {}
34
-
35
- elementConfig0['w'] = parent.node.width * (100 / 100)
36
- elementConfig0['height'] = parent.node.height * (100 / 100)
37
-
38
- if(!elms[0].nodeId) {
39
- elms[0].populate(elementConfig0)
40
- }
41
-
42
- return elms
43
- }, effects: [], context: {}},
25
+ template: `
26
+ <Element w="100%" height="100%"></Element>
27
+ `,
44
28
  state() {
45
29
  return {
46
30
  activeView: null,
@@ -21,31 +21,35 @@ import symbols from '../lib/symbols.js'
21
21
 
22
22
  export default () =>
23
23
  Component('Sprite', {
24
- /* eslint-disable no-unused-vars */
25
- code: { render: function anonymous(parent,component,context
26
- ) {
27
- const elms = []
24
+ /* eslint-disable no-unused-vars */
25
+ code: {
26
+ render: function anonymous(parent, component, context) {
27
+ const elms = []
28
28
 
29
- if(!elms[0]) {
30
- elms[0] = this.element({parent: parent || 'root'}, component)
31
- }
32
- const elementConfig0 = {}
33
-
34
- elementConfig0['w'] = parent.node.width * (100 / 100)
35
- elementConfig0['h'] = parent.node.height * (100 / 100)
29
+ if (!elms[0]) {
30
+ elms[0] = this.element({ parent: parent || 'root' }, component)
31
+ }
32
+ const elementConfig0 = {}
33
+
34
+ elementConfig0['w'] = parent.node.width * (100 / 100)
35
+ elementConfig0['h'] = parent.node.height * (100 / 100)
36
+
37
+ if (!elms[0].nodeId) {
38
+ elms[0].populate(elementConfig0)
39
+ }
36
40
 
37
- if(!elms[0].nodeId) {
38
- elms[0].populate(elementConfig0)
39
- }
40
-
41
- return elms
42
- }, effects: [function anonymous(component,elms,context
43
- ) {
44
- elms[0].set('texture', component.texture)
45
- },function anonymous(component,elms,context
46
- ) {
47
- elms[0].set('color', component.color)
48
- }], context: {}},
41
+ return elms
42
+ },
43
+ effects: [
44
+ function anonymous(component, elms, context) {
45
+ elms[0].set('texture', component.texture)
46
+ },
47
+ function anonymous(component, elms, context) {
48
+ elms[0].set('color', component.color)
49
+ },
50
+ ],
51
+ context: {},
52
+ },
49
53
  props: ['image', 'map', 'frame', 'color'],
50
54
  state() {
51
55
  return {
@@ -21,31 +21,9 @@ import symbols from '../lib/symbols.js'
21
21
 
22
22
  export default () =>
23
23
  Component('Sprite', {
24
- /* eslint-disable no-unused-vars */
25
- code: { render: function anonymous(parent,component,context
26
- ) {
27
- const elms = []
28
-
29
- if(!elms[0]) {
30
- elms[0] = this.element({parent: parent || 'root'}, component)
31
- }
32
- const elementConfig0 = {}
33
-
34
- elementConfig0['w'] = parent.node.width * (100 / 100)
35
- elementConfig0['h'] = parent.node.height * (100 / 100)
36
-
37
- if(!elms[0].nodeId) {
38
- elms[0].populate(elementConfig0)
39
- }
40
-
41
- return elms
42
- }, effects: [function anonymous(component,elms,context
43
- ) {
44
- elms[0].set('texture', component.texture)
45
- },function anonymous(component,elms,context
46
- ) {
47
- elms[0].set('color', component.color)
48
- }], context: {}},
24
+ template: `
25
+ <Element w="100%" h="100%" :texture="$texture" :color="$color" />
26
+ `,
49
27
  props: ['image', 'map', 'frame', 'color'],
50
28
  state() {
51
29
  return {
@@ -20,61 +20,65 @@ import Settings from '../settings.js'
20
20
 
21
21
  export default () =>
22
22
  Component('Text', {
23
- /* eslint-disable no-unused-vars */
24
- code: { render: function anonymous(parent,component,context
25
- ) {
26
- const elms = []
23
+ /* eslint-disable no-unused-vars */
24
+ code: {
25
+ render: function anonymous(parent, component, context) {
26
+ const elms = []
27
27
 
28
- if(!elms[0]) {
29
- elms[0] = this.element({parent: parent || 'root'}, component)
30
- }
31
- const elementConfig0 = {}
32
-
33
- elementConfig0['__textnode'] = true
34
- elementConfig0['fontFamily'] = component.font
35
- elementConfig0['letterSpacing'] = component.letterspacing
36
- elementConfig0['lineHeight'] = component._lineheight
37
- elementConfig0['stretch'] = component.stretch
38
- elementConfig0['contain'] = component._contain
39
- elementConfig0['@loaded'] = component['@loaded'] && component['@loaded'].bind(component)
40
- elementConfig0['@error'] = component['@error'] && component['@error'].bind(component)
28
+ if (!elms[0]) {
29
+ elms[0] = this.element({ parent: parent || 'root' }, component)
30
+ }
31
+ const elementConfig0 = {}
41
32
 
42
- if(!elms[0].nodeId) {
43
- elms[0].populate(elementConfig0)
44
- }
45
-
46
- return elms
47
- }, effects: [function anonymous(component,elms,context
48
- ) {
49
- elms[0].set('text', component.content)
50
- },function anonymous(component,elms,context
51
- ) {
52
- elms[0].set('fontSize', component.size)
53
- },function anonymous(component,elms,context
54
- ) {
55
- elms[0].set('color', component.color)
56
- },function anonymous(component,elms,context
57
- ) {
58
- elms[0].set('style', component.style)
59
- },function anonymous(component,elms,context
60
- ) {
61
- elms[0].set('weight', component.weight)
62
- },function anonymous(component,elms,context
63
- ) {
64
- elms[0].set('wordWrap', component.wordwrap)
65
- },function anonymous(component,elms,context
66
- ) {
67
- elms[0].set('maxLines', component.maxlines)
68
- },function anonymous(component,elms,context
69
- ) {
70
- elms[0].set('h', component.maxheight)
71
- },function anonymous(component,elms,context
72
- ) {
73
- elms[0].set('textAlign', component.align)
74
- },function anonymous(component,elms,context
75
- ) {
76
- elms[0].set('overflowSuffix', component.textoverflow)
77
- }], context: {}},
33
+ elementConfig0['__textnode'] = true
34
+ elementConfig0['fontFamily'] = component.font
35
+ elementConfig0['letterSpacing'] = component.letterspacing
36
+ elementConfig0['lineHeight'] = component._lineheight
37
+ elementConfig0['stretch'] = component.stretch
38
+ elementConfig0['contain'] = component._contain
39
+ elementConfig0['@loaded'] = component['@loaded'] && component['@loaded'].bind(component)
40
+ elementConfig0['@error'] = component['@error'] && component['@error'].bind(component)
41
+
42
+ if (!elms[0].nodeId) {
43
+ elms[0].populate(elementConfig0)
44
+ }
45
+
46
+ return elms
47
+ },
48
+ effects: [
49
+ function anonymous(component, elms, context) {
50
+ elms[0].set('text', component.content)
51
+ },
52
+ function anonymous(component, elms, context) {
53
+ elms[0].set('fontSize', component.size)
54
+ },
55
+ function anonymous(component, elms, context) {
56
+ elms[0].set('color', component.color)
57
+ },
58
+ function anonymous(component, elms, context) {
59
+ elms[0].set('style', component.style)
60
+ },
61
+ function anonymous(component, elms, context) {
62
+ elms[0].set('weight', component.weight)
63
+ },
64
+ function anonymous(component, elms, context) {
65
+ elms[0].set('wordWrap', component.wordwrap)
66
+ },
67
+ function anonymous(component, elms, context) {
68
+ elms[0].set('maxLines', component.maxlines)
69
+ },
70
+ function anonymous(component, elms, context) {
71
+ elms[0].set('h', component.maxheight)
72
+ },
73
+ function anonymous(component, elms, context) {
74
+ elms[0].set('textAlign', component.align)
75
+ },
76
+ function anonymous(component, elms, context) {
77
+ elms[0].set('overflowSuffix', component.textoverflow)
78
+ },
79
+ ],
80
+ context: {},
81
+ },
78
82
  props: [
79
83
  'content',
80
84
  {
@@ -20,61 +20,27 @@ import Settings from '../settings.js'
20
20
 
21
21
  export default () =>
22
22
  Component('Text', {
23
- /* eslint-disable no-unused-vars */
24
- code: { render: function anonymous(parent,component,context
25
- ) {
26
- const elms = []
27
-
28
- if(!elms[0]) {
29
- elms[0] = this.element({parent: parent || 'root'}, component)
30
- }
31
- const elementConfig0 = {}
32
-
33
- elementConfig0['__textnode'] = true
34
- elementConfig0['fontFamily'] = component.font
35
- elementConfig0['letterSpacing'] = component.letterspacing
36
- elementConfig0['lineHeight'] = component._lineheight
37
- elementConfig0['stretch'] = component.stretch
38
- elementConfig0['contain'] = component._contain
39
- elementConfig0['@loaded'] = component['@loaded'] && component['@loaded'].bind(component)
40
- elementConfig0['@error'] = component['@error'] && component['@error'].bind(component)
41
-
42
- if(!elms[0].nodeId) {
43
- elms[0].populate(elementConfig0)
44
- }
45
-
46
- return elms
47
- }, effects: [function anonymous(component,elms,context
48
- ) {
49
- elms[0].set('text', component.content)
50
- },function anonymous(component,elms,context
51
- ) {
52
- elms[0].set('fontSize', component.size)
53
- },function anonymous(component,elms,context
54
- ) {
55
- elms[0].set('color', component.color)
56
- },function anonymous(component,elms,context
57
- ) {
58
- elms[0].set('style', component.style)
59
- },function anonymous(component,elms,context
60
- ) {
61
- elms[0].set('weight', component.weight)
62
- },function anonymous(component,elms,context
63
- ) {
64
- elms[0].set('wordWrap', component.wordwrap)
65
- },function anonymous(component,elms,context
66
- ) {
67
- elms[0].set('maxLines', component.maxlines)
68
- },function anonymous(component,elms,context
69
- ) {
70
- elms[0].set('h', component.maxheight)
71
- },function anonymous(component,elms,context
72
- ) {
73
- elms[0].set('textAlign', component.align)
74
- },function anonymous(component,elms,context
75
- ) {
76
- elms[0].set('overflowSuffix', component.textoverflow)
77
- }], context: {}},
23
+ template: `
24
+ <Element
25
+ __textnode="true"
26
+ :text="$content"
27
+ fontFamily="$font"
28
+ :fontSize="$size"
29
+ :color="$color"
30
+ :style="$style"
31
+ :weight="$weight"
32
+ letterSpacing="$letterspacing"
33
+ lineHeight="$_lineheight"
34
+ stretch="$stretch"
35
+ contain="$_contain"
36
+ :wordWrap="$wordwrap"
37
+ :maxLines="$maxlines"
38
+ :h="$maxheight"
39
+ :textAlign="$align"
40
+ :overflowSuffix="$textoverflow"
41
+ @loaded="$@loaded"
42
+ @error="$@error"
43
+ />`,
78
44
  props: [
79
45
  'content',
80
46
  {
@@ -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
  },
@@ -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
  /**
@@ -58,6 +58,7 @@ export const track = (target, key) => {
58
58
  }
59
59
 
60
60
  export const trigger = (target, key, force = false) => {
61
+ if (paused) return
61
62
  const effectsMap = objectMap.get(target)
62
63
  if (!effectsMap) {
63
64
  return
@@ -32,6 +32,11 @@ const getRaw = (value) => {
32
32
  }
33
33
 
34
34
  const reactiveProxy = (original, _parent = null, _key) => {
35
+ // don't create a proxy when a Blits component is assigned to a state variable
36
+ if (typeof original === 'object' && original[symbols.id]) {
37
+ return original
38
+ }
39
+
35
40
  // if original object is already a proxy, don't create a new one but return the existing one instead
36
41
  const existingProxy = getProxy(original)
37
42
  if (existingProxy) {
@@ -89,7 +94,11 @@ const reactiveProxy = (original, _parent = null, _key) => {
89
94
  result = Reflect.set(target, key, value, receiver)
90
95
  }
91
96
 
92
- if (result && oldRawValue !== value) {
97
+ if (result && oldRawValue !== rawValue) {
98
+ // if we're assigning an array key directly trigger reactivity on the parent key as well
99
+ if (Array.isArray(target) && key in target) {
100
+ trigger(_parent, _key, true)
101
+ }
93
102
  trigger(target, key, true)
94
103
  }
95
104
  return result
@@ -272,11 +272,15 @@ export default (component, name) => {
272
272
  const deleteChildren = function (children) {
273
273
  for (let i = 0; i < children.length; i++) {
274
274
  if (!children[i]) return
275
- if (Array.isArray(children[i])) {
276
- deleteChildren(children[i])
277
- } else if (children[i].destroy) {
275
+ // call destroy when method is available on child
276
+ if (children[i].destroy && typeof children[i].destroy === 'function') {
278
277
  children[i].destroy()
279
278
  }
279
+ // recursively call deleteChildren when it's an object of items (happens when using a forloop construct)
280
+ else if (Object.getPrototypeOf(children[i]) === Object.prototype) {
281
+ deleteChildren(Object.values(children[i]))
282
+ }
283
+
280
284
  children[i] = null
281
285
  }
282
286
 
@@ -19,7 +19,7 @@ import { Log } from '../log.js'
19
19
 
20
20
  import symbols from '../symbols.js'
21
21
 
22
- export default (component, state) => {
22
+ export default (component, state = () => {}) => {
23
23
  component[symbols.stateKeys] = []
24
24
 
25
25
  state = { ...state.apply(component.prototype), ...{ hasFocus: false } }
@@ -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
  }