canvasengine 2.0.0-beta.5 → 2.0.0-beta.50
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/dist/components/Button.d.ts +185 -0
- package/dist/components/Button.d.ts.map +1 -0
- package/dist/components/Canvas.d.ts +17 -0
- package/dist/components/Canvas.d.ts.map +1 -0
- package/dist/components/Container.d.ts +86 -0
- package/dist/components/Container.d.ts.map +1 -0
- package/dist/components/DOMContainer.d.ts +98 -0
- package/dist/components/DOMContainer.d.ts.map +1 -0
- package/dist/components/DOMElement.d.ts +54 -0
- package/dist/components/DOMElement.d.ts.map +1 -0
- package/dist/components/DOMSprite.d.ts +127 -0
- package/dist/components/DOMSprite.d.ts.map +1 -0
- package/dist/components/DisplayObject.d.ts +94 -0
- package/dist/components/DisplayObject.d.ts.map +1 -0
- package/dist/components/FocusContainer.d.ts +129 -0
- package/dist/components/FocusContainer.d.ts.map +1 -0
- package/dist/components/Graphic.d.ts +64 -0
- package/dist/components/Graphic.d.ts.map +1 -0
- package/dist/components/Joystick.d.ts +36 -0
- package/dist/components/Joystick.d.ts.map +1 -0
- package/dist/components/Mesh.d.ts +208 -0
- package/dist/components/Mesh.d.ts.map +1 -0
- package/dist/components/NineSliceSprite.d.ts +16 -0
- package/dist/components/NineSliceSprite.d.ts.map +1 -0
- package/dist/components/ParticleEmitter.d.ts +4 -0
- package/dist/components/ParticleEmitter.d.ts.map +1 -0
- package/dist/components/Scene.d.ts +2 -0
- package/dist/components/Scene.d.ts.map +1 -0
- package/dist/components/Sprite.d.ts +242 -0
- package/dist/components/Sprite.d.ts.map +1 -0
- package/dist/components/Text.d.ts +25 -0
- package/dist/components/Text.d.ts.map +1 -0
- package/dist/components/TilingSprite.d.ts +17 -0
- package/dist/components/TilingSprite.d.ts.map +1 -0
- package/dist/components/Video.d.ts +14 -0
- package/dist/components/Video.d.ts.map +1 -0
- package/dist/components/Viewport.d.ts +121 -0
- package/dist/components/Viewport.d.ts.map +1 -0
- package/dist/components/index.d.ts +20 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/types/DisplayObject.d.ts +106 -0
- package/dist/components/types/DisplayObject.d.ts.map +1 -0
- package/dist/components/types/MouseEvent.d.ts +4 -0
- package/dist/components/types/MouseEvent.d.ts.map +1 -0
- package/dist/components/types/Spritesheet.d.ts +248 -0
- package/dist/components/types/Spritesheet.d.ts.map +1 -0
- package/dist/components/types/index.d.ts +4 -0
- package/dist/components/types/index.d.ts.map +1 -0
- package/dist/directives/Controls.d.ts +112 -0
- package/dist/directives/Controls.d.ts.map +1 -0
- package/dist/directives/ControlsBase.d.ts +199 -0
- package/dist/directives/ControlsBase.d.ts.map +1 -0
- package/dist/directives/Drag.d.ts +69 -0
- package/dist/directives/Drag.d.ts.map +1 -0
- package/dist/directives/Flash.d.ts +116 -0
- package/dist/directives/Flash.d.ts.map +1 -0
- package/dist/directives/FocusNavigation.d.ts +52 -0
- package/dist/directives/FocusNavigation.d.ts.map +1 -0
- package/dist/directives/GamepadControls.d.ts +224 -0
- package/dist/directives/GamepadControls.d.ts.map +1 -0
- package/dist/directives/JoystickControls.d.ts +171 -0
- package/dist/directives/JoystickControls.d.ts.map +1 -0
- package/dist/directives/KeyboardControls.d.ts +219 -0
- package/dist/directives/KeyboardControls.d.ts.map +1 -0
- package/dist/directives/Scheduler.d.ts +35 -0
- package/dist/directives/Scheduler.d.ts.map +1 -0
- package/dist/directives/Shake.d.ts +98 -0
- package/dist/directives/Shake.d.ts.map +1 -0
- package/dist/directives/Sound.d.ts +25 -0
- package/dist/directives/Sound.d.ts.map +1 -0
- package/dist/directives/Transition.d.ts +10 -0
- package/dist/directives/Transition.d.ts.map +1 -0
- package/dist/directives/ViewportCull.d.ts +11 -0
- package/dist/directives/ViewportCull.d.ts.map +1 -0
- package/dist/directives/ViewportFollow.d.ts +18 -0
- package/dist/directives/ViewportFollow.d.ts.map +1 -0
- package/dist/directives/index.d.ts +13 -0
- package/dist/directives/index.d.ts.map +1 -0
- package/dist/engine/FocusManager.d.ts +174 -0
- package/dist/engine/FocusManager.d.ts.map +1 -0
- package/dist/engine/animation.d.ts +72 -0
- package/dist/engine/animation.d.ts.map +1 -0
- package/dist/engine/bootstrap.d.ts +48 -0
- package/dist/engine/bootstrap.d.ts.map +1 -0
- package/dist/engine/directive.d.ts +13 -0
- package/dist/engine/directive.d.ts.map +1 -0
- package/dist/engine/reactive.d.ts +134 -0
- package/dist/engine/reactive.d.ts.map +1 -0
- package/dist/engine/signal.d.ts +71 -0
- package/dist/engine/signal.d.ts.map +1 -0
- package/dist/engine/trigger.d.ts +54 -0
- package/dist/engine/trigger.d.ts.map +1 -0
- package/dist/engine/utils.d.ts +89 -0
- package/dist/engine/utils.d.ts.map +1 -0
- package/dist/hooks/addContext.d.ts +2 -0
- package/dist/hooks/addContext.d.ts.map +1 -0
- package/dist/hooks/useFocus.d.ts +60 -0
- package/dist/hooks/useFocus.d.ts.map +1 -0
- package/dist/hooks/useProps.d.ts +42 -0
- package/dist/hooks/useProps.d.ts.map +1 -0
- package/dist/hooks/useRef.d.ts +4 -0
- package/dist/hooks/useRef.d.ts.map +1 -0
- package/dist/index-DaGekQUW.js +2218 -0
- package/dist/index-DaGekQUW.js.map +1 -0
- package/dist/index.d.ts +19 -1099
- package/dist/index.d.ts.map +1 -0
- package/dist/index.global.js +5 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +11749 -2901
- package/dist/index.js.map +1 -1
- package/dist/utils/Ease.d.ts +17 -0
- package/dist/utils/Ease.d.ts.map +1 -0
- package/dist/utils/GlobalAssetLoader.d.ts +141 -0
- package/dist/utils/GlobalAssetLoader.d.ts.map +1 -0
- package/dist/utils/RadialGradient.d.ts +57 -0
- package/dist/utils/RadialGradient.d.ts.map +1 -0
- package/dist/utils/functions.d.ts +2 -0
- package/dist/utils/functions.d.ts.map +1 -0
- package/dist/utils/tabindex.d.ts +16 -0
- package/dist/utils/tabindex.d.ts.map +1 -0
- package/package.json +13 -7
- package/src/components/Button.ts +399 -0
- package/src/components/Canvas.ts +62 -46
- package/src/components/Container.ts +21 -2
- package/src/components/DOMContainer.ts +379 -0
- package/src/components/DOMElement.ts +556 -0
- package/src/components/DOMSprite.ts +1040 -0
- package/src/components/DisplayObject.ts +392 -201
- package/src/components/FocusContainer.ts +368 -0
- package/src/components/Graphic.ts +227 -66
- package/src/components/Joystick.ts +363 -0
- package/src/components/Mesh.ts +222 -0
- package/src/components/NineSliceSprite.ts +4 -1
- package/src/components/ParticleEmitter.ts +12 -8
- package/src/components/Sprite.ts +297 -31
- package/src/components/Text.ts +125 -18
- package/src/components/Video.ts +2 -2
- package/src/components/Viewport.ts +118 -63
- package/src/components/index.ts +9 -2
- package/src/components/types/DisplayObject.ts +41 -4
- package/src/components/types/Spritesheet.ts +0 -118
- package/src/directives/Controls.ts +254 -0
- package/src/directives/ControlsBase.ts +267 -0
- package/src/directives/Drag.ts +357 -52
- package/src/directives/Flash.ts +419 -0
- package/src/directives/FocusNavigation.ts +113 -0
- package/src/directives/GamepadControls.ts +537 -0
- package/src/directives/JoystickControls.ts +396 -0
- package/src/directives/KeyboardControls.ts +85 -430
- package/src/directives/Scheduler.ts +12 -4
- package/src/directives/Shake.ts +298 -0
- package/src/directives/Sound.ts +94 -31
- package/src/directives/ViewportFollow.ts +40 -9
- package/src/directives/index.ts +12 -6
- package/src/engine/FocusManager.ts +510 -0
- package/src/engine/animation.ts +175 -21
- package/src/engine/bootstrap.ts +93 -3
- package/src/engine/directive.ts +4 -4
- package/src/engine/reactive.ts +901 -161
- package/src/engine/signal.ts +113 -25
- package/src/engine/trigger.ts +34 -7
- package/src/engine/utils.ts +19 -3
- package/src/hooks/useFocus.ts +91 -0
- package/src/hooks/useProps.ts +1 -1
- package/src/index.ts +8 -2
- package/src/types/pixi-cull.d.ts +7 -0
- package/src/utils/GlobalAssetLoader.ts +257 -0
- package/src/utils/functions.ts +7 -0
- package/src/utils/tabindex.ts +70 -0
- package/testing/index.ts +35 -4
- package/tsconfig.json +18 -0
- package/vite.config.ts +39 -0
package/src/engine/signal.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
Observable,
|
|
3
|
+
Subscription
|
|
3
4
|
} from "rxjs";
|
|
5
|
+
import { isSignal } from "@signe/reactive";
|
|
4
6
|
import type { Element } from "./reactive";
|
|
7
|
+
import { isElementFrozen, waitForDependencies } from "./reactive";
|
|
8
|
+
import { isPromise } from "./utils";
|
|
5
9
|
import { Tick } from "../directives/Scheduler";
|
|
10
|
+
import { Container } from "../components";
|
|
6
11
|
|
|
7
12
|
type MountFunction = (fn: (element: Element) => void) => void;
|
|
8
13
|
|
|
@@ -19,16 +24,16 @@ export let mountTracker: MountFunction | null = null;
|
|
|
19
24
|
* @param {(element: Element) => void} fn - The function to be called on mount.
|
|
20
25
|
* @example
|
|
21
26
|
* ```ts
|
|
22
|
-
|
|
23
|
-
*
|
|
27
|
+
* mount((el) => {
|
|
28
|
+
* console.log('mounted', el);
|
|
24
29
|
* });
|
|
25
30
|
* ```
|
|
26
31
|
* Unmount the component by returning a function:
|
|
27
32
|
* ```ts
|
|
28
|
-
|
|
29
|
-
*
|
|
33
|
+
* mount((el) => {
|
|
34
|
+
* console.log('mounted', el);
|
|
30
35
|
* return () => {
|
|
31
|
-
*
|
|
36
|
+
* console.log('unmounted', el);
|
|
32
37
|
* }
|
|
33
38
|
* });
|
|
34
39
|
* ```
|
|
@@ -42,8 +47,8 @@ export function mount(fn: (element: Element) => void) {
|
|
|
42
47
|
* @param {(tickValue: Tick, element: Element) => void} fn - The function to be called on each tick.
|
|
43
48
|
* @example
|
|
44
49
|
* ```ts
|
|
45
|
-
|
|
46
|
-
*
|
|
50
|
+
* tick((tickValue, el) => {
|
|
51
|
+
* console.log('tick', tickValue, el);
|
|
47
52
|
* });
|
|
48
53
|
* ```
|
|
49
54
|
*/
|
|
@@ -53,7 +58,11 @@ export function tick(fn: (tickValue: Tick, element: Element) => void) {
|
|
|
53
58
|
let subscription: Subscription | undefined
|
|
54
59
|
if (context.tick) {
|
|
55
60
|
subscription = context.tick.observable.subscribe(({ value }) => {
|
|
56
|
-
|
|
61
|
+
// Block tick if element is frozen
|
|
62
|
+
if (isElementFrozen(el)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
fn(value, el)
|
|
57
66
|
})
|
|
58
67
|
}
|
|
59
68
|
return () => {
|
|
@@ -71,29 +80,29 @@ export function tick(fn: (tickValue: Tick, element: Element) => void) {
|
|
|
71
80
|
* @returns {ReturnType<C>}
|
|
72
81
|
* @example
|
|
73
82
|
* ```ts
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
83
|
+
* const el = h(MyComponent, {
|
|
84
|
+
* x: 100,
|
|
85
|
+
* y: 100,
|
|
86
|
+
* });
|
|
78
87
|
* ```
|
|
79
88
|
*
|
|
80
89
|
* with children:
|
|
81
90
|
* ```ts
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
*
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
* const el = h(MyComponent, {
|
|
92
|
+
* x: 100,
|
|
93
|
+
* y: 100,
|
|
94
|
+
* },
|
|
95
|
+
* h(MyChildComponent, {
|
|
96
|
+
* x: 50,
|
|
97
|
+
* y: 50,
|
|
98
|
+
* }),
|
|
90
99
|
* );
|
|
91
100
|
* ```
|
|
92
101
|
*/
|
|
93
|
-
|
|
94
|
-
componentFunction: C,
|
|
102
|
+
function _h<C extends ComponentFunction<any>>(
|
|
103
|
+
componentFunction: C | Element,
|
|
95
104
|
props: Parameters<C>[0] = {} as Parameters<C>[0],
|
|
96
|
-
|
|
105
|
+
children: any[]
|
|
97
106
|
): ReturnType<C> {
|
|
98
107
|
const allSubscriptions = new Set<Subscription>();
|
|
99
108
|
const allMounts = new Set<MountFunction>();
|
|
@@ -110,7 +119,25 @@ export function h<C extends ComponentFunction<any>>(
|
|
|
110
119
|
children = children[0]
|
|
111
120
|
}
|
|
112
121
|
|
|
113
|
-
let component
|
|
122
|
+
let component: Element
|
|
123
|
+
|
|
124
|
+
if (Array.isArray(componentFunction)) {
|
|
125
|
+
if (componentFunction.length === 1) {
|
|
126
|
+
component = componentFunction[0]
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
component = _h(Container, {}, componentFunction) as Element
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else if ('tag' in componentFunction) {
|
|
133
|
+
component = componentFunction
|
|
134
|
+
}
|
|
135
|
+
else if (componentFunction instanceof Observable) {
|
|
136
|
+
component = componentFunction as any
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
component = componentFunction({ ...props, children }) as Element;
|
|
140
|
+
}
|
|
114
141
|
|
|
115
142
|
if (!component) {
|
|
116
143
|
component = {} as any
|
|
@@ -122,6 +149,12 @@ export function h<C extends ComponentFunction<any>>(
|
|
|
122
149
|
...((component as any).effectMounts ?? [])
|
|
123
150
|
];
|
|
124
151
|
|
|
152
|
+
// Copy dependencies prop to the returned element so it can be used for delayed mounting
|
|
153
|
+
if (props?.dependencies) {
|
|
154
|
+
component.props = component.props || {};
|
|
155
|
+
component.props.dependencies = props.dependencies;
|
|
156
|
+
}
|
|
157
|
+
|
|
125
158
|
// call mount hook for root component
|
|
126
159
|
if (component instanceof Promise) {
|
|
127
160
|
component.then((component) => {
|
|
@@ -136,3 +169,58 @@ export function h<C extends ComponentFunction<any>>(
|
|
|
136
169
|
|
|
137
170
|
return component as ReturnType<C>;
|
|
138
171
|
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Add tracking for subscriptions and mounts, then create an element from a component function.
|
|
175
|
+
* @template C
|
|
176
|
+
* @param {C} componentFunction - The component function to create an element from.
|
|
177
|
+
* @param {Parameters<C>[0]} [props={}] - The props to pass to the component function.
|
|
178
|
+
* @param {...any[]} children - The children elements of the component.
|
|
179
|
+
* @returns {ReturnType<C>}
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* const el = h(MyComponent, {
|
|
183
|
+
* x: 100,
|
|
184
|
+
* y: 100,
|
|
185
|
+
* });
|
|
186
|
+
* ```
|
|
187
|
+
*
|
|
188
|
+
* with children:
|
|
189
|
+
* ```ts
|
|
190
|
+
* const el = h(MyComponent, {
|
|
191
|
+
* x: 100,
|
|
192
|
+
* y: 100,
|
|
193
|
+
* },
|
|
194
|
+
* h(MyChildComponent, {
|
|
195
|
+
* x: 50,
|
|
196
|
+
* y: 50,
|
|
197
|
+
* }),
|
|
198
|
+
* );
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
export function h<C extends ComponentFunction<any>>(
|
|
202
|
+
componentFunction: C | Element,
|
|
203
|
+
props: Parameters<C>[0] = {} as Parameters<C>[0],
|
|
204
|
+
...children: any[]
|
|
205
|
+
): ReturnType<C> {
|
|
206
|
+
if (props?.dependencies) {
|
|
207
|
+
const hasPromise = props.dependencies.some(isPromise);
|
|
208
|
+
if (!hasPromise) {
|
|
209
|
+
const allReady = props.dependencies.every(dep => {
|
|
210
|
+
if (isSignal(dep)) return dep() !== undefined;
|
|
211
|
+
return dep !== undefined;
|
|
212
|
+
});
|
|
213
|
+
if (allReady) {
|
|
214
|
+
return _h(componentFunction, props, children);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return new Observable(subscriber => {
|
|
219
|
+
waitForDependencies(props.dependencies).then(() => {
|
|
220
|
+
const el = _h(componentFunction, props, children);
|
|
221
|
+
subscriber.next(el);
|
|
222
|
+
});
|
|
223
|
+
}) as any;
|
|
224
|
+
}
|
|
225
|
+
return _h(componentFunction, props, children);
|
|
226
|
+
}
|
package/src/engine/trigger.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { effect, signal } from "@signe/reactive";
|
|
2
2
|
|
|
3
|
-
interface Listen<T = any> {
|
|
3
|
+
export interface Listen<T = any> {
|
|
4
4
|
config: T | undefined;
|
|
5
5
|
seed: {
|
|
6
6
|
config: T | undefined;
|
|
@@ -9,7 +9,7 @@ interface Listen<T = any> {
|
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
interface Trigger<T = any> {
|
|
12
|
+
export interface Trigger<T = any> {
|
|
13
13
|
start: () => Promise<void>;
|
|
14
14
|
listen: () => Listen<T> | undefined;
|
|
15
15
|
}
|
|
@@ -47,13 +47,14 @@ export function trigger<T = any>(globalConfig?: T): Trigger<T> {
|
|
|
47
47
|
return {
|
|
48
48
|
start: (config?: T) => {
|
|
49
49
|
return new Promise((resolve: (value: any) => void) => {
|
|
50
|
+
const newValue = Math.random();
|
|
50
51
|
_signal.set({
|
|
51
52
|
config: {
|
|
52
53
|
...globalConfig,
|
|
53
54
|
...config,
|
|
54
55
|
},
|
|
55
56
|
resolve,
|
|
56
|
-
value:
|
|
57
|
+
value: newValue,
|
|
57
58
|
});
|
|
58
59
|
});
|
|
59
60
|
},
|
|
@@ -70,27 +71,53 @@ export function trigger<T = any>(globalConfig?: T): Trigger<T> {
|
|
|
70
71
|
* Subscribes to a trigger and executes a callback when the trigger is activated
|
|
71
72
|
* @param triggerSignal - The trigger to subscribe to
|
|
72
73
|
* @param callback - Function to execute when the trigger is activated
|
|
74
|
+
* @returns Subscription that can be unsubscribed to stop listening
|
|
73
75
|
* @throws Error if triggerSignal is not a valid trigger
|
|
74
76
|
* @example
|
|
75
77
|
* ```ts
|
|
76
78
|
* const click = trigger()
|
|
77
79
|
*
|
|
78
|
-
* on(click, () => {
|
|
80
|
+
* const subscription = on(click, () => {
|
|
79
81
|
* console.log('Click triggered')
|
|
80
82
|
* })
|
|
83
|
+
*
|
|
84
|
+
* // Later, to stop listening:
|
|
85
|
+
* subscription.unsubscribe()
|
|
81
86
|
* ```
|
|
82
87
|
*/
|
|
83
88
|
export function on(triggerSignal: any, callback: (config: any) => void | Promise<void>) {
|
|
84
89
|
if (!isTrigger(triggerSignal)) {
|
|
85
90
|
throw new Error("In 'on(arg)' must have a trigger signal type");
|
|
86
91
|
}
|
|
87
|
-
|
|
92
|
+
let lastValue: number | undefined;
|
|
93
|
+
|
|
94
|
+
const effectResult = effect(() => {
|
|
88
95
|
const result = triggerSignal.listen();
|
|
89
|
-
|
|
96
|
+
const seed = result?.seed;
|
|
97
|
+
|
|
98
|
+
if (!seed) return;
|
|
99
|
+
|
|
100
|
+
// Only run callback when the trigger value actually changes
|
|
101
|
+
if (lastValue === undefined) {
|
|
102
|
+
lastValue = seed.value;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (seed.value === lastValue) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
lastValue = seed.value;
|
|
109
|
+
|
|
110
|
+
try {
|
|
90
111
|
const ret = callback(result?.seed.config);
|
|
91
112
|
if (ret && typeof ret.then === 'function') {
|
|
92
|
-
ret.then(
|
|
113
|
+
ret.then((value: any) => seed.resolve(value)).catch(() => seed.resolve(undefined));
|
|
114
|
+
} else {
|
|
115
|
+
seed.resolve(ret);
|
|
93
116
|
}
|
|
117
|
+
} catch (err) {
|
|
118
|
+
seed.resolve(undefined);
|
|
94
119
|
}
|
|
95
120
|
});
|
|
121
|
+
|
|
122
|
+
return effectResult.subscription;
|
|
96
123
|
}
|
package/src/engine/utils.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { isSignal } from "@signe/reactive"
|
|
1
2
|
import { ObservablePoint } from "pixi.js"
|
|
3
|
+
import { Observable } from "rxjs"
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* Checks if code is running in a browser environment
|
|
@@ -86,12 +88,23 @@ export function isFunction(val: unknown): boolean {
|
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
/**
|
|
89
|
-
* Checks if a value is a plain object
|
|
91
|
+
* Checks if a value is a plain object (not an instance of a class)
|
|
90
92
|
* @param {unknown} val - Value to check
|
|
91
|
-
* @returns {boolean} True if value is
|
|
93
|
+
* @returns {boolean} True if value is a plain object (not null, not array, not instance), false otherwise
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* isObject({}) // true
|
|
97
|
+
* isObject(new Date()) // false
|
|
98
|
+
* isObject([]) // false
|
|
99
|
+
* isObject(null) // false
|
|
100
|
+
* ```
|
|
92
101
|
*/
|
|
93
102
|
export function isObject(val: unknown): boolean {
|
|
94
|
-
return typeof val == 'object' && val != null && !Array.isArray(val)
|
|
103
|
+
return typeof val == 'object' && val != null && !Array.isArray(val) && val.constructor === Object
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function isObservable(val: unknown): boolean {
|
|
107
|
+
return val instanceof Observable
|
|
95
108
|
}
|
|
96
109
|
|
|
97
110
|
/**
|
|
@@ -186,6 +199,9 @@ export function setObservablePoint(
|
|
|
186
199
|
else if (Array.isArray(point)) {
|
|
187
200
|
observablePoint.set(point[0], point[1]);
|
|
188
201
|
}
|
|
202
|
+
else if (isObject(point) && 'value' in point) {
|
|
203
|
+
observablePoint.set((point as any).value.x, (point as any).value.y);
|
|
204
|
+
}
|
|
189
205
|
else {
|
|
190
206
|
observablePoint.set(point.x, point.y);
|
|
191
207
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Signal } from "@signe/reactive";
|
|
2
|
+
import { Element } from "../engine/reactive";
|
|
3
|
+
import { focusManager } from "../engine/FocusManager";
|
|
4
|
+
import { effect } from "@signe/reactive";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get the current focus index signal for a container
|
|
8
|
+
*
|
|
9
|
+
* Returns a reactive signal that updates when the focus index changes.
|
|
10
|
+
*
|
|
11
|
+
* @param containerId - Container identifier
|
|
12
|
+
* @returns Signal for current focus index, or null if container not found
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const focusIndex = useFocusIndex('myContainer');
|
|
17
|
+
* effect(() => {
|
|
18
|
+
* console.log('Current focus index:', focusIndex?.());
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function useFocusIndex(containerId: string): Signal<number | null> | null {
|
|
23
|
+
return focusManager.getCurrentIndexSignal(containerId);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get the current focused element signal for a container
|
|
28
|
+
*
|
|
29
|
+
* Returns a reactive signal that updates when the focused element changes.
|
|
30
|
+
*
|
|
31
|
+
* @param containerId - Container identifier
|
|
32
|
+
* @returns Signal for current focused element, or null if container not found
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const focusedElement = useFocusedElement('myContainer');
|
|
37
|
+
* effect(() => {
|
|
38
|
+
* const element = focusedElement?.();
|
|
39
|
+
* if (element) {
|
|
40
|
+
* console.log('Focused element:', element);
|
|
41
|
+
* }
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function useFocusedElement(containerId: string): Signal<Element | null> | null {
|
|
46
|
+
return focusManager.getFocusedElementSignal(containerId);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Hook to react to focus changes
|
|
51
|
+
*
|
|
52
|
+
* Sets up a reactive effect that calls the callback whenever the focus changes.
|
|
53
|
+
*
|
|
54
|
+
* @param containerId - Container identifier
|
|
55
|
+
* @param callback - Function to call when focus changes
|
|
56
|
+
* @returns Cleanup function to unsubscribe
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* useFocusChange('myContainer', (index, element) => {
|
|
61
|
+
* console.log('Focus changed to index', index);
|
|
62
|
+
* if (element) {
|
|
63
|
+
* console.log('Focused element:', element);
|
|
64
|
+
* }
|
|
65
|
+
* });
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export function useFocusChange(
|
|
69
|
+
containerId: string,
|
|
70
|
+
callback: (index: number | null, element: Element | null) => void
|
|
71
|
+
): () => void {
|
|
72
|
+
const indexSignal = focusManager.getCurrentIndexSignal(containerId);
|
|
73
|
+
const elementSignal = focusManager.getFocusedElementSignal(containerId);
|
|
74
|
+
|
|
75
|
+
if (!indexSignal || !elementSignal) {
|
|
76
|
+
console.warn(`FocusContainer with id "${containerId}" not found`);
|
|
77
|
+
return () => {};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Set up reactive effect
|
|
81
|
+
const effectResult = effect(() => {
|
|
82
|
+
const index = indexSignal();
|
|
83
|
+
const element = elementSignal();
|
|
84
|
+
callback(index, element);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Return cleanup function
|
|
88
|
+
return () => {
|
|
89
|
+
effectResult.subscription?.unsubscribe();
|
|
90
|
+
};
|
|
91
|
+
}
|
package/src/hooks/useProps.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
export * from './directives'
|
|
2
3
|
export * from '@signe/reactive'
|
|
3
4
|
export { Howler } from 'howler'
|
|
4
5
|
export * from './components'
|
|
5
6
|
export * from './engine/reactive'
|
|
7
|
+
export { registerAllComponents } from './engine/reactive'
|
|
6
8
|
export * from './engine/signal'
|
|
7
9
|
export * from './engine/trigger'
|
|
8
10
|
export * from './engine/bootstrap'
|
|
9
11
|
export * from './engine/animation'
|
|
12
|
+
export { FocusManager, focusManager, type ScrollOptions } from './engine/FocusManager'
|
|
10
13
|
export { useProps, useDefineProps } from './hooks/useProps'
|
|
14
|
+
export { useFocusIndex, useFocusedElement, useFocusChange } from './hooks/useFocus'
|
|
11
15
|
export * from './utils/Ease'
|
|
12
16
|
export * from './utils/RadialGradient'
|
|
17
|
+
export * from './utils/tabindex'
|
|
13
18
|
export * from './components/DisplayObject'
|
|
14
19
|
export { isObservable } from 'rxjs'
|
|
15
|
-
export * as Utils from './engine/utils'
|
|
20
|
+
export * as Utils from './engine/utils'
|
|
21
|
+
export * as Howl from 'howler'
|