@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 +14 -0
- package/docs/essentials/settings.md +117 -0
- package/docs/sidebar.json +4 -0
- package/jsconfig.json +12 -0
- package/package.json +1 -1
- package/src/component/base/events.js +23 -0
- package/src/component/base/methods.js +35 -0
- package/src/component/base/timeouts_intervals.js +4 -0
- package/src/component/setup/index.js +0 -2
- package/src/component.js +152 -3
- package/src/engines/L3/element.js +72 -0
- package/src/engines/L3/launch.js +10 -1
- package/src/launch.js +70 -0
- package/src/lib/componentId.js +14 -1
- package/src/lib/eventListeners.js +29 -0
- package/src/lib/hooks.js +21 -0
- package/src/lib/lifecycle.js +32 -0
- package/src/lib/log.js +11 -0
- package/src/lib/symbols.js +52 -0
- package/src/lib/utils.js +15 -0
- package/src/router/router.js +83 -2
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
package/jsconfig.json
ADDED
package/package.json
CHANGED
|
@@ -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
|
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 {
|
|
50
|
-
* @returns {
|
|
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 = {
|
package/src/engines/L3/launch.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
package/src/lib/componentId.js
CHANGED
|
@@ -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
|
package/src/lib/lifecycle.js
CHANGED
|
@@ -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 = {}
|
package/src/lib/symbols.js
CHANGED
|
@@ -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,
|
package/src/router/router.js
CHANGED
|
@@ -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
|
-
|
|
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) {
|