@lightningjs/blits 0.10.0 → 1.1.0

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 +23 -0
  2. package/boilerplate/js/default/src/index.js +1 -0
  3. package/docs/essentials/displaying_text.md +1 -1
  4. package/package.json +5 -5
  5. package/src/application.js +2 -1
  6. package/src/component/base/events.js +1 -1
  7. package/src/component/base/utils.js +34 -1
  8. package/src/component/setup/props.js +3 -1
  9. package/src/component/setup/props.test.js +51 -19
  10. package/src/component.d.ts +2 -1
  11. package/src/component.js +20 -13
  12. package/src/component.test.js +340 -4
  13. package/src/components/Circle.js +13 -12
  14. package/src/components/FPScounter.js +388 -536
  15. package/src/components/Image.js +7 -9
  16. package/src/components/Layout.js +49 -0
  17. package/src/components/Layout.orig.js +34 -0
  18. package/src/components/RouterView.js +6 -10
  19. package/src/components/Sprite.js +10 -12
  20. package/src/components/index.js +2 -2
  21. package/src/components/index.orig.js +2 -2
  22. package/src/constants.js +14 -0
  23. package/src/engine.js +1 -1
  24. package/src/engines/L3/element.js +193 -180
  25. package/src/engines/L3/element.test.js +170 -0
  26. package/src/engines/L3/fontLoader.js +4 -5
  27. package/src/engines/L3/index.js +2 -2
  28. package/src/engines/L3/launch.js +10 -16
  29. package/src/engines/L3/shaderLoader.js +12 -0
  30. package/src/engines/index.js +1 -1
  31. package/src/focus.js +3 -2
  32. package/src/launch.d.ts +31 -3
  33. package/src/launch.js +1 -1
  34. package/src/lib/codegenerator/generator.js +212 -84
  35. package/src/lib/codegenerator/generator.test.js +657 -942
  36. package/src/lib/colors/colors.js +59 -46
  37. package/src/lib/componentId.js +9 -0
  38. package/src/lib/componentId.test.js +2 -1
  39. package/src/lib/precompiler/precompiler.js +3 -4
  40. package/src/lib/reactivity/effect.js +10 -13
  41. package/src/lib/reactivity/reactive.js +24 -14
  42. package/src/lib/symbols.js +1 -0
  43. package/src/router/router.js +17 -3
  44. package/vite/index.js +1 -4
  45. package/vite/preCompiler.js +3 -1
  46. package/boilerplate/js/default/src/renderer.js +0 -4
  47. package/src/components/Text.js +0 -119
  48. package/src/components/Text.orig.js +0 -81
@@ -15,64 +15,77 @@
15
15
  * SPDX-License-Identifier: Apache-2.0
16
16
  */
17
17
 
18
- import htmlColors from './htmlColors.js'
19
- import { Log } from '../log.js'
18
+ import colorsMap from './htmlColors.js'
19
+
20
+ const hex = /^#?([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i
21
+ const rgba =
22
+ /^(rgba?)\((\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\s*),(\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\s*),(\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\s*)(,(\s*(-?\d+(?:\.\d+)?)\s*))?\)$/
23
+ const hsla =
24
+ /^(hsla?)\((\s*(360|3[0-5][0-9]|[12]?[0-9]{1,2})\s*),(\s*(100|[1-9]?[0-9])\s*)%,(\s*(100|[1-9]?[0-9])\s*)%(,(\s*(1|0(?:\.\d+)?)\s*))?\)$/
25
+
26
+ const hexLookup = {}
27
+
28
+ const decimalToHex = (decimal) => {
29
+ if (hexLookup[decimal] !== undefined) {
30
+ return hexLookup[decimal]
31
+ }
32
+
33
+ const resp = parseInt(decimal).toString(16).padStart(2, '0')
34
+ hexLookup[decimal] = resp
35
+ return resp
36
+ }
20
37
 
21
38
  export default {
22
- // The defaultColor parameter should be set to null when utilizing this function within the template parser.
23
- // Because the template parser evaluates attribute values, even if they are not color codes,
24
- // to determine whether they represent color values or not.
25
- normalize(color = '', defaultColor = '0xffffffff') {
39
+ normalize: (color = '', defaultColor = '0xffffffff') => {
26
40
  color = color.toString()
27
41
 
28
- if (color.length > 0) {
29
- const normalized = /^0x[0-9a-f]{8}$/
30
- const hex = /^#?([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i
31
- const rgba =
32
- /^(rgba?)\((\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\s*),(\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\s*),(\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\s*)(,(\s*(-?\d+(?:\.\d+)?)\s*))?\)$/
33
- const hsla =
34
- /^(hsla?)\((\s*(360|3[0-5][0-9]|[12]?[0-9]{1,2})\s*),(\s*(100|[1-9]?[0-9])\s*)%,(\s*(100|[1-9]?[0-9])\s*)%(,(\s*(1|0(?:\.\d+)?)\s*))?\)$/
42
+ // its mappable, map it
43
+ if (colorsMap[color] !== undefined) {
44
+ return colorsMap[color]
45
+ }
35
46
 
36
- if (normalized.test(color)) {
37
- return color
47
+ // its a 0xRRGGBBAA color, store it and return it
48
+ if (color.startsWith('0x') && color.length === 10) {
49
+ colorsMap[color] = color
50
+ return color
51
+ }
52
+
53
+ // check for hex color
54
+ if (hex.test(color)) {
55
+ color = color.replace('#', '').toLowerCase()
56
+ if (color.length === 3) {
57
+ color = color
58
+ .split('')
59
+ .map((c) => c + c)
60
+ .join('')
38
61
  }
39
62
 
40
- if (hex.test(color)) {
41
- color = color.replace('#', '').toLowerCase()
42
- if (color.length === 3) {
43
- color = color
44
- .split('')
45
- .map((c) => c + c)
46
- .join('')
47
- }
63
+ const colorRGBA = '0x' + color.padEnd(8, 'f')
64
+ colorsMap[color] = colorRGBA
65
+ return colorRGBA
66
+ }
48
67
 
49
- return '0x' + color.padEnd(8, 'f')
50
- }
68
+ //rgb/a
69
+ const rgbaMatch = rgba.exec(color)
70
+ if (rgbaMatch) {
71
+ const r = decimalToHex(rgbaMatch[3])
72
+ const g = decimalToHex(rgbaMatch[5])
73
+ const b = decimalToHex(rgbaMatch[7])
74
+ let a = 'ff'
51
75
 
52
- //rgb/a
53
- const rgbaMatch = rgba.exec(color)
54
- if (rgbaMatch) {
55
- return (
56
- '0x' +
57
- parseInt(rgbaMatch[3]).toString(16).padStart(2, '0') +
58
- parseInt(rgbaMatch[5]).toString(16).padStart(2, '0') +
59
- parseInt(rgbaMatch[7]).toString(16).padStart(2, '0') +
60
- (rgbaMatch[10] && rgbaMatch[1] === 'rgba'
61
- ? Math.min(Math.max(Math.round(parseFloat(rgbaMatch[10]) * 255), 0), 255)
62
- .toString(16)
63
- .padStart(2, '0')
64
- : 'ff')
65
- )
76
+ if (rgbaMatch[10] && rgbaMatch[1] === 'rgba') {
77
+ const alpha = Math.min(Math.max(Math.round(parseFloat(rgbaMatch[10]) * 255), 0), 255)
78
+ a = decimalToHex(alpha)
66
79
  }
67
80
 
68
- if (hsla.test(color)) {
69
- Log.warn('HSL(A) color format is not supported yet')
70
- return '0xffffffff'
71
- }
81
+ const resp = '0x' + r + g + b + a
82
+ colorsMap[color] = resp
83
+ return resp
84
+ }
72
85
 
73
- if (color in htmlColors) {
74
- return htmlColors[color]
75
- }
86
+ if (hsla.test(color)) {
87
+ console.warn('HSL(A) color format is not supported yet')
88
+ return '0xffffffff'
76
89
  }
77
90
 
78
91
  return defaultColor
@@ -25,3 +25,12 @@ export const createHumanReadableId = (name) => {
25
25
  export const createInternalId = () => {
26
26
  return ++counter
27
27
  }
28
+
29
+ /**
30
+ * Resets the counter value back to 0.
31
+ * Used in automated tests to ensure consistent results, not intended
32
+ * to be used in the actual framework code!
33
+ */
34
+ export const resetCounter = () => {
35
+ counter = 0
36
+ }
@@ -16,7 +16,7 @@
16
16
  */
17
17
 
18
18
  import test from 'tape'
19
- import { createHumanReadableId, createInternalId } from './componentId.js'
19
+ import { createHumanReadableId, createInternalId, resetCounter } from './componentId.js'
20
20
 
21
21
  test('Type createHumandReadableId', (assert) => {
22
22
  const expected = 'function'
@@ -59,6 +59,7 @@ test('Type createInternalId', (assert) => {
59
59
  })
60
60
 
61
61
  test('Returns an internal id, disregarding the component name', (assert) => {
62
+ resetCounter()
62
63
  const expected = 1
63
64
  const actual = createInternalId('Spinner')
64
65
 
@@ -17,13 +17,13 @@
17
17
 
18
18
  import parser from '../templateparser/parser.js'
19
19
  import generator from '../codegenerator/generator.js'
20
- import path from 'path'
21
20
 
22
21
  export default (source, filePath) => {
23
22
  if (
24
23
  source.indexOf('Blits.Component(') > -1 ||
25
24
  source.indexOf('Blits.Application(') > -1 ||
26
- /=>\s*Component\(['"][A-Za-z]+['"],/s.test(source) // blits component
25
+ /=>\s*Component\(['"][A-Za-z]+['"],/s.test(source) || // blits component
26
+ /\{.*?template\s*:\s*(['"`])((?:\\?.)*?)\1.*?\}/s.test(source) // object with template key
27
27
  ) {
28
28
  const templates = source.matchAll(/(?<!\/\/\s*)template\s*:\s*(['"`])((?:\\?.)*?)\1/gs)
29
29
  let newSource = source
@@ -45,8 +45,7 @@ export default (source, filePath) => {
45
45
  resourceName = source.match(/Blits\.Component\(['"](.*)['"]\s*,/)[1]
46
46
  }
47
47
 
48
- const componentPath = path.relative(process.cwd(), filePath)
49
- const parsed = parser(templateContent, resourceName, null, componentPath)
48
+ const parsed = parser(templateContent, resourceName, null, filePath)
50
49
 
51
50
  // Generate the code
52
51
  const code = generator.call({ components: {} }, parsed)
@@ -16,6 +16,7 @@
16
16
  */
17
17
 
18
18
  let currentEffect = null
19
+ let currentKey = null
19
20
 
20
21
  let paused = false
21
22
 
@@ -25,22 +26,16 @@ export const pauseTracking = () => {
25
26
 
26
27
  export const resumeTracking = () => {
27
28
  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
29
  }
35
30
 
36
31
  const objectMap = new WeakMap()
37
32
 
38
- const trackQueue = []
39
-
40
33
  export const track = (target, key) => {
41
34
  if (currentEffect) {
42
35
  if (paused) {
43
- trackQueue.push({ target, key, currentEffect })
36
+ return
37
+ }
38
+ if (currentKey !== null && key !== currentKey) {
44
39
  return
45
40
  }
46
41
  let effectsMap = objectMap.get(target)
@@ -58,21 +53,23 @@ export const track = (target, key) => {
58
53
  }
59
54
 
60
55
  export const trigger = (target, key, force = false) => {
61
- if (paused) return
56
+ if (paused === true) return
62
57
  const effectsMap = objectMap.get(target)
63
58
  if (!effectsMap) {
64
59
  return
65
60
  }
66
61
  const effects = effectsMap.get(key)
67
62
  if (effects) {
68
- effects.forEach((effect) => {
63
+ for (let effect of effects) {
69
64
  effect(force)
70
- })
65
+ }
71
66
  }
72
67
  }
73
68
 
74
- export const effect = (effect) => {
69
+ export const effect = (effect, key = null) => {
75
70
  currentEffect = effect
71
+ currentKey = key
76
72
  currentEffect()
77
73
  currentEffect = null
74
+ currentKey = null
78
75
  }
@@ -18,27 +18,27 @@
18
18
  import { track, trigger, pauseTracking, resumeTracking } from './effect.js'
19
19
  import symbols from '../symbols.js'
20
20
 
21
- const arrayPatchMethods = ['push', 'pop', 'shift', 'unshift', 'splice']
21
+ const arrayPatchMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort']
22
22
 
23
23
  const proxyMap = new WeakMap()
24
24
 
25
- const getProxy = (obj) => {
26
- return proxyMap.get(obj)
27
- }
28
-
29
- const getRaw = (value) => {
25
+ export const getRaw = (value) => {
30
26
  const raw = value && value[symbols.raw]
31
27
  return raw ? getRaw(raw) : value
32
28
  }
33
29
 
34
30
  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]) {
31
+ // don't create a proxy when a Blits component or an Image Texture
32
+ // is assigned to a state variable
33
+ if (
34
+ (typeof original === 'object' && original[symbols.id]) ||
35
+ original.constructor.name === '_ImageTexture'
36
+ ) {
37
37
  return original
38
38
  }
39
39
 
40
40
  // if original object is already a proxy, don't create a new one but return the existing one instead
41
- const existingProxy = getProxy(original)
41
+ const existingProxy = proxyMap.get(original)
42
42
  if (existingProxy) {
43
43
  return existingProxy
44
44
  }
@@ -52,21 +52,31 @@ const reactiveProxy = (original, _parent = null, _key) => {
52
52
 
53
53
  // handling arrays
54
54
  if (Array.isArray(target)) {
55
+ if (typeof target[key] === 'object' && target[key] !== null) {
56
+ if (Array.isArray(target[key])) {
57
+ track(target, key)
58
+ }
59
+ // create a new reactive proxy
60
+ return reactiveProxy(getRaw(target[key]), target, key)
61
+ }
55
62
  // augment array path methods (that change the length of the array)
56
- if (arrayPatchMethods.indexOf(key) > -1) {
63
+ if (arrayPatchMethods.indexOf(key) !== -1) {
57
64
  return function (...args) {
58
65
  pauseTracking()
59
66
  const result = target[key].apply(this, args)
67
+ resumeTracking()
60
68
  // trigger a change on the parent object and the key
61
69
  // i.e. when pushing a new item to `obj.data`, _parent will equal `obj`
62
70
  // and _key will equal `data`
63
- resumeTracking()
64
71
  trigger(_parent, _key)
65
72
  return result
66
73
  }
67
- } else {
68
- return Reflect.get(target, key, receiver)
69
74
  }
75
+ if (key === 'length') {
76
+ return original.length
77
+ }
78
+
79
+ return Reflect.get(target, key, receiver)
70
80
  }
71
81
 
72
82
  // handling objects (but not null values, which have object type in JS)
@@ -75,7 +85,7 @@ const reactiveProxy = (original, _parent = null, _key) => {
75
85
  track(target, key)
76
86
  }
77
87
  // create a new reactive proxy
78
- return reactiveProxy(target[key], target, key)
88
+ return reactiveProxy(getRaw(target[key]), target, key)
79
89
  }
80
90
 
81
91
  // handling all other types
@@ -3,6 +3,7 @@ export default {
3
3
  cursorTagStart: Symbol('cursorTagStart'),
4
4
  computedKeys: Symbol('computedKeys'),
5
5
  destroy: Symbol('destroy'),
6
+ getChildren: Symbol('getChildren'),
6
7
  holder: Symbol('holder'),
7
8
  id: Symbol('id'),
8
9
  identifier: Symbol('identifier'),
@@ -259,9 +259,23 @@ const removeView = async (route, view, transition) => {
259
259
  }
260
260
 
261
261
  const setOrAnimate = (node, transition, shouldAnimate = true) => {
262
- return shouldAnimate
263
- ? node.animate(transition.prop, transition.value, transition)
264
- : node.set(transition.prop, transition.value)
262
+ return new Promise((resolve) => {
263
+ if (shouldAnimate) {
264
+ // resolve the promise in the transition end-callback
265
+ // ("extending" end callback when one is already specified)
266
+ const existingEndCallback = transition.end
267
+ transition.end = existingEndCallback
268
+ ? (...args) => {
269
+ existingEndCallback(...args)
270
+ resolve()
271
+ }
272
+ : resolve
273
+ node.set(transition.prop, { transition })
274
+ } else {
275
+ node.set(transition.prop, transition.value)
276
+ resolve()
277
+ }
278
+ })
265
279
  }
266
280
 
267
281
  export const to = (location, data = {}, options = {}) => {
package/vite/index.js CHANGED
@@ -15,13 +15,10 @@
15
15
  * SPDX-License-Identifier: Apache-2.0
16
16
  */
17
17
 
18
- import { importChunkUrl } from '@lightningjs/vite-plugin-import-chunk-url'
19
-
20
18
  import preCompiler from './preCompiler.js'
21
19
  import msdfGenerator from './msdfGenerator.js'
22
20
 
23
- export { importChunkUrl as importChunkUrl } from '@lightningjs/vite-plugin-import-chunk-url'
24
21
  export { default as preCompiler } from './preCompiler.js'
25
22
  export { default as msdfGenerator } from './msdfGenerator.js'
26
23
 
27
- export default [importChunkUrl(), preCompiler(), msdfGenerator()]
24
+ export default [preCompiler(), msdfGenerator()]
@@ -16,6 +16,7 @@
16
16
  */
17
17
 
18
18
  import compiler from '../src/lib/precompiler/precompiler.js'
19
+ import path from 'path'
19
20
 
20
21
  export default function () {
21
22
  let config
@@ -26,7 +27,8 @@ export default function () {
26
27
  },
27
28
  transform(source, filePath) {
28
29
  if (config.blits && config.blits.precompile === false) return source
29
- return compiler(source, filePath)
30
+ const relativePath = path.relative(process.cwd(), filePath)
31
+ return compiler(source, relativePath)
30
32
  },
31
33
  }
32
34
  }
@@ -1,4 +0,0 @@
1
- // @ts-ignore
2
- import renderer from '@lightningjs/blits/renderer'
3
-
4
- renderer()
@@ -1,119 +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 Component from '../component.js'
19
- import Settings from '../settings.js'
20
-
21
- export default () =>
22
- Component('Text', {
23
- /* eslint-disable no-unused-vars */
24
- code: {
25
- render: function anonymous(parent, component, context, components) {
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
- },
48
- effects: [
49
- function anonymous(component, elms, context, components) {
50
- elms[0].set('text', component.content)
51
- },
52
- function anonymous(component, elms, context, components) {
53
- elms[0].set('fontSize', component.size)
54
- },
55
- function anonymous(component, elms, context, components) {
56
- elms[0].set('color', component.color)
57
- },
58
- function anonymous(component, elms, context, components) {
59
- elms[0].set('style', component.style)
60
- },
61
- function anonymous(component, elms, context, components) {
62
- elms[0].set('weight', component.weight)
63
- },
64
- function anonymous(component, elms, context, components) {
65
- elms[0].set('wordWrap', component.wordwrap)
66
- },
67
- function anonymous(component, elms, context, components) {
68
- elms[0].set('maxLines', component.maxlines)
69
- },
70
- function anonymous(component, elms, context, components) {
71
- elms[0].set('h', component.maxheight)
72
- },
73
- function anonymous(component, elms, context, components) {
74
- elms[0].set('textAlign', component.align)
75
- },
76
- function anonymous(component, elms, context, components) {
77
- elms[0].set('overflowSuffix', component.textoverflow)
78
- },
79
- ],
80
- context: {},
81
- },
82
- props: [
83
- 'content',
84
- {
85
- key: 'font',
86
- default: Settings.get('defaultFont', 'lato'),
87
- },
88
- {
89
- key: 'size',
90
- cast: Number,
91
- default: 32,
92
- },
93
- 'style',
94
- 'color',
95
- 'weight',
96
- 'letterspacing',
97
- 'stretch',
98
- 'align',
99
- 'wordwrap',
100
- 'maxlines',
101
- 'maxheight',
102
- 'lineheight',
103
- 'contain',
104
- '@loaded',
105
- '@error',
106
- 'textoverflow',
107
- ],
108
- computed: {
109
- _contain() {
110
- return (
111
- this.contain ||
112
- (this.maxheight && this.wordwrap ? 'both' : this.wordwrap ? 'width' : 'none')
113
- )
114
- },
115
- _lineheight() {
116
- return this.lineheight !== undefined ? this.lineheight : this.size
117
- },
118
- },
119
- })
@@ -1,81 +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 Component from '../component.js'
19
- import Settings from '../settings.js'
20
-
21
- export default () =>
22
- Component('Text', {
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
- />`,
44
- props: [
45
- 'content',
46
- {
47
- key: 'font',
48
- default: Settings.get('defaultFont', 'lato'),
49
- },
50
- {
51
- key: 'size',
52
- cast: Number,
53
- default: 32,
54
- },
55
- 'style',
56
- 'color',
57
- 'weight',
58
- 'letterspacing',
59
- 'stretch',
60
- 'align',
61
- 'wordwrap',
62
- 'maxlines',
63
- 'maxheight',
64
- 'lineheight',
65
- 'contain',
66
- '@loaded',
67
- '@error',
68
- 'textoverflow',
69
- ],
70
- computed: {
71
- _contain() {
72
- return (
73
- this.contain ||
74
- (this.maxheight && this.wordwrap ? 'both' : this.wordwrap ? 'width' : 'none')
75
- )
76
- },
77
- _lineheight() {
78
- return this.lineheight !== undefined ? this.lineheight : this.size
79
- },
80
- },
81
- })