@lightningjs/blits 1.9.1 → 1.10.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.10.0
4
+
5
+ _8 nov 2024_
6
+
7
+ - Fixed issue with back button not bubbling to App component after last page in router history is popped
8
+ - Added `align-items` attribute to Layout component
9
+ - Fixed issue with watching nested state variables and global state
10
+ - Upgraded to renderer 2.6.2
11
+ - Fixed issue with white background for Elements with falsy src attribute
12
+ - Fixed issue with calling focus on component that already is focussed
13
+
14
+
15
+ ## v1.9.2
16
+
17
+ _5 nov 2024_
18
+
19
+ - Fixed Element related tests
20
+ - Bumped renderer to version 2.6.0
21
+
3
22
  ## v1.9.1
4
23
 
5
24
  _4 nov 2024_
@@ -37,6 +37,14 @@ In order to align vertically use `<Layout direction="vertical"></Layout>`. And u
37
37
 
38
38
  By default the Layout-component places each Element directly besides (or below) the previous one. By adding the `gap`-attribute you can control how much space will be added between each Element or Component. The `gap`-attribute accepts a number in pixels.
39
39
 
40
+ ### Aligning items
41
+
42
+ The layout component positions its children based on the provided direction (`horizontal` or `vertical`). With the `align-items`-attribute you can specify how to align the children on the opposite axis:
43
+
44
+ - `start` (the default value) - aligns the children in the _top_ for horizontal layouts, and on the _left_ for vertical layouts
45
+ - `center` - align the children in the center
46
+ - `end` - aligns the children in the _bottom_ for horizontal layouts, and on the _right_ for vertical layouts
47
+
40
48
  ### Dynamic dimensions
41
49
 
42
50
  For the Layout component to work properly, the direct children all need to have dimensions (i.e `w` and `h` attributes). The exception here being Text elements.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightningjs/blits",
3
- "version": "1.9.1",
3
+ "version": "1.10.0",
4
4
  "description": "Blits: The Lightning 3 App Development Framework",
5
5
  "bin": "bin/index.js",
6
6
  "exports": {
@@ -9,7 +9,8 @@
9
9
  "./transitions": "./src/router/transitions/index.js",
10
10
  "./precompiler": "./src/lib/precompiler/precompiler.js",
11
11
  "./plugins": "./src/plugins/index.js",
12
- "./symbols": "./src/lib/symbols.js"
12
+ "./symbols": "./src/lib/symbols.js",
13
+ "./blitsFileConverter": "./src/lib/blitsfileconverter/blitsfileconverter.js"
13
14
  },
14
15
  "scripts": {
15
16
  "test": "c8 npm run test:run",
@@ -49,7 +50,7 @@
49
50
  },
50
51
  "dependencies": {
51
52
  "@lightningjs/msdf-generator": "^1.1.0",
52
- "@lightningjs/renderer": "^2.5.1"
53
+ "@lightningjs/renderer": "^2.6.2"
53
54
  },
54
55
  "repository": {
55
56
  "type": "git",
package/src/component.js CHANGED
@@ -176,6 +176,7 @@ const Component = (name = required('name'), config = required('config')) => {
176
176
  for (let i = 0; i < watcherkeysLength; i++) {
177
177
  let target = this
178
178
  let key = watcherkeys[i]
179
+ const watchKey = key
179
180
  // when dot notation used, find the nested target
180
181
  if (key.indexOf('.') > -1) {
181
182
  const keys = key.split('.')
@@ -190,7 +191,7 @@ const Component = (name = required('name'), config = required('config')) => {
190
191
  effect((force = false) => {
191
192
  const newValue = target[key]
192
193
  if (old !== newValue || force === true) {
193
- this[symbols.watchers][key].apply(this, [newValue, old])
194
+ this[symbols.watchers][watchKey].apply(this, [newValue, old])
194
195
  old = newValue
195
196
  }
196
197
  })
@@ -60,8 +60,11 @@ export default () =>
60
60
  },
61
61
  },
62
62
  input: {
63
- back() {
64
- Router.back()
63
+ back(e) {
64
+ const navigating = Router.back()
65
+ if (navigating === false) {
66
+ this.parent.$focus(e)
67
+ }
65
68
  },
66
69
  },
67
70
  })
@@ -44,8 +44,11 @@ export default () =>
44
44
  },
45
45
  },
46
46
  input: {
47
- back() {
48
- Router.back()
47
+ back(e) {
48
+ const navigating = Router.back()
49
+ if (navigating === false) {
50
+ this.parent.$focus(e)
51
+ }
49
52
  },
50
53
  },
51
54
  })
@@ -24,9 +24,11 @@ import Settings from '../../settings.js'
24
24
 
25
25
  const layoutFn = function (config) {
26
26
  let offset = 0
27
- const xy = config.direction === 'vertical' ? 'y' : 'x'
28
- const wh = config.direction === 'vertical' ? 'height' : 'width'
29
- const opositeWh = config.direction === 'vertical' ? 'width' : 'height'
27
+ const position = config.direction === 'vertical' ? 'y' : 'x'
28
+ const oppositePosition = config.direction === 'vertical' ? 'x' : 'y'
29
+ const oppositeMount = config.direction === 'vertical' ? 'mountX' : 'mountY'
30
+ const dimension = config.direction === 'vertical' ? 'height' : 'width'
31
+ const oppositeDimension = config.direction === 'vertical' ? 'width' : 'height'
30
32
 
31
33
  const children = this.children
32
34
  const childrenLength = children.length
@@ -34,11 +36,11 @@ const layoutFn = function (config) {
34
36
  const gap = config.gap || 0
35
37
  for (let i = 0; i < childrenLength; i++) {
36
38
  const node = children[i]
37
- node[xy] = offset
39
+ node[position] = offset
38
40
  // todo: temporary text check, due to 1px width of empty text node
39
- if (wh === 'width') {
41
+ if (dimension === 'width') {
40
42
  offset += node.width + (node.width !== ('text' in node ? 1 : 0) ? gap : 0)
41
- } else if (wh === 'height') {
43
+ } else if (dimension === 'height') {
42
44
  offset +=
43
45
  'text' in node
44
46
  ? node.width > 1
@@ -48,11 +50,25 @@ const layoutFn = function (config) {
48
50
  ? node.height + gap
49
51
  : 0
50
52
  }
51
- otherDimension = Math.max(otherDimension, node[opositeWh])
53
+ otherDimension = Math.max(otherDimension, node[oppositeDimension])
52
54
  }
53
55
  // adjust the size of the layout container
54
- this[wh] = offset - gap
55
- this[opositeWh] = otherDimension
56
+ this[dimension] = offset - gap
57
+ this[oppositeDimension] = otherDimension
58
+
59
+ const align = {
60
+ start: 0,
61
+ end: 1,
62
+ center: 0.5,
63
+ }[config['align-items'] || 'start']
64
+
65
+ if (align !== 0) {
66
+ for (let i = 0; i < childrenLength; i++) {
67
+ const node = children[i]
68
+ node[oppositePosition] = otherDimension
69
+ node[oppositeMount] = align
70
+ }
71
+ }
56
72
  }
57
73
 
58
74
  const isTransition = (value) => {
@@ -146,7 +162,7 @@ const propsTransformer = {
146
162
  set src(v) {
147
163
  this.props['src'] = v
148
164
  if (this.raw['color'] === undefined) {
149
- this.props['color'] = 0xffffffff
165
+ this.props['color'] = this.props['src'] ? 0xffffffff : 0x00000000
150
166
  }
151
167
  },
152
168
  set texture(v) {
@@ -225,7 +241,15 @@ const propsTransformer = {
225
241
  }
226
242
  },
227
243
  set show(v) {
228
- this.props['alpha'] = v ? 1 : 0
244
+ if (v) {
245
+ this.props['alpha'] = 1
246
+ this.props['width'] = this.raw['w'] || this.raw['width']
247
+ this.props['height'] = this.raw['h'] || this.raw['height']
248
+ } else {
249
+ this.props['alpha'] = 0
250
+ this.props['width'] = 0
251
+ this.props['height'] = 0
252
+ }
229
253
  },
230
254
  set alpha(v) {
231
255
  this.props['alpha'] = v
@@ -101,7 +101,7 @@ test('Element - Set `w` property', (assert) => {
101
101
 
102
102
  assert.equal(el.node['width'], 100, 'Node width parameter should be set')
103
103
  assert.equal(el.props.props['width'], 100, 'Props width parameter should be set')
104
- assert.equal(el.props.raw.get('w'), 100, "Props' raw map entry should be added")
104
+ assert.equal(el.props.raw['w'], 100, "Props' raw map entry should be added")
105
105
  assert.end()
106
106
  })
107
107
 
@@ -116,7 +116,7 @@ test('Element - Set `mount` property', (assert) => {
116
116
  assert.equal(el.node['mountY'], 20, 'Node mountY parameter should be set')
117
117
  assert.equal(el.props.props['mountX'], 10, 'Props mountX parameter should be set')
118
118
  assert.equal(el.props.props['mountY'], 20, 'Props mountY parameter should be set')
119
- assert.equal(el.props.raw.get('mount'), value, "Props' raw map entry should be added")
119
+ assert.equal(el.props.raw['mount'], value, "Props' raw map entry should be added")
120
120
  assert.end()
121
121
  })
122
122
 
@@ -128,7 +128,7 @@ test('Element - Set `color` property', (assert) => {
128
128
 
129
129
  assert.equal(el.node['color'], '0xf0ffffff', 'Node color parameter should be set')
130
130
  assert.equal(el.props.props['color'], '0xf0ffffff', 'Props color parameter should be set')
131
- assert.equal(el.props.raw.get('color'), 'azure', "Props' raw map entry should be added")
131
+ assert.equal(el.props.raw['color'], 'azure', "Props' raw map entry should be added")
132
132
  assert.end()
133
133
  })
134
134
 
@@ -141,7 +141,7 @@ test('Element - Set `src` property', (assert) => {
141
141
 
142
142
  assert.equal(el.node['src'], value, 'Node src parameter should be set')
143
143
  assert.equal(el.props.props['src'], value, 'Props src parameter should be set')
144
- assert.equal(el.props.raw.get('src'), value, "Props' raw map entry should be added")
144
+ assert.equal(el.props.raw['src'], value, "Props' raw map entry should be added")
145
145
  assert.equal(el.props.props['color'], 0xffffffff, 'Props default color parameter should be set')
146
146
  assert.end()
147
147
  })
@@ -154,7 +154,7 @@ test('Element - Set `texture` property', (assert) => {
154
154
 
155
155
  assert.equal(el.node['texture'], 'foo', 'Node texture parameter should be set')
156
156
  assert.equal(el.props.props['texture'], 'foo', 'Props texture parameter should be set')
157
- assert.equal(el.props.raw.get('texture'), 'foo', "Props' raw map entry should be added")
157
+ assert.equal(el.props.raw['texture'], 'foo', "Props' raw map entry should be added")
158
158
  assert.equal(el.props.props['color'], 0xffffffff, 'Props default color parameter should be set')
159
159
  assert.end()
160
160
  })
@@ -181,7 +181,7 @@ test('Element - Set `fit` property with a string type value', (assert) => {
181
181
  fitVal,
182
182
  'Props textureOptions parameter should be set'
183
183
  )
184
- assert.equal(el.props.raw.get('fit'), fitVal, "Props' raw map entry should be added")
184
+ assert.equal(el.props.raw['fit'], fitVal, "Props' raw map entry should be added")
185
185
  assert.end()
186
186
  })
187
187
 
@@ -212,7 +212,7 @@ test('Element - Set `fit` property with an object type value', (assert) => {
212
212
  1,
213
213
  'Node resizeMode "clipY" parameter should be set to correct value'
214
214
  )
215
- assert.equal(el.props.raw.get('fit'), fitVal, "Props' raw map entry should be added")
215
+ assert.equal(el.props.raw['fit'], fitVal, "Props' raw map entry should be added")
216
216
  assert.end()
217
217
  })
218
218
 
@@ -243,7 +243,7 @@ test('Element - Set `fit` property with position key as a string type value', (a
243
243
  1,
244
244
  'Node resizeMode "clipY" parameter should be set to correct value'
245
245
  )
246
- assert.equal(el.props.raw.get('fit'), fitVal, "Props' raw map entry should be added")
246
+ assert.equal(el.props.raw['fit'], fitVal, "Props' raw map entry should be added")
247
247
  assert.end()
248
248
  })
249
249
 
package/src/focus.js CHANGED
@@ -38,6 +38,7 @@ export default {
38
38
  return focusedComponent
39
39
  },
40
40
  set(component, event) {
41
+ if (component === focusedComponent) return
41
42
  clearTimeout(setFocusTimeout)
42
43
  focusedComponent && focusedComponent !== component.parent && focusedComponent.unfocus()
43
44
  focusChain.reverse().forEach((cmp) => cmp.unfocus())
@@ -0,0 +1,52 @@
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
+ export default (source) => {
19
+ const { template, script } = parseBlitsFile(source)
20
+ return injectTemplate(script, template)
21
+ }
22
+
23
+ const parseBlitsFile = (source) => {
24
+ const templateMatch = source.match(/<template>([\s\S]*?)<\/template>/)
25
+ const scriptMatch = source.match(/<script(?:\s+lang=["'](?:js|ts)["'])?\s*>([\s\S]*?)<\/script>/)
26
+
27
+ return {
28
+ template: templateMatch ? templateMatch[1].trim() : '',
29
+ script: scriptMatch ? scriptMatch[1].trim() : '',
30
+ }
31
+ }
32
+
33
+ const injectTemplate = (script, template) => {
34
+ const componentRegex =
35
+ /(Blits\.Component|Component)\s*\(\s*(['"`])(?:(?=(\\?))\3.)*?\2\s*,\s*\{|Blits\.Application\s*\(\s*\{/
36
+
37
+ const match = script.match(componentRegex)
38
+
39
+ if (!match) {
40
+ // we might consider initializing a component if it's not found automatically
41
+ throw new Error(
42
+ 'Could not find Blits.Component, Component, or Blits.Application initialization in the script'
43
+ )
44
+ }
45
+
46
+ // The insertion point is right after the opening curly brace
47
+ const insertIndex = match.index + match[0].length
48
+
49
+ // Using template literals to preserve multiline strings and escape characters
50
+ const injection = `\n template: \`${template.replace(/`/g, '\\`')}\`,\n`
51
+ return script.slice(0, insertIndex) + injection + script.slice(insertIndex)
52
+ }
@@ -0,0 +1,38 @@
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 blitsfileconverter from '../src/lib/blitsfileconverter/blitsfileconverter.js'
19
+
20
+ export default function blitsFileType() {
21
+ return {
22
+ name: 'vite-plugin-blits-file-type',
23
+ enforce: 'pre',
24
+ transform(src, id) {
25
+ if (id.endsWith('.blits')) {
26
+ try {
27
+ const transformedCode = blitsfileconverter(src)
28
+ return {
29
+ code: transformedCode,
30
+ map: null, // no source map
31
+ }
32
+ } catch (error) {
33
+ this.error(error)
34
+ }
35
+ }
36
+ },
37
+ }
38
+ }
package/vite/index.js CHANGED
@@ -17,8 +17,10 @@
17
17
 
18
18
  import preCompiler from './preCompiler.js'
19
19
  import msdfGenerator from './msdfGenerator.js'
20
+ import blitsFileConverter from './blitsFileConverter.js'
20
21
 
21
22
  export { default as preCompiler } from './preCompiler.js'
22
23
  export { default as msdfGenerator } from './msdfGenerator.js'
24
+ export { default as blitsFileConverter } from './blitsFileConverter.js'
23
25
 
24
- export default [preCompiler(), msdfGenerator()]
26
+ export default [blitsFileConverter(), preCompiler(), msdfGenerator()]
@@ -1,3 +1,20 @@
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
+
1
18
  import path from 'path'
2
19
  import * as fs from 'fs'
3
20
  import { createHash } from 'crypto'
@@ -27,6 +27,13 @@ export default function () {
27
27
  },
28
28
  transform(source, filePath) {
29
29
  if (config.blits && config.blits.precompile === false) return source
30
+
31
+ const fileExtension = path.extname(filePath)
32
+
33
+ // we should only precompile .js and .ts files
34
+ if (fileExtension === '.js' || fileExtension === '.ts') {
35
+ return compiler(source, filePath)
36
+ }
30
37
  const relativePath = path.relative(process.cwd(), filePath)
31
38
  return compiler(source, relativePath)
32
39
  },