@lightningjs/blits 1.29.1 → 1.29.3

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
+ _03 jun 2025_
4
+
5
+ ## v1.29.3
6
+
7
+ - Added first batch internal JS doc types
8
+ - Added documentation on Launch settings
9
+ - Fixed issue with reactivity effects being shared (and retained) on the prototype
10
+
11
+ _28 may 2025_
12
+
13
+ ## v1.29.2
14
+
15
+ - Added end of life flag to prevent timers, intervals and listeners to be registered after component destroy
16
+
3
17
  _22 may 2025_
4
18
 
5
19
  ## v1.29.1
@@ -0,0 +1,117 @@
1
+ # Application Settings
2
+
3
+ Blits provides a flexible and performant way to configure your application at launch using the settings object passed to `Blits.Launch`. These settings allow you to fine-tune rendering, performance, input, fonts, and more.
4
+
5
+ Below is a comprehensive overview of the available settings you can provide to a Blits Application:
6
+
7
+ ## Basic Settings
8
+
9
+ | Setting | Type | Description |
10
+ |----------------|---------------------|-------------|
11
+ | `w` | `number` | Width of the application (canvas) |
12
+ | `h` | `number` | Height of the application (canvas) |
13
+ | `debugLevel` | `number \| string[]`| Debug level for console log messages |
14
+ | `multithreaded`| `boolean` | Enable multithreaded rendering |
15
+
16
+ ## Fonts & Text
17
+
18
+ | Setting | Type | Description |
19
+ |----------------|-----------|-------------|
20
+ | `fonts` | `Font[]` | Array of font objects to register |
21
+ | `defaultFont` | `string` | Default font family to use |
22
+
23
+ Example font object:
24
+ ```js
25
+ {
26
+ family: 'lato',
27
+ type: 'msdf', // or 'web'
28
+ file: 'fonts/Lato-Regular.ttf',
29
+ }
30
+ ```
31
+
32
+ ## Rendering & Performance
33
+
34
+ | Setting | Type | Description |
35
+ |----------------|-----------|-------------|
36
+ | `renderQuality` | `'low' \| 'medium' \| 'high' \| 'retina' \| number` | Controls render quality (1 = 100%) |
37
+ | `screenResolution` | `'hd' \| 'fhd' \| '4k' \| number` | Sets device screen resolution |
38
+ | `pixelRatio` | `number` | Custom pixel ratio (overrides screenResolution) |
39
+ | `canvasColor` | `string` | Background color of the canvas |
40
+ | `fpsInterval` | `number` | Interval (ms) for FPS updates (0 disables) |
41
+ | `webWorkersLimit` | `number`| Max number of web workers for image handling |
42
+ | `gpuMemory` | `object` | GPU memory management (see below) |
43
+ | `gpuMemoryLimit`| `number` | (Deprecated) Use `gpuMemory` instead |
44
+ | `textureProcessingTimeLimit` | `number` | Max ms per frame for texture processing |
45
+ | `viewportMargin`| `number \| [number,number,number,number]` | Extra margin for preloading elements |
46
+ | `advanced` | `object` | Advanced renderer settings (use with care) |
47
+
48
+ ### GPU Memory Example
49
+ ```js
50
+ {
51
+ max: 200, // MB
52
+ target: 0.8, // 80% of max
53
+ cleanupInterval: 5000, // ms
54
+ baseline: 25, // MB
55
+ strict: false
56
+ }
57
+ ```
58
+
59
+ ## Input & Focus
60
+
61
+ | Setting | Type | Description |
62
+ |----------------|-----------|-------------|
63
+ | `keymap` | `object` | Custom key mapping for input events |
64
+ | `holdTimeout` | `number` | Time (ms) to consider a key press as hold |
65
+
66
+ ## Renderer
67
+
68
+ | Setting | Type | Description |
69
+ |----------------|-----------|-------------|
70
+ | `renderMode` | `'webgl' \| 'canvas'` | Renderer mode (default: 'webgl') |
71
+ | `canvas` | `HTMLCanvasElement` | Custom canvas to render to |
72
+
73
+ ## Effects & Shaders
74
+
75
+ | Setting | Type | Description |
76
+ |----------------|-----------|-------------|
77
+ | `effects` | `ShaderEffect[]` | Effects for DynamicShader |
78
+ | `shaders` | `Shader[]` | Custom shaders |
79
+
80
+ ## Inspector & Debugging
81
+
82
+ | Setting | Type | Description |
83
+ |----------------|-----------|-------------|
84
+ | `inspector` | `boolean` | Enable the inspector tool |
85
+
86
+ ## Accessibility
87
+
88
+ | Setting | Type | Description |
89
+ |----------------|-----------|-------------|
90
+ | `announcer` | `boolean` | Enable/disable text-to-speech announcer |
91
+
92
+ ## Example Usage
93
+
94
+ ```js
95
+ Blits.Launch(App, 'app', {
96
+ w: 1920,
97
+ h: 1080,
98
+ debugLevel: 1,
99
+ renderQuality: 'high',
100
+ fonts: [
101
+ { family: 'lato', type: 'msdf', file: 'fonts/Lato-Regular.ttf' },
102
+ ],
103
+ keymap: {
104
+ ArrowLeft: 'left',
105
+ ArrowRight: 'right',
106
+ },
107
+ gpuMemory: {
108
+ max: 200,
109
+ target: 0.8,
110
+ cleanupInterval: 5000,
111
+ baseline: 25,
112
+ strict: false,
113
+ },
114
+ inspector: false,
115
+ announcer: true,
116
+ })
117
+ ```
package/docs/sidebar.json CHANGED
@@ -42,6 +42,10 @@
42
42
  {
43
43
  "text": "Displaying text",
44
44
  "link": "/essentials/displaying_text"
45
+ },
46
+ {
47
+ "text": "Application settings",
48
+ "link": "/essentials/settings"
45
49
  }
46
50
  ]
47
51
  },
package/jsconfig.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "allowJs": true,
6
+ "checkJs": true,
7
+ "moduleResolution": "node",
8
+ "baseUrl": "./"
9
+ },
10
+ "include": ["src"],
11
+ "exclude": ["node_modules"]
12
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightningjs/blits",
3
- "version": "1.29.1",
3
+ "version": "1.29.3",
4
4
  "description": "Blits: The Lightning 3 App Development Framework",
5
5
  "bin": "bin/index.js",
6
6
  "exports": {
@@ -18,6 +18,13 @@
18
18
  import eventListeners from '../../lib/eventListeners.js'
19
19
 
20
20
  export default {
21
+ /**
22
+ * Emits an event to all registered listeners for the given event name.
23
+ *
24
+ * @param {string} event - The name of the event to emit.
25
+ * @param {any} params - The parameters to pass to the event listeners.
26
+ * @returns {boolean} True if all listeners executed, false otherwise.
27
+ */
21
28
  $emit: {
22
29
  value: function (event, params) {
23
30
  // returning if all listeners executed
@@ -27,14 +34,30 @@ export default {
27
34
  enumerable: true,
28
35
  configurable: false,
29
36
  },
37
+ /**
38
+ * Registers a listener callback for a specific event.
39
+ *
40
+ * @param {string} event - The name of the event to listen for.
41
+ * @param {Function} callback - The callback function to execute when the event is emitted.
42
+ * @param {number} [priority=0] - The priority of the listener (higher runs first).
43
+ * @returns {void}
44
+ */
30
45
  $listen: {
31
46
  value: function (event, callback, priority = 0) {
47
+ // early exit when component is marked as end of life
48
+ if (this.eol === true) return
32
49
  eventListeners.registerListener(this, event, callback, priority)
33
50
  },
34
51
  writable: false,
35
52
  enumerable: true,
36
53
  configurable: false,
37
54
  },
55
+ /**
56
+ * Deregisters a listener for a specific event.
57
+ *
58
+ * @param {string} event - The name of the event to stop listening for.
59
+ * @returns {void}
60
+ */
38
61
  $unlisten: {
39
62
  value: function (event) {
40
63
  eventListeners.deregisterListener(this, event)
@@ -24,6 +24,9 @@ import { removeGlobalEffects } from '../../lib/reactivity/effect.js'
24
24
 
25
25
  export default {
26
26
  focus: {
27
+ /**
28
+ * @this {import('../../component').BlitsComponent}
29
+ */
27
30
  value: function (e) {
28
31
  Log.warn('this.focus is deprecated, use this.$focus instead')
29
32
  return this.$focus(e)
@@ -33,6 +36,9 @@ export default {
33
36
  configurable: false,
34
37
  },
35
38
  $focus: {
39
+ /**
40
+ * @this {import('../../component').BlitsComponent}
41
+ */
36
42
  value: function (e) {
37
43
  this[symbols.state].hasFocus = true
38
44
  Focus.set(this, e)
@@ -42,6 +48,9 @@ export default {
42
48
  configurable: false,
43
49
  },
44
50
  unfocus: {
51
+ /**
52
+ * @this {import('../../component').BlitsComponent}
53
+ */
45
54
  value: function () {
46
55
  this[symbols.state].hasFocus = false
47
56
  this.lifecycle.state = 'unfocus'
@@ -51,7 +60,11 @@ export default {
51
60
  configurable: false,
52
61
  },
53
62
  destroy: {
63
+ /**
64
+ * @this {import('../../component').BlitsComponent}
65
+ */
54
66
  value: function () {
67
+ this.eol = true
55
68
  this.lifecycle.state = 'destroy'
56
69
  this.$clearTimeouts()
57
70
  this.$clearIntervals()
@@ -93,6 +106,9 @@ export default {
93
106
  configurable: false,
94
107
  },
95
108
  [symbols.removeGlobalEffects]: {
109
+ /**
110
+ * @this {import('../../component').BlitsComponent}
111
+ */
96
112
  value: function (effects = []) {
97
113
  removeGlobalEffects(effects)
98
114
  },
@@ -101,6 +117,9 @@ export default {
101
117
  configurable: false,
102
118
  },
103
119
  select: {
120
+ /**
121
+ * @this {import('../../component').BlitsComponent}
122
+ */
104
123
  value: function (ref) {
105
124
  Log.warn('this.select is deprecated, use this.$select instead')
106
125
  return this.$select(ref)
@@ -110,6 +129,9 @@ export default {
110
129
  configurable: false,
111
130
  },
112
131
  $select: {
132
+ /**
133
+ * @this {import('../../component').BlitsComponent}
134
+ */
113
135
  value: function (ref) {
114
136
  let selected = null
115
137
  this[symbols.children].forEach((child) => {
@@ -132,6 +154,9 @@ export default {
132
154
  configurable: false,
133
155
  },
134
156
  trigger: {
157
+ /**
158
+ * @this {import('../../component').BlitsComponent}
159
+ */
135
160
  value: function (key) {
136
161
  Log.warn('this.trigger is deprecated, use this.$trigger instead')
137
162
  return this.$trigger(key)
@@ -141,6 +166,9 @@ export default {
141
166
  configurable: false,
142
167
  },
143
168
  $trigger: {
169
+ /**
170
+ * @this {import('../../component').BlitsComponent}
171
+ */
144
172
  value: function (key) {
145
173
  let target = this[symbols.originalState]
146
174
  // when dot notation used, find the nested target
@@ -159,6 +187,9 @@ export default {
159
187
  configurable: false,
160
188
  },
161
189
  shader: {
190
+ /**
191
+ * @this {import('../../component').BlitsComponent}
192
+ */
162
193
  value: function (type, args) {
163
194
  return {
164
195
  type: type,
@@ -181,6 +212,10 @@ export default {
181
212
  },
182
213
  }
183
214
 
215
+ /**
216
+ * Recursively destroys all BlitsComponent children.
217
+ * @param {import('../../component').BlitsComponent[]} children
218
+ */
184
219
  const deleteChildren = function (children) {
185
220
  for (let i = 0; i < children.length; i++) {
186
221
  if (!children[i]) return
@@ -20,6 +20,8 @@ import symbols from '../../lib/symbols.js'
20
20
  export default {
21
21
  $setTimeout: {
22
22
  value: function (fn, ms, ...params) {
23
+ // early exit when component is marked as end of life
24
+ if (this.eol === true) return
23
25
  const timeoutId = setTimeout(
24
26
  () => {
25
27
  this[symbols.timeouts] = this[symbols.timeouts].filter((id) => id !== timeoutId)
@@ -59,6 +61,8 @@ export default {
59
61
  },
60
62
  $setInterval: {
61
63
  value: function (fn, ms, ...params) {
64
+ // early exit when component is marked as end of life
65
+ if (this.eol === true) return
62
66
  const intervalId = setInterval(() => fn.apply(null, params), ms, params)
63
67
  this[symbols.intervals].push(intervalId)
64
68
  return intervalId
@@ -32,8 +32,6 @@ let counter = 0
32
32
  export default function (component, config) {
33
33
  component[symbols.identifier] = ++counter
34
34
 
35
- component[symbols.effects] = []
36
-
37
35
  // setup hooks
38
36
  registerHooks(config.hooks, component[symbols.identifier])
39
37
 
package/src/component.js CHANGED
@@ -43,12 +43,150 @@ const required = (name) => {
43
43
  throw new Error(`Parameter ${name} is required`)
44
44
  }
45
45
 
46
+ /**
47
+ * @typedef {function} BlitsComponentFactory
48
+ * @param {object} opts - The options for the component instance
49
+ * @param {BlitsComponent} parentEl - The parent element for the component instance
50
+ * @param {BlitsComponent} parentComponent - The parent component for the component instance
51
+ * @param {BlitsComponent} rootComponent - The root component for the component instance
52
+ * @returns {BlitsComponent} - The component instance
53
+ */
54
+
55
+ /**
56
+ * Structure of a Blits component:
57
+ * Component:
58
+ * <Holder>
59
+ * <Wrapper>
60
+ * []<Elements>
61
+ * </Wrapper>
62
+ * </Holder>
63
+ *
64
+ * A Blits Element
65
+ * @typedef {Object} BlitsAnnouncer
66
+ * @property {(message: string) => void} assertive - Function to assertively announce a message.
67
+ * @property {() => void} clear - Function to clear the announcer.
68
+ * @property {() => void} disable - Function to disable the announcer.
69
+ * @property {() => void} enable - Function to enable the announcer.
70
+ * @property {(delay: number) => void} pause - Function to pause the announcer.
71
+ * @property {(message: string) => void} polite - Function to politely announce a message.
72
+ * @property {(message: string, politeness: 'off'|'polite'|'assertive') => void} announce - Function to announce a message with specified politeness.
73
+ * @property {() => void} stop - Function to stop the announcer.
74
+ * @property {(v: boolean) => void} toggle - Function to toggle the announcer.
75
+ *
76
+ * @typedef {Object} BlitsElementConfig
77
+ * @property {BlitsElement} parent - The parent element of this element.
78
+ * @property {any} node - The node object for the element.
79
+ *
80
+ * @typedef {Object} BlitsElementProps
81
+ * @property {boolean} __textnode - Indicates if the element is a text node.
82
+ * @property {boolean} __layout - Indicates if the element is a layout node.
83
+ * @property {BlitsElement} element - The element to which the props belong?? Do we need this?
84
+ * @property {BlitsElementConfig} config - Configuration object for the element.
85
+ * @property {Object<string, any>} props - The props object containing the properties of the element.
86
+ * @property {Object<string, any>} raw - The raw input props.
87
+ * @property {Object<string, any>} scheduledTransitions - Tracks transitions by property name.
88
+ *
89
+ * @typedef {Object} BlitsElement
90
+ * @property {BlitsComponent} component - Reference to the owning Blits component.
91
+ * @property {BlitsElementConfig} config - Configuration object for the element.
92
+ * @property {number} counter - Unique counter used for shader workarounds. FIXME?
93
+ * @property {string[]} effectNames - Names of active shader effects.
94
+ * @property {any} node - The underlying renderer node (e.g., WebGL node or text node).
95
+ * @property {BlitsElementProps} props - Proxy-like object containing transformed props.
96
+ * @property {any[]} children - WVB I cant see this populated? Filtered list of children owned by this element. FIXME?
97
+ * @property {any} parent - WVB Shortcut to the parent CoreNode?
98
+ * @property {number} nodeId - ID of the CoreNode, if available.
99
+ * @property {string|null} ref - Ref name (if defined).
100
+ * @property {function(Object):void} populate - Initializes the element with props and hooks.
101
+ * @property {function(string, any):void} set - Updates a single property.
102
+ * @property {function(string, any, Object):void} animate - Animates a property with transition options.
103
+ * @property {function():void} destroy - Destroys the underlying node and cancels transitions.
104
+ * @property {function(any): any} triggerLayout - Triggers a layout update for the element.
105
+ *
106
+ * @typedef {Object} BlitsLifecycle
107
+ * @property {BlitsComponent} component - The Blits comonent instance this lifecycle belongs to.
108
+ * @property {'init'|'ready'|'destroyed'} current - The current lifecycle state of the component.
109
+ * @property {'init'|'ready'|'destroyed'|null} previous - The previous lifecycle state of the component.
110
+ * @property {string} state - The current lifecycle state of the component.
111
+ *
112
+ * @typedef {object} BlitsComponent
113
+ * Main properties of the Blits component:
114
+ * @property {string} componentId - The unique identifier for the component instance
115
+ * @property {BlitsLifecycle} lifecycle - The lifecycle object for the component instance
116
+ * @property {BlitsComponent} parent - The parent component of the current component instance
117
+ * @property {BlitsComponent} rootParent - Reference to the root component in case of slots, otherwise this is the same as parent
118
+ * @property {BlitsComponent|BlitsElement[]} [children] - The children of the component instance
119
+ * @property {BlitsElement} [holder] - The wrapper of the entire component instance
120
+ * @property {number} [id] - The internal ID for the component instance
121
+ * @property {number} [identifier] - The identifier for the component instance WVB Whats the difference with id?
122
+ * @property {any[]} [intervals] - The intervals created by the component instance WVB Fixme
123
+ * @property {Object<string, any>} [originalState] - The original state of the component instance
124
+ * @property {Object<string, any>} [props] - The reactive properties of the component instance
125
+ * @property {any[]} [slots] - The slots of the component instance WVB Fixme
126
+ * @property {Object<string, any>} [state] - The reactive state of the component instance
127
+ * @property {any[]} [timeouts] - The timeouts created by the component instance
128
+ * @property {BlitsElement} [wrapper] - The reference to the outer element of the component instance
129
+ * @property {object} [effects] - The effects of the component instance
130
+ * @property {object} [watchers] - The watchers of the component instance
131
+ * @property {Object<string, any>} computedKeys - The computed keys of the component instance
132
+ * @property {any[]} [effects] - The effects of the component instance
133
+ * @property {string[]} [propKeys] - The keys of the props of the component instance
134
+ * @property {any[]} [stateKeys] - The keys of the state of the component instance
135
+ * Single props:
136
+ * @property {object} activeView - The active view of the component instance
137
+ * @property {boolean} hasFocus - Indicates if the component has focus
138
+ * @property {string} ref - The reference name of the component instance
139
+ * @property {number|undefined} index - The index in a for loop
140
+ * @property {number|undefined} activeRow - The active row in a for loop
141
+ * @property {string} color - The color of the component instance
142
+ * @property {number} radius - The radius of the component instance
143
+ * @property {number} size - The size of the component instance
144
+ * Methods:
145
+ * @property {function(): void} destroy - Destroys the component and its children, clearing listeners and effects.
146
+ * @property {function(any): any} focus - ⚠️ Deprecated. Use `$focus()` instead.
147
+ * @property {function(string): any} select - ⚠️ Deprecated. Use `$select(ref)` instead.
148
+ * @property {function(string, object): {type: string, props: object}} shader - Creates a shader definition object.
149
+ * @property {function(string): void} trigger - ⚠️ Deprecated. Use `$trigger(key)` instead.
150
+ * @property {function(): void} unfocus - Clears the focus state and sets lifecycle to 'unfocus'.
151
+ * Builtins:
152
+ * @property {BlitsAnnouncer} $announcer - The announcer object for the component instance
153
+ * @property {() => void} $clearTimeouts - Clears all timeouts created by the component instance
154
+ * @property {(timeoutId: number) => void} $clearTimeout - Clears all timeouts created by the component instance
155
+ * @property {() => void} $clearIntervals - Clears all intervals created by the component instance
156
+ * @property {(intervalId: number) => void} $clearInterval - Clears all intervals created by the component instance
157
+ * @property {Object} $colors - The colors object for the component instance
158
+ * @property {(event: string, params: object) => void} $emit - Emits an event with the specified parameters
159
+ * @property {function(any): void} $focus - Sets the component focus state and delegates to the Focus manager.
160
+ * @property {Object} $language - The language object for the component instance
161
+ * @property {function(any): any} $listen - The listen object for the component instance
162
+ * @property {Object} $log - The log object for the component instance
163
+ * @property {Object} $router - The router object for the component instance
164
+ * @property {function(string): any} $select - Selects a child component by `ref`.
165
+ * @property {function(any): any} $setInterval - Sets an interval for the component instance
166
+ * @property {function(any): any} $setTimeout - Sets a timeout for the component instance
167
+ * @property {function(any): any} $size - The size object for the component instance
168
+ * @property {function(any): any} $sizes - The sizes object for the component instance
169
+ * @property {function(string): void} $trigger - Forces a reactivity trigger on a property in `originalState`.
170
+ * @property {function(any): any} $unlisten - The unlisten object for the component instance
171
+ *
172
+ */
173
+
174
+ /**
175
+ * @typedef {Object} BlitsComponentConfig
176
+ * @property {string} template - The template string for the component.
177
+ * @property {function(this: BlitsComponent): Object} [state] - State factory function.
178
+ * @property {Object} [hooks] - Lifecycle hooks (frameTick, idle, attach, detach, enter, exit, etc).
179
+ * @property {Object} [code] - Compiled render/effects code (render: Function, effects: Function[]).
180
+ * @property {string} [name] - Optional name for the component.
181
+ * @property {any} [data] - Optional static data for the component.
182
+ * @property {Object} [options] - Optional options for the component.
183
+ */
184
+
46
185
  /**
47
186
  * Component factory function
48
187
  * @param {string} name - The name of the component
49
- * @param {object} config - The configuration object for the component
50
- * @returns {function} - A factory function that creates a new component instance
51
- *
188
+ * @param {BlitsComponentConfig} config - The configuration object for the component
189
+ * @returns {BlitsComponentFactory} - The component factory function
52
190
  */
53
191
  const Component = (name = required('name'), config = required('config')) => {
54
192
  let base = undefined
@@ -167,6 +305,7 @@ const Component = (name = required('name'), config = required('config')) => {
167
305
  // setup (and execute) all the generated side effects based on the
168
306
  // reactive bindings define in the template
169
307
  const effects = config.code.effects
308
+ this[symbols.effects] = []
170
309
  for (let i = 0; i < effects.length; i++) {
171
310
  const eff = () => {
172
311
  effects[i](this, this[symbols.children], config, globalComponents, rootComponent, effect)
@@ -216,11 +355,21 @@ const Component = (name = required('name'), config = required('config')) => {
216
355
  return this
217
356
  }
218
357
 
358
+ /**
359
+ * Component factory function
360
+ * @typedef {BlitsComponentFactory}
361
+ * @param {Object} options
362
+ * @param {BlitsComponent} parentEl
363
+ * @param {BlitsComponent} parentComponent
364
+ * @param {BlitsComponent} rootComponent
365
+ * @returns {BlitsComponent}
366
+ */
219
367
  const factory = (options = {}, parentEl, parentComponent, rootComponent) => {
220
368
  if (Base[symbols['launched']] === false) {
221
369
  // Register user defined plugins once on the Base object (after launch)
222
370
  const pluginKeys = Object.keys(plugins)
223
371
  const pluginKeysLength = pluginKeys.length
372
+ /** @type {Object} */
224
373
  const pluginInstances = {}
225
374
  for (let i = 0; i < pluginKeysLength; i++) {
226
375
  const pluginName = pluginKeys[i]
@@ -25,6 +25,12 @@ import Settings from '../../settings.js'
25
25
  // temporary counter to work around shader caching issues
26
26
  let counter = 0
27
27
 
28
+ /**
29
+ * Creates a padding object from a value and direction.
30
+ * @param {number|object|string|undefined} padding - The padding value.
31
+ * @param {string} direction - The layout direction ('vertical' or 'horizontal').
32
+ * @returns {{start: number, end: number, oppositeStart: number, oppositeEnd: number}} The padding object.
33
+ */
28
34
  const createPaddingObject = (padding, direction) => {
29
35
  if (padding === undefined) {
30
36
  return { start: 0, end: 0, oppositeStart: 0, oppositeEnd: 0 }
@@ -67,6 +73,11 @@ const createPaddingObject = (padding, direction) => {
67
73
  return { start: 0, end: 0, oppositeStart: 0, oppositeEnd: 0 }
68
74
  }
69
75
 
76
+ /**
77
+ * Layout function for arranging children in a layout container.
78
+ * @param {object} config - The layout configuration object.
79
+ * @this {import('../../component.js').BlitsElement}
80
+ */
70
81
  const layoutFn = function (config) {
71
82
  const position = config.direction === 'vertical' ? 'y' : 'x'
72
83
  const oppositePosition = config.direction === 'vertical' ? 'x' : 'y'
@@ -135,18 +146,40 @@ const layoutFn = function (config) {
135
146
  }
136
147
  }
137
148
 
149
+ /**
150
+ * Checks if a value is a transition object.
151
+ * @param {any} value - The value to check.
152
+ * @returns {boolean} True if the value is a transition object, false otherwise.
153
+ */
138
154
  const isTransition = (value) => {
139
155
  return value !== null && typeof value === 'object' && 'transition' in value === true
140
156
  }
141
157
 
158
+ /**
159
+ * Checks if a string is an object string (starts and ends with curly braces).
160
+ * @param {string} str - The string to check.
161
+ * @returns {boolean} True if the string is an object string, false otherwise.
162
+ */
142
163
  const isObjectString = (str) => {
143
164
  return typeof str === 'string' && str.startsWith('{') && str.endsWith('}')
144
165
  }
145
166
 
167
+ /**
168
+ * Parses a string into an object, converting single quotes to double and adding quotes to keys.
169
+ * @param {string} str - The string to parse.
170
+ * @returns {object} The parsed object.
171
+ */
146
172
  const parseToObject = (str) => {
147
173
  return JSON.parse(str.replace(/'/g, '"').replace(/([\w-_]+)\s*:/g, '"$1":'))
148
174
  }
149
175
 
176
+ /**
177
+ * Parses a percentage string or returns the value as-is.
178
+ * @param {string|number} v - The value to parse (may be a percentage string).
179
+ * @param {string} base - The base property name ('width' or 'height').
180
+ * @returns {number|string} The parsed value as a number or the original value.
181
+ * @this {{ element: { config: { parent?: { node?: Record<string, number> } } } }}
182
+ */
150
183
  const parsePercentage = function (v, base) {
151
184
  if (typeof v !== 'string') {
152
185
  return v
@@ -160,6 +193,11 @@ const parsePercentage = function (v, base) {
160
193
  return v
161
194
  }
162
195
 
196
+ /**
197
+ * Unpacks a transition value from an object or returns the value as-is.
198
+ * @param {any} v - The value to unpack.
199
+ * @returns {any} The unpacked value.
200
+ */
163
201
  const unpackTransition = (v) => {
164
202
  if (typeof v !== 'object' || v === null) return v
165
203
  if (v.constructor === Object) {
@@ -180,8 +218,18 @@ const colorMap = {
180
218
  right: 'colorRight',
181
219
  }
182
220
 
221
+ /**
222
+ * Default text settings for text nodes (initialized on first use).
223
+ * @type {object|null}
224
+ */
183
225
  let textDefaults = null
184
226
 
227
+ /**
228
+ * @typedef {import('../../component.js').BlitsElement} BlitsElement
229
+ *
230
+ * This is always a BlitsElement
231
+ * @this {BlitsElement} this
232
+ */
185
233
  const propsTransformer = {
186
234
  set parent(v) {
187
235
  this.props['parent'] = v === 'root' ? renderer.root : v.node
@@ -448,6 +496,10 @@ const propsTransformer = {
448
496
  }
449
497
 
450
498
  const Element = {
499
+ /**
500
+ * Populates the element with data
501
+ * @param {import('../../component.js').BlitsElementProps} data
502
+ */
451
503
  populate(data) {
452
504
  const props = data
453
505
  props['node'] = this.config.node
@@ -459,6 +511,7 @@ const Element = {
459
511
  this.props.element = this
460
512
 
461
513
  this.props['parent'] = props['parent'] || this.config.parent
514
+ //@ts-ignore This might be a left over from the old code?
462
515
  delete props.parent
463
516
 
464
517
  this.props.raw = data
@@ -506,12 +559,24 @@ const Element = {
506
559
  })
507
560
  }
508
561
  },
562
+ /**
563
+ * Set an individual property on the node
564
+ *
565
+ * @this {import('../../component').BlitsElement} this
566
+ *
567
+ * @param {import('../..//component.js').BlitsElementProps} prop
568
+ * @param {any} value
569
+ * @returns {void}
570
+ */
509
571
  set(prop, value) {
510
572
  if (value === undefined) return
573
+ // @ts-ignore
511
574
  if (this.props.raw[prop] === value) return
575
+ // @ts-ignore
512
576
  this.props.raw[prop] = value
513
577
 
514
578
  this.props.props = {}
579
+ // @ts-ignore
515
580
  this.props[prop] = unpackTransition(value)
516
581
 
517
582
  const propsKeys = Object.keys(this.props.props)
@@ -654,6 +719,13 @@ const Element = {
654
719
  },
655
720
  }
656
721
 
722
+ /**
723
+ * Returns a new Blits Element
724
+ *
725
+ * @param {Object} config - The configuration object for the element
726
+ * @param {import('../../component.js').BlitsComponent} component - The component to which the element belongs
727
+ * @returns {import('../../component.js').BlitsElement} - The new Blits Element
728
+ */
657
729
  export default (config, component) => {
658
730
  if (textDefaults === null) {
659
731
  textDefaults = {
@@ -26,7 +26,8 @@ import colors from '../../lib/colors/colors.js'
26
26
  import fontLoader from './fontLoader.js'
27
27
  import shaderLoader from './shaderLoader.js'
28
28
 
29
- export let renderer = {}
29
+ /** @type {RendererMain|null} */
30
+ export let renderer = null
30
31
 
31
32
  const renderEngine = (settings) => {
32
33
  const renderMode = 'renderMode' in settings ? settings.renderMode : 'webgl'
@@ -63,6 +64,14 @@ const textureMemorySettings = (settings) => {
63
64
  }
64
65
  }
65
66
 
67
+ /**
68
+ * Launch the render engine and application
69
+ *
70
+ * @param {import('../../launch.js').BlitsAppFactory} App - Factory function that returns the application instance (extends BlitsComponent with .quit())
71
+ * @param {HTMLElement} target - The target element to render the application into
72
+ * @param {Partial<import('../../launch.js').BlitsSettings>} [settings] - The settings for the renderer
73
+ *
74
+ */
66
75
  export default (App, target, settings = {}) => {
67
76
  renderer = new RendererMain(
68
77
  {
package/src/launch.js CHANGED
@@ -20,6 +20,30 @@ import { initLog, Log } from './lib/log.js'
20
20
  import engine from './engine.js'
21
21
  import blitsPackageInfo from '../package.json' assert { type: 'json' }
22
22
 
23
+ /**
24
+ * @typedef {Object} Font
25
+ * @property {string} family - Name of the font family
26
+ * @property {string} type - Type of font (web, msdf, sdf)
27
+ * @property {string} [file] - Location to the font file
28
+ * @property {string} [json] - Location of the font map (for msdf/sdf)
29
+ * @property {string} [png] - Location of the font png (for msdf/sdf)
30
+ */
31
+ /**
32
+ * @typedef {Object} ShaderEffect
33
+ * @property {string} name
34
+ * @property {any} type
35
+ */
36
+ /**
37
+ * @typedef {Object} Shader
38
+ * @property {string} name
39
+ * @property {any} type
40
+ */
41
+
42
+ /**
43
+ * @typedef {import('@lightningjs/renderer').RendererMain} RendererMain
44
+ * @type {RendererMain}
45
+ */
46
+ // @ts-ignore - We ignore this because it will be replaced by the renderer once the app is launched
23
47
  export let renderer = {}
24
48
  export const stage = {}
25
49
 
@@ -37,6 +61,52 @@ async function rendererVersion() {
37
61
  }
38
62
  }
39
63
 
64
+ /**
65
+ * @typedef {Object} BlitsSettings
66
+ * @property {number} [w] - Width of the Application
67
+ * @property {number} [h] - Height of the Application
68
+ * @property {boolean} [multithreaded] - Whether to enable multithreaded
69
+ * @property {0|1|2|"info"|"warn"|"error"|"debug"[]} [debugLevel] - Debug level for console log messages
70
+ * @property {Font[]} [fonts] - Fonts to be used in the Application
71
+ * @property {ShaderEffect[]} [effects] - Effects to be used by DynamicShader
72
+ * @property {Shader[]} [shaders] - Shaders to be used in the application
73
+ * @property {string} [defaultFont] - Default font family to use in the Application
74
+ * @property {object} [keymap] - Custom keymapping
75
+ * @property {"Proxy"|"defineProperty"} [reactivityMode] - Mode of reactivity
76
+ * @property {"hd"|"720p"|720|"fhd"|"fullhd"|"1080p"|1080|"4k"|"2160p"|2160} [screenResolution] - Screen resolution of the device
77
+ * @property {"low"|"medium"|"high"|"retina"|number} [renderQuality] - Quality of the rendered App
78
+ * @property {number} [pixelRatio] - Custom pixel ratio of the device
79
+ * @property {number} [fpsInterval] - Interval in ms to receive FPS updates
80
+ * @property {number} [webWorkersLimit] - Maximum number of web workers
81
+ * @property {string} [canvasColor] - Background color of the canvas
82
+ * @property {boolean} [inspector] - Enable inspector
83
+ * @property {number|[number,number,number,number]} [viewportMargin] - Extra margin to the viewport
84
+ * @property {number} [gpuMemoryLimit] - Threshold after which textures are freed (deprecated)
85
+ * @property {object} [gpuMemory] - Configures the gpu memory settings
86
+ * @property {"webgl"|"canvas"} [renderMode] - Defines which mode the renderer should operate in
87
+ * @property {number} [holdTimeout] - Time after which a key press is considered a hold
88
+ * @property {HTMLCanvasElement} [canvas] - Custom canvas object used to render the App
89
+ * @property {number} [textureProcessingTimeLimit] - Max time renderer can process textures in a frame
90
+ * @property {Partial<import('@lightningjs/renderer').RendererMainSettings>} [advanced] - Advanced renderer settings
91
+ * @property {boolean} [announcer] - Whether or not the announcer should be activated on initialization
92
+ */
93
+
94
+ /**
95
+ * Blits App defines the structure of the Blits application.
96
+ * @typedef {import('./component').BlitsComponent} BlitsComponent
97
+ * @typedef {BlitsComponent & { quit: () => void }} BlitsAppComponent
98
+ * @typedef {() => BlitsAppComponent} BlitsAppFactory
99
+ */
100
+
101
+ /**
102
+ * Launches the Blits application with the given App, target, and settings.
103
+ * Sets up logging, version info, and initializes the renderer and stage singletons.
104
+ *
105
+ * @param {BlitsAppFactory} App - The root BlitsComponent to launch.
106
+ * @param {HTMLElement} target - The DOM element or rendering target.
107
+ * @param {BlitsSettings} settings - Configuration settings for the application.
108
+ * @returns {void}
109
+ */
40
110
  export default (App, target, settings) => {
41
111
  Settings.set(settings)
42
112
 
@@ -18,18 +18,31 @@
18
18
  const counters = {}
19
19
  let counter = 0
20
20
 
21
+ /**
22
+ * Creates a human-readable component ID string for a given component name.
23
+ *
24
+ * @param {string} name - The name of the component.
25
+ * @returns {string} The generated human-readable component ID.
26
+ */
21
27
  export const createHumanReadableId = (name) => {
22
28
  return `BlitsComponent::${name}_${(counters[name] = (counters[name] || 0) + 1)}`
23
29
  }
24
30
 
31
+ /**
32
+ * Generates a new unique internal numeric ID.
33
+ *
34
+ * @returns {number} The next unique internal ID.
35
+ */
25
36
  export const createInternalId = () => {
26
37
  return ++counter
27
38
  }
28
39
 
29
40
  /**
30
- * Resets the counter value back to 0.
41
+ * Resets the internal counter value back to 0.
31
42
  * Used in automated tests to ensure consistent results, not intended
32
43
  * to be used in the actual framework code!
44
+ *
45
+ * @returns {void}
33
46
  */
34
47
  export const resetCounter = () => {
35
48
  counter = 0
@@ -19,6 +19,15 @@ const eventsMap = new Map()
19
19
  const callbackCache = new Map()
20
20
 
21
21
  export default {
22
+ /**
23
+ * Registers a listener callback for a specific event on a component.
24
+ *
25
+ * @param {object} component - The component instance to register the listener for.
26
+ * @param {string} event - The name of the event to listen for.
27
+ * @param {Function} cb - The callback function to execute when the event is emitted.
28
+ * @param {number} [priority=0] - The priority of the listener (higher runs first).
29
+ * @returns {void}
30
+ */
22
31
  registerListener(component, event, cb, priority = 0) {
23
32
  let componentsMap = eventsMap.get(event)
24
33
  if (componentsMap === undefined) {
@@ -36,6 +45,13 @@ export default {
36
45
  callbackCache.delete(event) // Invalidate the callbackCache when a new callback is added
37
46
  },
38
47
 
48
+ /**
49
+ * Deregisters a listener for a specific event on a component.
50
+ *
51
+ * @param {object} component - The component instance to deregister the listener for.
52
+ * @param {string} event - The name of the event to stop listening for.
53
+ * @returns {void}
54
+ */
39
55
  deregisterListener(component, event) {
40
56
  let componentsMap = eventsMap.get(event)
41
57
  if (componentsMap === undefined) {
@@ -49,6 +65,13 @@ export default {
49
65
  }
50
66
  },
51
67
 
68
+ /**
69
+ * Executes all registered listeners for a given event, in priority order.
70
+ *
71
+ * @param {string} event - The name of the event to emit.
72
+ * @param {any} params - The parameters to pass to the event listeners.
73
+ * @returns {boolean} True if all listeners executed without stopping propagation, false if any listener returned false.
74
+ */
52
75
  executeListeners(event, params) {
53
76
  const componentsMap = eventsMap.get(event)
54
77
  if (componentsMap === undefined || componentsMap.size === 0) {
@@ -78,6 +101,12 @@ export default {
78
101
  return true // All listeners executed without stopping propagation
79
102
  },
80
103
 
104
+ /**
105
+ * Removes all listeners for a given component from all events.
106
+ *
107
+ * @param {object} component - The component instance to remove listeners for.
108
+ * @returns {void}
109
+ */
81
110
  removeListeners(component) {
82
111
  for (const [event, componentsMap] of eventsMap) {
83
112
  if (componentsMap.has(component)) {
package/src/lib/hooks.js CHANGED
@@ -19,15 +19,36 @@ import symbols from './symbols.js'
19
19
 
20
20
  const cbs = {}
21
21
 
22
+ /**
23
+ * Emits a registered hook for a given identifier, calling the hook with the provided scope and data.
24
+ *
25
+ * @param {string|symbol} hook - The name or symbol of the hook to emit.
26
+ * @param {string} identifier - The unique identifier for the hook set.
27
+ * @param {object} scope - The value of `this` inside the hook function.
28
+ * @param {Array} [data=[]] - Arguments to pass to the hook function.
29
+ */
22
30
  export const emit = (hook, identifier, scope, data = []) => {
23
31
  cbs[identifier] && cbs[identifier][hook] && cbs[identifier][hook].apply(scope, data)
24
32
  }
25
33
 
34
+ /**
35
+ * Emits a registered symbol-based hook for a given identifier, calling the hook with the provided scope.
36
+ *
37
+ * @param {string|symbol} hook - The name or symbol of the hook to emit (will be mapped to a symbol).
38
+ * @param {string} identifier - The unique identifier for the hook set.
39
+ * @param {object} scope - The value of `this` inside the hook function.
40
+ */
26
41
  export const privateEmit = (hook, identifier, scope) => {
27
42
  const symHook = symbols[hook]
28
43
  cbs[identifier] && cbs[identifier][symHook] && cbs[identifier][symHook].apply(scope)
29
44
  }
30
45
 
46
+ /**
47
+ * Registers a set of hooks (functions) for a given identifier.
48
+ *
49
+ * @param {Object<string,Function>|Object<symbol,Function>} hooks - An object whose keys are hook names or symbols and values are functions.
50
+ * @param {string} identifier - The unique identifier for the hook set.
51
+ */
31
52
  export const registerHooks = (hooks = {}, identifier) => {
32
53
  cbs[identifier] = {}
33
54
  // Combines enumerable keys and symbol properties of the 'hooks' object
@@ -19,6 +19,10 @@ import { Log } from './log.js'
19
19
  import { emit, privateEmit } from './hooks.js'
20
20
  import symbols from './symbols.js'
21
21
 
22
+ /**
23
+ * List of valid lifecycle states for a component.
24
+ * @type {Array<string>}
25
+ */
22
26
  const states = [
23
27
  'init', // fired upon component instantiation
24
28
  'ready', // fired when component instantiated, reactivity setup done and template spawned
@@ -31,12 +35,40 @@ const states = [
31
35
  'exit', // fired when leaving the visible viewport
32
36
  ]
33
37
 
38
+ /**
39
+ * Lifecycle state manager for components.
40
+ *
41
+ * @typedef {Object} Lifecycle
42
+ * @property {string|null} previous - The previous lifecycle state.
43
+ * @property {string|null} current - The current lifecycle state.
44
+ * @property {Object} [component] - The component instance this lifecycle belongs to.
45
+ * @property {string|null} state - The current lifecycle state (getter/setter).
46
+ */
47
+
48
+ /**
49
+ * Lifecycle state management object for components.
50
+ * Handles state transitions and emits corresponding hooks.
51
+ *
52
+ * @type {Lifecycle}
53
+ * @this {Lifecycle & {component: Object}}
54
+ * The 'component' property is expected to be set by the component instance at runtime.
55
+ */
34
56
  export default {
35
57
  previous: null,
36
58
  current: null,
59
+ /**
60
+ * Gets the current lifecycle state.
61
+ * @this {Lifecycle & {component: Object}}
62
+ * @returns {string|null}
63
+ */
37
64
  get state() {
38
65
  return this.current
39
66
  },
67
+ /**
68
+ * Sets the lifecycle state and emits hooks if the state is valid and changed.
69
+ * @this {Lifecycle & {component: Object}}
70
+ * @param {string} v - The new lifecycle state.
71
+ */
40
72
  set state(v) {
41
73
  if (states.indexOf(v) > -1 && (v !== this.current || v === 'focus')) {
42
74
  Log.debug(
package/src/lib/log.js CHANGED
@@ -19,6 +19,10 @@ import Settings from '../settings.js'
19
19
 
20
20
  const n = () => {}
21
21
 
22
+ /**
23
+ * Returns the current time as a locale time string (hh:mm:ss).
24
+ * @returns {string} The current time string.
25
+ */
22
26
  const time = () =>
23
27
  new Date().toLocaleTimeString([], {
24
28
  hour: '2-digit',
@@ -26,6 +30,13 @@ const time = () =>
26
30
  second: '2-digit',
27
31
  })
28
32
 
33
+ /**
34
+ * Returns a logger object for the given context, with info, warn, debug, and error methods.
35
+ * Logging methods are no-ops if the debug level does not match.
36
+ *
37
+ * @param {string} context - The context label for log messages.
38
+ * @returns {Object} Logger object with info, warn, debug, and error methods.
39
+ */
29
40
  const logger = (context) => {
30
41
  const level = Settings.get('debugLevel')
31
42
  const log = {}
@@ -1,3 +1,55 @@
1
+ /**
2
+ * Symbol registry for internal framework properties and generated code.
3
+ *
4
+ * @typedef {Object} BlitsSymbols
5
+ * @property {symbol} currentView
6
+ * @property {symbol} cursorTagStart
7
+ * @property {symbol} computedKeys
8
+ * @property {symbol} destroy
9
+ * @property {symbol} getChildren
10
+ * @property {symbol} holder
11
+ * @property {symbol} id
12
+ * @property {symbol} identifier
13
+ * @property {symbol} index
14
+ * @property {symbol} init
15
+ * @property {symbol} inputEvents
16
+ * @property {symbol} intervals
17
+ * @property {symbol} launched
18
+ * @property {symbol} level
19
+ * @property {symbol} methodKeys
20
+ * @property {symbol} originalState
21
+ * @property {symbol} propKeys
22
+ * @property {symbol} raw
23
+ * @property {symbol} ready
24
+ * @property {symbol} renderer
25
+ * @property {symbol} routes
26
+ * @property {symbol} routerHooks
27
+ * @property {symbol} settings
28
+ * @property {symbol} state
29
+ * @property {symbol} stateKeys
30
+ * @property {symbol} textnode
31
+ * @property {symbol} timeouts
32
+ * @property {symbol} type
33
+ * @property {symbol} watchers
34
+ * @property {symbol} watchKeys
35
+ * @property {symbol} wrapper
36
+ * @property {symbol} children
37
+ * @property {symbol} components
38
+ * @property {symbol} config
39
+ * @property {symbol} isSlot
40
+ * @property {symbol} props
41
+ * @property {symbol} slots
42
+ * @property {symbol} componentType
43
+ * @property {symbol} isComponent
44
+ * @property {symbol} effects
45
+ * @property {symbol} removeGlobalEffects
46
+ */
47
+
48
+ /**
49
+ * Internal symbol registry for Blits framework and generated code.
50
+ *
51
+ * @type {BlitsSymbols}
52
+ */
1
53
  export default {
2
54
  currentView: Symbol('currentView'),
3
55
  cursorTagStart: Symbol('cursorTagStart'),
package/src/lib/utils.js CHANGED
@@ -1,3 +1,18 @@
1
+ /**
2
+ * A mapping of common screen resolution names to their scale factors relative to 1080p (Full HD).
3
+ *
4
+ * @type {Object<string|number, number>}
5
+ * @property {number} hd - 0.666... (720p)
6
+ * @property {number} '720p' - 0.666... (720p)
7
+ * @property {number} 720 - 0.666... (720p)
8
+ * @property {number} fhd - 1 (Full HD)
9
+ * @property {number} fullhd - 1 (Full HD)
10
+ * @property {number} '1080p' - 1 (Full HD)
11
+ * @property {number} 1080 - 1 (Full HD)
12
+ * @property {number} '4k' - 2 (2160p)
13
+ * @property {number} '2160p' - 2 (2160p)
14
+ * @property {number} 2160 - 2 (2160p)
15
+ */
1
16
  export const screenResolutions = {
2
17
  hd: 0.66666667,
3
18
  '720p': 0.66666667,
@@ -25,6 +25,30 @@ import Focus from '../focus.js'
25
25
  import Announcer from '../announcer/announcer.js'
26
26
  import Settings from '../settings.js'
27
27
 
28
+ /**
29
+ * @typedef {import('../component.js').BlitsComponentFactory} BlitsComponentFactory - The component of the route
30
+ * @typedef {import('../component.js').BlitsComponent} BlitsComponent - The element of the route
31
+ * @typedef {import('../engines/L3/element.js').BlitsElement} BlitsElement - The element of the route
32
+ *
33
+ * @typedef {Object} Route
34
+ * @property {string} path - The path of the route
35
+ * @property {string} hash - The hash of the route
36
+ * @property {Object} params - The params of the route
37
+ * @property {Object} data - The data of the route
38
+ * @property {Object} options - The options of the route
39
+ * @property {Object} hooks - The hooks of the route
40
+ * @property {Object} transition - The transition of the route
41
+ * @property {Object} announce - The announce of the route
42
+ * @property {(options: Object, parentEl: BlitsElement, parentComponent: BlitsComponent, rootComponent?: BlitsComponent) => BlitsComponent} component - The component factory of the route
43
+ *
44
+ * @typedef {Object} Hash
45
+ * @property {string} path - The path of the hash
46
+ * @property {URLSearchParams} queryParams - The query params of the hash
47
+ * @property {string} hash - The hash
48
+ *
49
+ */
50
+
51
+ /** @type {Route} */
28
52
  export let currentRoute
29
53
  export const state = reactive(
30
54
  {
@@ -40,6 +64,14 @@ export const state = reactive(
40
64
 
41
65
  // Changed from WeakMap to Map to allow for caching of views by the url hash.
42
66
  // We are manually doing the cleanup of the cache when the route is not marked as keepAlive.
67
+
68
+ /**
69
+ * @typedef {Object} CacheMapEntry
70
+ * @property {BlitsComponent|BlitsComponentFactory} view - The view of the route
71
+ * @property {BlitsComponent} focus - The focus of the route
72
+ */
73
+
74
+ /** @type {Map<String, CacheMapEntry>} */
43
75
  const cacheMap = new Map()
44
76
  const history = []
45
77
 
@@ -48,6 +80,10 @@ let navigationData = {}
48
80
  let navigatingBack = false
49
81
  let previousFocus
50
82
 
83
+ /**
84
+ * Get the current hash
85
+ * @returns {Hash}
86
+ */
51
87
  export const getHash = () => {
52
88
  const hashParts = (document.location.hash || '/').replace(/^#/, '').split('?')
53
89
  return {
@@ -65,14 +101,34 @@ const normalizePath = (path) => {
65
101
  .toLowerCase()
66
102
  )
67
103
  }
104
+
105
+ /**
106
+ * Check if a value is an object
107
+ * @param {any} v
108
+ * @returns {boolean} True if v is an object
109
+ */
68
110
  const isObject = (v) => typeof v === 'object' && v !== null
69
111
 
112
+ /**
113
+ * Check if a value is a function
114
+ * @param {any} v
115
+ * @returns {boolean} True if v is a string
116
+ */
70
117
  const isString = (v) => typeof v === 'string'
71
118
 
119
+ /**
120
+ * Match a path to a route
121
+ *
122
+ * @param {string} path
123
+ * @param {Route[]} routes
124
+ * @returns {Route}
125
+ */
72
126
  export const matchHash = (path, routes = []) => {
73
127
  // remove trailing slashes
74
128
  const originalPath = path.replace(/^\/+|\/+$/g, '')
75
129
  path = normalizePath(path)
130
+
131
+ /** @type {boolean|Route} */
76
132
  let matchingRoute = false
77
133
  let i = 0
78
134
  while (!matchingRoute && i < routes.length) {
@@ -126,9 +182,22 @@ export const matchHash = (path, routes = []) => {
126
182
  }
127
183
  }
128
184
 
185
+ // @ts-ignore - Remove me when we have a better way to handle this
129
186
  return matchingRoute
130
187
  }
131
188
 
189
+ /**
190
+ * Navigate to a route
191
+ *
192
+ * This isn't the prettiest way to do this, but it works. The reason is that extends
193
+ * only works for Classes or Factory functions. As such we need to use this
194
+ * @typedef {BlitsComponent & {
195
+ * activeView: BlitsComponent
196
+ * }} RouterViewComponent
197
+ *
198
+ * @this {RouterViewComponent} this
199
+ * @returns {Promise<void>}
200
+ */
132
201
  export const navigate = async function () {
133
202
  Announcer.stop()
134
203
  Announcer.clear()
@@ -178,6 +247,7 @@ export const navigate = async function () {
178
247
  }
179
248
  // apply default transition if none specified
180
249
  if (!('transition' in route)) {
250
+ /** @ts-ignore */
181
251
  route.transition = fadeInFadeOutTransition
182
252
  }
183
253
  // a transition can be a function returning a dynamic transition object
@@ -186,8 +256,10 @@ export const navigate = async function () {
186
256
  route.transition = route.transition(previousRoute, route)
187
257
  }
188
258
 
259
+ /** @type {import('../engines/L3/element.js').BlitsElement} */
189
260
  let holder
190
261
  let routeData
262
+
191
263
  let { view, focus } = cacheMap.get(route.hash) || {}
192
264
 
193
265
  // Announce route change if a message has been specified for this route
@@ -236,7 +308,9 @@ export const navigate = async function () {
236
308
  }
237
309
  }
238
310
  if (typeof view === 'function') {
239
- view = view({ props }, holder, this)
311
+ // had to inline this because the tscompiler does not like LHS reassignments
312
+ // that also change the type of the variable in a variable union
313
+ view = /** @type {BlitsComponentFactory} */ (view)({ props }, holder, this)
240
314
  }
241
315
  } else {
242
316
  holder = view[symbols.holder]
@@ -267,7 +341,7 @@ export const navigate = async function () {
267
341
  previousFocus = Focus.get()
268
342
 
269
343
  // set focus to the view that we're routing to
270
- focus ? focus.$focus() : view.$focus()
344
+ focus ? focus.$focus() : /** @type {BlitsComponent} */ (view).$focus()
271
345
 
272
346
  // apply before settings to holder element
273
347
  if (route.transition.before) {
@@ -321,6 +395,13 @@ export const navigate = async function () {
321
395
  state.navigating = false
322
396
  }
323
397
 
398
+ /**
399
+ * Remove the currently active view
400
+ *
401
+ * @param {Route} route
402
+ * @param {BlitsComponent} view
403
+ * @param {Object} transition
404
+ */
324
405
  const removeView = async (route, view, transition) => {
325
406
  // apply out transition
326
407
  if (transition) {