@lightningjs/blits 2.1.3 → 2.2.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,19 @@
1
1
  # Changelog
2
2
 
3
+ ## v2.2.0
4
+
5
+ _11 may 2026_
6
+
7
+ - Exposed built-in reactivity to be used in custom Blits plugins
8
+ - Cleaned up unused key names from default key mapping
9
+ - Improved documentation
10
+ - Fixed reactive color not working for components
11
+ - Added EOL guard for Blits elements to prevent potential race conditions
12
+ - Updated MSDF generator version in boilerplate
13
+ - Fixed / improved GH workflow for automated tests
14
+ - Upgraded renderer to 3.0.3
15
+
16
+
3
17
  ## v2.1.3
4
18
 
5
19
  _16 apr 2026_
package/index.d.ts CHANGED
@@ -405,6 +405,11 @@ declare module '@lightningjs/blits' {
405
405
  */
406
406
  readonly $parent: ComponentBase | undefined,
407
407
 
408
+ /**
409
+ * Human-readable identifier for this component instance (e.g. "MyComponent_0")
410
+ */
411
+ readonly $componentId: string,
412
+
408
413
  /**
409
414
  * Indicates whether the component currently is hovered
410
415
  *
@@ -536,6 +541,14 @@ declare module '@lightningjs/blits' {
536
541
  * Router instance
537
542
  */
538
543
  $router: Router
544
+ /**
545
+ * Creates a reactive object. Changes to properties on the returned object
546
+ * will automatically trigger re-renders in any component that accesses them.
547
+ *
548
+ * Pre-configured with the app's reactivity mode and global scope.
549
+ * Primarily intended for use inside custom plugins.
550
+ */
551
+ $reactive: <T extends Record<string, any>>(target: T) => T
539
552
  /**
540
553
  * Dynamically set the size of a component holder node
541
554
  */
@@ -1331,7 +1344,7 @@ declare module '@lightningjs/blits' {
1331
1344
  * Should do all necessary setup and ideally return an object with
1332
1345
  * properties or methods that can be used in the App
1333
1346
  */
1334
- plugin: () => any
1347
+ plugin: (options?: any) => any
1335
1348
  }
1336
1349
 
1337
1350
 
@@ -1389,7 +1402,7 @@ declare module '@lightningjs/blits' {
1389
1402
  * Object with options to be passed into the plugin instantiation method.
1390
1403
  * Can be used to set default values
1391
1404
  */
1392
- Plugin(plugin: Plugin, nameOrOptions?: string | object , options?: object) : void
1405
+ Plugin(plugin: Plugin | ((options?: any) => any), nameOrOptions?: string | object , options?: object) : void
1393
1406
  }
1394
1407
 
1395
1408
  const Blits: Blits;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightningjs/blits",
3
- "version": "2.1.3",
3
+ "version": "2.2.0",
4
4
  "description": "Blits: The Lightning 3 App Development Framework",
5
5
  "bin": "bin/index.js",
6
6
  "exports": {
@@ -75,7 +75,7 @@
75
75
  "tape": "^5.5.0"
76
76
  },
77
77
  "dependencies": {
78
- "@lightningjs/renderer": "^3.0.2",
78
+ "@lightningjs/renderer": "^3.0.3",
79
79
  "magic-string": "^0.30.21"
80
80
  },
81
81
  "repository": {
@@ -22,8 +22,22 @@ import router from './router.js'
22
22
  import announcer from './announcer.js'
23
23
  import utils from './utils.js'
24
24
  import symbols from '../../lib/symbols.js'
25
+ import { reactive } from '../../lib/reactivity/reactive.js'
26
+ import Settings from '../../settings.js'
25
27
 
26
- export const shared = { ...events, ...router, ...announcer }
28
+ export const shared = {
29
+ ...events,
30
+ ...router,
31
+ ...announcer,
32
+ $reactive: {
33
+ value: function (target) {
34
+ return reactive(target, Settings.get('reactivityMode'), true)
35
+ },
36
+ writable: false,
37
+ enumerable: true,
38
+ configurable: false,
39
+ },
40
+ }
27
41
 
28
42
  export default Object.defineProperties(
29
43
  {
package/src/component.js CHANGED
@@ -432,6 +432,10 @@ const Component = (name = required('name'), config = required('config')) => {
432
432
  */
433
433
  const factory = (options = {}, parentEl, parentComponent, rootComponent) => {
434
434
  if (Base[symbols['launched']] === false) {
435
+ // create a context with shared properties so this.$reactive (etc.)
436
+ // is available during plugin initialization
437
+ const pluginContext = Object.defineProperties({}, shared)
438
+
435
439
  // Register user defined plugins once on the Base object (after launch)
436
440
  const pluginKeys = Object.keys(plugins)
437
441
  const pluginKeysLength = pluginKeys.length
@@ -449,8 +453,8 @@ const Component = (name = required('name'), config = required('config')) => {
449
453
  const plugin = plugins[pluginName]
450
454
 
451
455
  pluginInstances[prefixedPluginName] = {
452
- // instantiate the plugin, passing in provided options
453
- value: Object.defineProperties(plugin.plugin(plugin.options), shared),
456
+ // instantiate the plugin with shared context, then apply shared to the result
457
+ value: Object.defineProperties(plugin.plugin.call(pluginContext, plugin.options), shared),
454
458
  writable: false,
455
459
  enumerable: true,
456
460
  configurable: true,
@@ -629,6 +629,7 @@ const Element = {
629
629
  * @param {Object} data - Framework inspector metadata to merge
630
630
  */
631
631
  setInspectorMetadata(data) {
632
+ if (this.eol === true) return
632
633
  // Early return if inspector not enabled (performance optimization)
633
634
  if (inspectorEnabled !== true) {
634
635
  return
@@ -666,6 +667,7 @@ const Element = {
666
667
  * @returns {void}
667
668
  */
668
669
  set(prop, value) {
670
+ if (this.eol === true) return
669
671
  if (value === undefined) return
670
672
  // @ts-ignore
671
673
  if (this.props.raw[prop] === value) return
@@ -701,6 +703,8 @@ const Element = {
701
703
  }
702
704
  },
703
705
  animate(prop, value, transition) {
706
+ if (this.eol === true) return
707
+
704
708
  // Clear any existing debounce timeout for this property
705
709
  if (this.debounceTimeouts[prop] !== undefined) {
706
710
  clearTimeout(this.debounceTimeouts[prop])
@@ -812,6 +816,9 @@ const Element = {
812
816
  f.start()
813
817
  },
814
818
  destroy() {
819
+ if (this.eol === true) return
820
+ this.eol = true
821
+
815
822
  if (this.node === null) return
816
823
 
817
824
  Log.debug('Deleting Node', this.nodeId)
@@ -903,6 +910,7 @@ export default (config, component) => {
903
910
  inspectorEnabled = Settings.get('inspector', false)
904
911
  }
905
912
  return Object.assign(Object.create(Element), {
913
+ eol: false,
906
914
  props: Object.assign(Object.create(propsTransformer), { props: {} }),
907
915
  scheduledTransitions: {},
908
916
  debounceTimeouts: {},
@@ -225,7 +225,6 @@ const generateElementCode = function (
225
225
  const value = templateObject[key]
226
226
 
227
227
  if (isReactiveKey(key)) {
228
- if (options.holder && key === ':color') return
229
228
  if (options.holder) {
230
229
  this.effectsCode.push(`
231
230
  if(typeof skips === 'undefined' || (typeof skips[${counter}] === 'undefined' ||