@lightningjs/blits 1.43.2 → 1.45.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,25 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.45.0
4
+
5
+ _29 dec 2025_
6
+
7
+ - Added support for defining types for custom plugins on the Blits component definitions
8
+ - Added importable type definitions for built-in plugins
9
+ - Added support for JS sourcemaps
10
+ - Added reactivity for shader props (individual shaders, not effects via dynamic shader)
11
+ - Fixed issue with usage of Blits plugins not working in for loops
12
+ - Improved test coverage
13
+
14
+ ## v1.44.0
15
+
16
+ _20 Nov 2025_
17
+
18
+ - Added `$input` method to facilitate key handling _without_ also passing focus
19
+ - Added support for passing `type` of image in the `src`-attribute (`regular`, `svg`, `compressed` for cases the file type can't be derived from the file name)
20
+ - Bumped Lightning renderer to v2.20.0 with improved support for compressed textures
21
+
22
+
3
23
  ## v1.43.2
4
24
 
5
25
  _13 Nov 2025_
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  # Blits - Lightning 3 App Development Framework
4
4
 
5
+ ![npm](https://img.shields.io/npm/v/@lightningjs/blits?label=Version&color=blue) ![License](https://img.shields.io/github/license/lightning-js/blits?label=License&color=blue) ![Tests](https://github.com/lightning-js/blits/workflows/Tests/badge.svg) ![Coverage](https://img.shields.io/codecov/c/github/lightning-js/blits/master?label=Coverage) ![npm](https://img.shields.io/npm/dm/@lightningjs/blits?label=Downloads&color=blue)
6
+
5
7
  With Blits, the App Development Framework for Lightning 3, it becomes a breeze to build great Lightning 3 applications.
6
8
 
7
9
  Blits is built on top of the Lightning 3 Rendererer and aims to provide a **great developer experience**, making it fun and easy to build your apps!
package/index.d.ts CHANGED
@@ -18,10 +18,10 @@
18
18
  // blits file type reference
19
19
  /// <reference path="./blits.d.ts" />
20
20
 
21
- import {type ShaderEffect as RendererShaderEffect, type WebGlCoreShader, type RendererMainSettings} from '@lightningjs/renderer'
22
-
23
21
  declare module '@lightningjs/blits' {
24
-
22
+ type RendererShaderEffect = import('@lightningjs/renderer').ShaderEffect
23
+ type WebGlCoreShader = import('@lightningjs/renderer').WebGlCoreShader
24
+ type RendererMainSettings = import('@lightningjs/renderer').RendererMainSettings
25
25
 
26
26
  export interface AnnouncerUtteranceOptions {
27
27
  /**
@@ -209,7 +209,7 @@ declare module '@lightningjs/blits' {
209
209
  }
210
210
 
211
211
  export interface Input {
212
- [key: string]: (event: KeyboardEvent) => void | undefined | unknown,
212
+ [key: string]: ((event: KeyboardEvent) => unknown) | undefined,
213
213
  /**
214
214
  * Catch all input function
215
215
  *
@@ -362,7 +362,39 @@ declare module '@lightningjs/blits' {
362
362
  }
363
363
  }
364
364
 
365
- export type ComponentBase = {
365
+ // Extension point for app- and plugin-specific fields on the component `this`.
366
+ // Add your own properties (e.g., `$telemetry`, `componentName`) via TypeScript
367
+ // module augmentation in your app, without changing core types.
368
+ // Note: `ComponentBase` extends this interface, so augmented fields appear in all
369
+ // hooks, methods, input, computed, and watch.
370
+ export interface CustomComponentProperties {
371
+ // Empty by design: extend in your app via TypeScript module augmentation.
372
+ }
373
+
374
+ export interface LanguagePlugin {
375
+ translate(key: string, ...replacements: any[]): string
376
+ readonly language: string
377
+ set(language: string): void
378
+ translations(translationsObject: Record<string, unknown>): void
379
+ load(file: string): Promise<void>
380
+ }
381
+
382
+ export interface ThemePlugin {
383
+ get<T = unknown>(key: string): T | undefined
384
+ get<T>(key: string, fallback: T): T
385
+ set(theme: string): void
386
+ }
387
+
388
+ export interface StoragePlugin {
389
+ get<T = unknown>(key: string): T | null
390
+ set(key: string, value: unknown): boolean
391
+ remove(key: string): void
392
+ clear(): void
393
+ }
394
+
395
+ export type AppStatePlugin<TState extends Record<string, unknown> = Record<string, unknown>> = TState
396
+
397
+ export interface ComponentBase extends CustomComponentProperties {
366
398
  /**
367
399
  * Indicates whether the component currently has focus
368
400
  *
@@ -431,6 +463,12 @@ declare module '@lightningjs/blits' {
431
463
  * Set focus to the Component, optionally pass a KeyboardEvent for instant event bubbling
432
464
  */
433
465
  $focus: (event?: KeyboardEvent) => void
466
+ /**
467
+ * Handle a keyboard event on this component without changing focus
468
+ * @param event - The keyboard event to handle
469
+ * @returns Returns true if this component or a parent component handled the event, false otherwise
470
+ */
471
+ $input: (event: KeyboardEvent) => boolean
434
472
  /**
435
473
  * @deprecated
436
474
  * Deprecated: use `this.$focus()` instead
@@ -618,7 +656,7 @@ declare module '@lightningjs/blits' {
618
656
  }
619
657
 
620
658
  export interface RouterHooks {
621
- init?: () => Promise<> | void;
659
+ init?: () => Promise<void> | void;
622
660
  beforeEach?: (to: Route, from: Route) => string | Route | Promise<string | Route> | void;
623
661
  error?: (err: string) => string | Route | Promise<string | Route> | void;
624
662
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightningjs/blits",
3
- "version": "1.43.2",
3
+ "version": "1.45.0",
4
4
  "description": "Blits: The Lightning 3 App Development Framework",
5
5
  "bin": "bin/index.js",
6
6
  "exports": {
@@ -8,7 +8,26 @@
8
8
  "./vite": "./vite/index.js",
9
9
  "./transitions": "./src/router/transitions/index.js",
10
10
  "./precompiler": "./src/lib/precompiler/precompiler.js",
11
- "./plugins": "./src/plugins/index.js",
11
+ "./plugins": {
12
+ "types": "./src/plugins/index.d.ts",
13
+ "default": "./src/plugins/index.js"
14
+ },
15
+ "./plugins/language": {
16
+ "types": "./src/plugins/language.d.ts",
17
+ "default": "./src/plugins/language.js"
18
+ },
19
+ "./plugins/theme": {
20
+ "types": "./src/plugins/theme.d.ts",
21
+ "default": "./src/plugins/theme.js"
22
+ },
23
+ "./plugins/appstate": {
24
+ "types": "./src/plugins/appstate.d.ts",
25
+ "default": "./src/plugins/appstate.js"
26
+ },
27
+ "./plugins/storage": {
28
+ "types": "./src/plugins/storage/storage.d.ts",
29
+ "default": "./src/plugins/storage/storage.js"
30
+ },
12
31
  "./symbols": "./src/lib/symbols.js",
13
32
  "./blitsFileConverter": "./src/lib/blitsfileconverter/blitsfileconverter.js"
14
33
  },
@@ -48,6 +67,7 @@
48
67
  "husky": "^9.1.7",
49
68
  "jsdom": "24.0.0",
50
69
  "lint-staged": "^15.5.0",
70
+ "magic-string": "^0.30.21",
51
71
  "prettier": "^3.6.2",
52
72
  "sinon": "^21.0.0",
53
73
  "tap-diff": "^0.1.1",
@@ -55,7 +75,7 @@
55
75
  },
56
76
  "dependencies": {
57
77
  "@lightningjs/msdf-generator": "^1.2.0",
58
- "@lightningjs/renderer": "^2.19.1"
78
+ "@lightningjs/renderer": "^2.20.0"
59
79
  },
60
80
  "repository": {
61
81
  "type": "git",
@@ -55,7 +55,10 @@ function processFile(filePath) {
55
55
  fs.copyFileSync(filePath, backupFilePath)
56
56
 
57
57
  const source = fs.readFileSync(filePath, 'utf-8')
58
- const newSource = compiler(source, filePath)
58
+ const result = compiler(source, filePath)
59
+
60
+ // Handle both string and object return types
61
+ const newSource = typeof result === 'object' && result.code ? result.code : result
59
62
  fs.writeFileSync(filePath, newSource)
60
63
 
61
64
  // only format the file if it was changed
@@ -20,28 +20,16 @@ import { default as Focus, keyUpCallbacks } from './focus.js'
20
20
  import Settings from './settings.js'
21
21
 
22
22
  import symbols from './lib/symbols.js'
23
- import { DEFAULT_HOLD_TIMEOUT_MS } from './constants.js'
23
+ import { DEFAULT_HOLD_TIMEOUT_MS, DEFAULT_KEYMAP } from './constants.js'
24
24
 
25
- const Application = (config) => {
26
- const defaultKeyMap = {
27
- ArrowLeft: 'left',
28
- ArrowRight: 'right',
29
- ArrowUp: 'up',
30
- ArrowDown: 'down',
31
- Enter: 'enter',
32
- ' ': 'space',
33
- Backspace: 'back',
34
- Escape: 'escape',
35
- 37: 'left',
36
- 39: 'right',
37
- 38: 'up',
38
- 40: 'down',
39
- 13: 'enter',
40
- 32: 'space',
41
- 8: 'back',
42
- 27: 'escape',
43
- }
25
+ /**
26
+ * Merged keyMap (default + custom settings).
27
+ * Initialized once during application init.
28
+ * @type {Object<string, string>}
29
+ */
30
+ export let keyMap = {}
44
31
 
32
+ const Application = (config) => {
45
33
  config.hooks = config.hooks || {}
46
34
 
47
35
  let keyDownHandler
@@ -63,7 +51,8 @@ const Application = (config) => {
63
51
  if (announcerOptions && typeof announcerOptions === 'object') {
64
52
  this.$announcer.configure(announcerOptions)
65
53
  }
66
- const keyMap = { ...defaultKeyMap, ...Settings.get('keymap', {}) }
54
+ // Initialize merged keyMap once during application init
55
+ keyMap = { ...DEFAULT_KEYMAP, ...Settings.get('keymap', {}) }
67
56
 
68
57
  /** @type {number} Input throttle time in milliseconds (0 = disabled) */
69
58
  const throttleMs = Settings.get('inputThrottle', 0)
@@ -17,11 +17,13 @@
17
17
 
18
18
  import symbols from '../../lib/symbols.js'
19
19
  import Focus from '../../focus.js'
20
+ import { keyUpCallbacks, getComponentWithInputEvent } from '../../focus.js'
20
21
  import eventListeners from '../../lib/eventListeners.js'
21
22
  import { trigger } from '../../lib/reactivity/effect.js'
22
23
  import { Log } from '../../lib/log.js'
23
24
  import { removeGlobalEffects } from '../../lib/reactivity/effect.js'
24
25
  import { renderer } from '../../launch.js'
26
+ import { keyMap } from '../../application.js'
25
27
 
26
28
  export default {
27
29
  focus: {
@@ -51,6 +53,41 @@ export default {
51
53
  enumerable: true,
52
54
  configurable: false,
53
55
  },
56
+ $input: {
57
+ /**
58
+ * Handle a keyboard event on this component without changing focus
59
+ * @this {import('../../component').BlitsComponent}
60
+ * @param {KeyboardEvent} event - The keyboard event to handle
61
+ * @returns {boolean} - Returns true if this component or a parent component handled the event, false otherwise
62
+ */
63
+ value: function (event) {
64
+ if (event === null || event === undefined || event instanceof KeyboardEvent === false)
65
+ return false
66
+
67
+ const key = keyMap[event.key] || keyMap[event.keyCode] || event.key || event.keyCode
68
+
69
+ const componentWithInputEvent = getComponentWithInputEvent(this, key)
70
+ if (componentWithInputEvent === null) return false
71
+
72
+ const inputEvents = componentWithInputEvent[symbols.inputEvents] || {}
73
+
74
+ let cb
75
+ if (inputEvents[key]) {
76
+ cb = inputEvents[key].call(componentWithInputEvent, event)
77
+ } else if (inputEvents.any) {
78
+ cb = inputEvents.any.call(componentWithInputEvent, event)
79
+ }
80
+
81
+ if (cb !== undefined && event.code) {
82
+ keyUpCallbacks.set(event.code, cb)
83
+ }
84
+
85
+ return true
86
+ },
87
+ writable: false,
88
+ enumerable: true,
89
+ configurable: false,
90
+ },
54
91
  unfocus: {
55
92
  /**
56
93
  * @this {import('../../component').BlitsComponent}
@@ -121,15 +121,20 @@ export default () =>
121
121
  // Resolve frame data from sprite map
122
122
  let options = null
123
123
  if (
124
- this.map !== undefined &&
125
124
  this.map !== null &&
126
- this.frame !== undefined &&
127
- this.frame !== null
125
+ this.map !== undefined &&
126
+ this.frame !== null &&
127
+ this.frame !== undefined
128
128
  ) {
129
- options =
130
- 'frames' in this.map
131
- ? Object.assign({}, this.map.defaults || {}, this.map.frames[this.frame])
132
- : this.map[this.frame]
129
+ if (
130
+ this.map.frames !== null &&
131
+ this.map.frames !== undefined &&
132
+ this.frame in this.map.frames
133
+ ) {
134
+ options = Object.assign({}, this.map.defaults || {}, this.map.frames[this.frame])
135
+ } else if (this.frame in this.map) {
136
+ options = this.map[this.frame]
137
+ }
133
138
  }
134
139
 
135
140
  // If no map but frame is object (manual subtexture)
package/src/constants.js CHANGED
@@ -1,5 +1,24 @@
1
1
  export const DEFAULT_HOLD_TIMEOUT_MS = 50
2
2
 
3
+ export const DEFAULT_KEYMAP = {
4
+ ArrowLeft: 'left',
5
+ ArrowRight: 'right',
6
+ ArrowUp: 'up',
7
+ ArrowDown: 'down',
8
+ Enter: 'enter',
9
+ ' ': 'space',
10
+ Backspace: 'back',
11
+ Escape: 'escape',
12
+ 37: 'left',
13
+ 39: 'right',
14
+ 38: 'up',
15
+ 40: 'down',
16
+ 13: 'enter',
17
+ 32: 'space',
18
+ 8: 'back',
19
+ 27: 'escape',
20
+ }
21
+
3
22
  export const SCREEN_RESOLUTIONS = {
4
23
  hd: 0.66666667,
5
24
  '720p': 0.66666667,
@@ -168,7 +168,7 @@ const isObjectString = (str) => {
168
168
  * @returns {object} The parsed object.
169
169
  */
170
170
  const parseToObject = (str) => {
171
- return JSON.parse(str.replace(/'/g, '"').replace(/([\w-_]+)\s*:/g, '"$1":'))
171
+ return JSON.parse(str.replace(/'/g, '"').replace(/([{,]\s*)([\w-_]+)(\s*:)/g, '$1"$2"$3'))
172
172
  }
173
173
 
174
174
  /**
@@ -276,7 +276,13 @@ const propsTransformer = {
276
276
  }
277
277
  },
278
278
  set src(v) {
279
- this.props['src'] = v
279
+ if (typeof v === 'object' || (isObjectString(v) === true && (v = parseToObject(v)))) {
280
+ this.props['src'] = v.src
281
+ this.props['imageType'] = v.type
282
+ } else {
283
+ this.props['src'] = v
284
+ }
285
+
280
286
  if (this.raw['color'] === undefined) {
281
287
  this.props['color'] = this.props['src'] ? 0xffffffff : 0x00000000
282
288
  }
@@ -374,10 +380,21 @@ const propsTransformer = {
374
380
  }
375
381
  },
376
382
  set shader(v) {
377
- if (v !== null) {
378
- this.props['shader'] = renderer.createShader(v.type, v.props)
379
- } else {
380
- this.props['shader'] = renderer.createShader('DefaultShader')
383
+ const target = this.element.node !== undefined ? this.element.node : this.props
384
+
385
+ if (v === null) {
386
+ target['shader'] = null
387
+ return
388
+ }
389
+
390
+ if (typeof v === 'object' || (isObjectString(v) === true && (v = parseToObject(v)))) {
391
+ if (target.shader !== undefined && target.shader.type === v.type) {
392
+ for (const prop in v.props) {
393
+ target.shader.props[prop] = v.props[prop]
394
+ }
395
+ return
396
+ }
397
+ target['shader'] = renderer.createShader(v.type, v.props)
381
398
  }
382
399
  },
383
400
  set effects(v) {
package/src/focus.js CHANGED
@@ -118,7 +118,7 @@ const getAncestors = (components) => {
118
118
  * @param {String} key
119
119
  * @returns component
120
120
  */
121
- const getComponentWithInputEvent = (component, key) => {
121
+ export const getComponentWithInputEvent = (component, key) => {
122
122
  if (
123
123
  component[symbols.inputEvents] &&
124
124
  (typeof component[symbols.inputEvents][key] === 'function' ||
@@ -409,7 +409,7 @@ const generateForLoopCode = function (templateObject, parent) {
409
409
  .replace(')', '')
410
410
  .split(/\s*,\s*/)
411
411
 
412
- const scopeRegex = new RegExp(`(scope\\.(?!${item}\\.|${index}|key)(\\w+))`, 'gi')
412
+ const scopeRegex = new RegExp(`(scope\\.(?!${item}\\.|${index}|key)([\\w$]+))`, 'gi')
413
413
 
414
414
  // local context
415
415
  const ctx = {
@@ -17,6 +17,7 @@
17
17
 
18
18
  import parser from '../templateparser/parser.js'
19
19
  import generator from '../codegenerator/generator.js'
20
+ import MagicString from 'magic-string'
20
21
 
21
22
  export default (source, filePath, mode) => {
22
23
  if (
@@ -26,12 +27,9 @@ export default (source, filePath, mode) => {
26
27
  /\{.*?template\s*:\s*(['"`])((?:\\?.)*?)\1.*?\}/s.test(source) // object with template key
27
28
  ) {
28
29
  const templates = source.matchAll(/(?<!\/\/\s*)template\s*:\s*(['"`])((?:\\?.)*?)\1/gs)
29
- let newSource = source
30
- /*
31
- if there are multiple templates in the file, we need to keep
32
- track of the offset caused by the previous replacements
33
- */
34
- let offset = 0
30
+
31
+ // Use MagicString to track changes
32
+ const s = new MagicString(source)
35
33
 
36
34
  for (const template of templates) {
37
35
  if (template[2]) {
@@ -39,7 +37,8 @@ export default (source, filePath, mode) => {
39
37
 
40
38
  // Only process if it looks like a Blits template
41
39
  if (templateContent.match(/^\s*(<!--[\s\S]*?-->|<[A-Za-z][^>]*>)/s)) {
42
- const templateStartIndex = template.index + offset
40
+ // Use original indices - MagicString handles position tracking automatically
41
+ const templateStartIndex = template.index
43
42
  const templateEndIndex = templateStartIndex + template[0].length
44
43
 
45
44
  // Parse the template
@@ -58,16 +57,26 @@ export default (source, filePath, mode) => {
58
57
  (fn) => fn.toString()
59
58
  )}], context: {}}`
60
59
 
61
- offset += replacement.length - template[0].length
62
-
63
- newSource =
64
- newSource.substring(0, templateStartIndex) +
65
- replacement +
66
- newSource.substring(templateEndIndex)
60
+ // MagicString tracks all changes automatically, no offset needed
61
+ s.overwrite(templateStartIndex, templateEndIndex, replacement)
67
62
  }
68
63
  }
69
64
  }
70
- return newSource
65
+
66
+ const newSource = s.toString()
67
+
68
+ if (newSource !== source) {
69
+ const fileName = filePath.split(/[\\/]/).pop()
70
+ return {
71
+ code: newSource,
72
+ map: s.generateMap({
73
+ hires: true,
74
+ source: fileName,
75
+ includeContent: true,
76
+ file: fileName,
77
+ }),
78
+ }
79
+ }
71
80
  }
72
81
  return source
73
82
  }
@@ -213,7 +213,12 @@ export default (code) => {
213
213
  modifiedCode = modifiedCode.replace(mod.original, mod.replacement)
214
214
  }
215
215
 
216
- return { code: modifiedCode }
216
+ // Returning code without a source map
217
+ // Vite will automatically chain this with the next plugin's source map (preCompiler)
218
+ return {
219
+ code: modifiedCode,
220
+ map: { mappings: '' },
221
+ }
217
222
  }
218
223
 
219
224
  return null
@@ -0,0 +1,29 @@
1
+ /*
2
+ * Copyright 2024 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 type { AppStatePlugin } from '@lightningjs/blits'
19
+
20
+ // Re-export AppStatePlugin for direct imports
21
+ export type { AppStatePlugin }
22
+
23
+ declare const appState: {
24
+ readonly name: 'appState'
25
+ plugin: <TState extends Record<string, unknown>>(state?: TState) => AppStatePlugin<TState>
26
+ }
27
+
28
+ export default appState
29
+
@@ -0,0 +1,29 @@
1
+ /*
2
+ * Copyright 2024 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 as language } from './language.js'
19
+ export { default as theme } from './theme.js'
20
+ export { default as appState } from './appstate.js'
21
+ export { default as storage } from './storage/storage.js'
22
+
23
+ // Re-export plugin interfaces for convenience
24
+ export type { LanguagePlugin, ThemePlugin, StoragePlugin, AppStatePlugin } from '@lightningjs/blits'
25
+
26
+ // Re-export option types
27
+ export type { LanguagePluginOptions } from './language.js'
28
+ export type { ThemePluginConfig } from './theme.js'
29
+
@@ -0,0 +1,34 @@
1
+ /*
2
+ * Copyright 2024 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 type { LanguagePlugin } from '@lightningjs/blits'
19
+
20
+ export interface LanguagePluginOptions {
21
+ file?: string
22
+ language?: string
23
+ }
24
+
25
+ // Re-export LanguagePlugin for direct imports
26
+ export type { LanguagePlugin }
27
+
28
+ declare const language: {
29
+ readonly name: 'language'
30
+ plugin: (options?: LanguagePluginOptions) => LanguagePlugin
31
+ }
32
+
33
+ export default language
34
+
@@ -0,0 +1,29 @@
1
+ /*
2
+ * Copyright 2024 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 type { StoragePlugin } from '@lightningjs/blits'
19
+
20
+ // Re-export StoragePlugin for direct imports
21
+ export type { StoragePlugin }
22
+
23
+ declare const storage: {
24
+ readonly name: 'storage'
25
+ plugin: () => StoragePlugin
26
+ }
27
+
28
+ export default storage
29
+
@@ -0,0 +1,35 @@
1
+ /*
2
+ * Copyright 2024 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 type { ThemePlugin } from '@lightningjs/blits'
19
+
20
+ export interface ThemePluginConfig {
21
+ themes?: Record<string, Record<string, unknown>>
22
+ current?: string
23
+ base?: string
24
+ }
25
+
26
+ // Re-export ThemePlugin for direct imports
27
+ export type { ThemePlugin }
28
+
29
+ declare const theme: {
30
+ readonly name: 'theme'
31
+ plugin: (config?: ThemePluginConfig | Record<string, unknown>) => ThemePlugin
32
+ }
33
+
34
+ export default theme
35
+
@@ -32,12 +32,22 @@ export default function () {
32
32
 
33
33
  // we should only precompile .blits, .js and .ts files
34
34
  if (
35
- fileExtension === '.js' ||
36
- fileExtension === '.ts' ||
37
- fileExtension === '.blits' ||
38
- fileExtension === '.mjs'
35
+ filePath.indexOf('node_modules') === -1 &&
36
+ (fileExtension === '.js' ||
37
+ fileExtension === '.ts' ||
38
+ fileExtension === '.blits' ||
39
+ fileExtension === '.mjs')
39
40
  ) {
40
- return compiler(source, filePath, config.mode)
41
+ const result = compiler(source, filePath, config.mode)
42
+
43
+ if (typeof result === 'object') {
44
+ return {
45
+ code: result.code,
46
+ map: result.map,
47
+ }
48
+ }
49
+ // No transformation needed - return null so Vite knows no changes were made
50
+ return null
41
51
  }
42
52
 
43
53
  // vite expects null if there is no modification