canvasengine 2.0.0-beta.14 → 2.0.0-beta.15
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/index.d.ts +3 -0
- package/dist/index.js +103 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Sprite.ts +8 -2
- package/src/directives/Drag.ts +92 -5
- package/src/directives/Sound.ts +5 -4
- package/src/engine/reactive.ts +30 -0
- package/src/index.ts +2 -1
package/package.json
CHANGED
package/src/components/Sprite.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Howl } from 'howler';
|
|
2
|
+
import { computed, effect, isSignal, Signal } from "@signe/reactive";
|
|
2
3
|
import {
|
|
3
4
|
Assets,
|
|
4
5
|
Container,
|
|
@@ -338,7 +339,12 @@ export class CanvasSprite extends DisplayObject(PixiSprite) {
|
|
|
338
339
|
const sound = this.currentAnimation.data.sound;
|
|
339
340
|
|
|
340
341
|
if (sound) {
|
|
341
|
-
|
|
342
|
+
new Howl({
|
|
343
|
+
src: sound,
|
|
344
|
+
autoplay: true,
|
|
345
|
+
loop: false,
|
|
346
|
+
volume: 1,
|
|
347
|
+
})
|
|
342
348
|
}
|
|
343
349
|
|
|
344
350
|
// Updates immediately to avoid flickering
|
package/src/directives/Drag.ts
CHANGED
|
@@ -14,6 +14,7 @@ export type DragProps = {
|
|
|
14
14
|
end?: () => void;
|
|
15
15
|
snap?: SignalOrPrimitive<number>;
|
|
16
16
|
direction?: SignalOrPrimitive<'x' | 'y' | 'all'>;
|
|
17
|
+
keyToPress?: SignalOrPrimitive<string[]>;
|
|
17
18
|
viewport?: {
|
|
18
19
|
edgeThreshold?: SignalOrPrimitive<number>;
|
|
19
20
|
maxSpeed?: SignalOrPrimitive<number>;
|
|
@@ -46,10 +47,14 @@ export class Drag extends Directive {
|
|
|
46
47
|
private viewport: any | null = null;
|
|
47
48
|
private animationFrameId: number | null = null;
|
|
48
49
|
private lastPointerPosition: Point = new Point();
|
|
50
|
+
private pressedKeys: Set<string> = new Set();
|
|
51
|
+
private pointerIsDown = false;
|
|
49
52
|
|
|
50
53
|
private onDragMoveHandler: (event: FederatedPointerEvent) => void = () => {};
|
|
51
54
|
private onDragEndHandler: () => void = () => {};
|
|
52
55
|
private onDragStartHandler: (event: FederatedPointerEvent) => void = () => {};
|
|
56
|
+
private onKeyDownHandler: (event: KeyboardEvent) => void = () => {};
|
|
57
|
+
private onKeyUpHandler: (event: KeyboardEvent) => void = () => {};
|
|
53
58
|
|
|
54
59
|
private subscriptions: Subscription[] = [];
|
|
55
60
|
|
|
@@ -58,6 +63,8 @@ export class Drag extends Directive {
|
|
|
58
63
|
this.onDragMoveHandler = this.onDragMove.bind(this);
|
|
59
64
|
this.onDragEndHandler = this.onDragEnd.bind(this);
|
|
60
65
|
this.onDragStartHandler = this.onPointerDown.bind(this);
|
|
66
|
+
this.onKeyDownHandler = this.onKeyDown.bind(this);
|
|
67
|
+
this.onKeyUpHandler = this.onKeyUp.bind(this);
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
onMount(element: Element<Container>) {
|
|
@@ -89,6 +96,12 @@ export class Drag extends Directive {
|
|
|
89
96
|
this.stageRef.on('pointerup', this.onDragEndHandler);
|
|
90
97
|
this.stageRef.on('pointerupoutside', this.onDragEndHandler);
|
|
91
98
|
|
|
99
|
+
const keysToPress = dragProps.keyToPress ? dragProps.keyToPress : [];
|
|
100
|
+
|
|
101
|
+
// Always add keyboard event listeners to track pressed keys
|
|
102
|
+
window.addEventListener('keydown', this.onKeyDownHandler);
|
|
103
|
+
window.addEventListener('keyup', this.onKeyUpHandler);
|
|
104
|
+
|
|
92
105
|
this.subscriptions = [
|
|
93
106
|
tick.observable.subscribe(() => {
|
|
94
107
|
if (this.isDragging && this.viewport) {
|
|
@@ -104,7 +117,8 @@ export class Drag extends Directive {
|
|
|
104
117
|
const options = useProps(drag?.value ?? drag, {
|
|
105
118
|
snap: 0,
|
|
106
119
|
viewport: {},
|
|
107
|
-
direction: 'all'
|
|
120
|
+
direction: 'all',
|
|
121
|
+
keyToPress: []
|
|
108
122
|
});
|
|
109
123
|
options.viewport = useProps(options.viewport, {
|
|
110
124
|
edgeThreshold: 300,
|
|
@@ -243,10 +257,13 @@ export class Drag extends Directive {
|
|
|
243
257
|
* Handles drag end event and stops viewport movement
|
|
244
258
|
*/
|
|
245
259
|
private onDragEnd() {
|
|
246
|
-
|
|
260
|
+
this.pointerIsDown = false;
|
|
261
|
+
|
|
262
|
+
if (!this.isDragging) return;
|
|
247
263
|
|
|
248
264
|
const dragProps = this.dragProps;
|
|
249
265
|
this.isDragging = false;
|
|
266
|
+
|
|
250
267
|
dragProps?.end?.();
|
|
251
268
|
|
|
252
269
|
if (this.stageRef) {
|
|
@@ -254,23 +271,86 @@ export class Drag extends Directive {
|
|
|
254
271
|
}
|
|
255
272
|
}
|
|
256
273
|
|
|
274
|
+
onKeyDown(event: KeyboardEvent) {
|
|
275
|
+
this.pressedKeys.add(event.code);
|
|
276
|
+
this.pressedKeys.add(event.key.toLowerCase());
|
|
277
|
+
|
|
278
|
+
if (this.pointerIsDown && !this.isDragging && this.areRequiredKeysPressed()) {
|
|
279
|
+
this.startDrag();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
onKeyUp(event: KeyboardEvent) {
|
|
284
|
+
this.pressedKeys.delete(event.code);
|
|
285
|
+
this.pressedKeys.delete(event.key.toLowerCase());
|
|
286
|
+
if (this.isDragging && !this.areRequiredKeysPressed()) {
|
|
287
|
+
this.onDragEnd();
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
private areRequiredKeysPressed(): boolean {
|
|
292
|
+
const keyToPress = this.dragProps.keyToPress ? this.dragProps.keyToPress : [];
|
|
293
|
+
if (!keyToPress || keyToPress.length === 0) {
|
|
294
|
+
return true; // No keys required, always return true
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return keyToPress.some(key => {
|
|
298
|
+
// Check if the key is pressed directly
|
|
299
|
+
if (this.pressedKeys.has(key)) {
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Check common alternative formats
|
|
304
|
+
// Space key can be "Space", " ", or "space"
|
|
305
|
+
if (key.toLowerCase() === 'space') {
|
|
306
|
+
return this.pressedKeys.has('Space') || this.pressedKeys.has(' ');
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Shift key can be "ShiftLeft", "ShiftRight", or "shift"
|
|
310
|
+
if (key.toLowerCase() === 'shift') {
|
|
311
|
+
return this.pressedKeys.has('ShiftLeft') || this.pressedKeys.has('ShiftRight');
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Control key can be "ControlLeft", "ControlRight", or "control"
|
|
315
|
+
if (key.toLowerCase() === 'control' || key.toLowerCase() === 'ctrl') {
|
|
316
|
+
return this.pressedKeys.has('ControlLeft') || this.pressedKeys.has('ControlRight');
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Alt key can be "AltLeft", "AltRight", or "alt"
|
|
320
|
+
if (key.toLowerCase() === 'alt') {
|
|
321
|
+
return this.pressedKeys.has('AltLeft') || this.pressedKeys.has('AltRight');
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return false;
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
|
|
257
328
|
private onPointerDown(event: FederatedPointerEvent) {
|
|
258
329
|
if (!this.elementRef?.componentInstance || !this.stageRef || !this.elementRef.componentInstance.parent) return;
|
|
330
|
+
|
|
331
|
+
this.pointerIsDown = true;
|
|
259
332
|
|
|
260
333
|
const instance = this.elementRef.componentInstance;
|
|
261
334
|
const parent = instance.parent;
|
|
262
|
-
const dragProps = this.dragProps;
|
|
263
335
|
|
|
264
336
|
const parentLocalPointer = parent.toLocal(event.global);
|
|
265
337
|
|
|
266
338
|
this.offsetInParent.x = parentLocalPointer.x - instance.position.x;
|
|
267
339
|
this.offsetInParent.y = parentLocalPointer.y - instance.position.y;
|
|
268
|
-
|
|
269
|
-
this.isDragging = true;
|
|
270
340
|
|
|
271
341
|
// Store initial pointer position
|
|
272
342
|
this.lastPointerPosition.copyFrom(event.global);
|
|
273
343
|
|
|
344
|
+
if (this.areRequiredKeysPressed()) {
|
|
345
|
+
this.startDrag();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
private startDrag() {
|
|
350
|
+
if (this.isDragging || !this.stageRef) return;
|
|
351
|
+
|
|
352
|
+
this.isDragging = true;
|
|
353
|
+
const dragProps = this.dragProps;
|
|
274
354
|
dragProps?.start?.();
|
|
275
355
|
this.stageRef.on('pointermove', this.onDragMoveHandler);
|
|
276
356
|
}
|
|
@@ -293,8 +373,15 @@ export class Drag extends Directive {
|
|
|
293
373
|
this.stageRef.off('pointerup', this.onDragEndHandler);
|
|
294
374
|
this.stageRef.off('pointerupoutside', this.onDragEndHandler);
|
|
295
375
|
}
|
|
376
|
+
|
|
377
|
+
// Remove keyboard event listeners
|
|
378
|
+
window.removeEventListener('keydown', this.onKeyDownHandler);
|
|
379
|
+
window.removeEventListener('keyup', this.onKeyUpHandler);
|
|
380
|
+
|
|
296
381
|
this.stageRef = null;
|
|
297
382
|
this.viewport = null;
|
|
383
|
+
this.pressedKeys.clear();
|
|
384
|
+
this.pointerIsDown = false;
|
|
298
385
|
}
|
|
299
386
|
}
|
|
300
387
|
|
package/src/directives/Sound.ts
CHANGED
|
@@ -20,7 +20,8 @@ export class Sound extends Directive {
|
|
|
20
20
|
onMount(element: Element<Container>) {
|
|
21
21
|
const { props } = element
|
|
22
22
|
const tick = props.context.tick
|
|
23
|
-
const
|
|
23
|
+
const propsSound = props.sound.value ?? props.sound
|
|
24
|
+
const { src, autoplay, loop, volume, spatial } = propsSound
|
|
24
25
|
this.sound = new Howl({
|
|
25
26
|
src,
|
|
26
27
|
autoplay,
|
|
@@ -28,8 +29,8 @@ export class Sound extends Directive {
|
|
|
28
29
|
volume
|
|
29
30
|
})
|
|
30
31
|
for (let event of EVENTS) {
|
|
31
|
-
if (!
|
|
32
|
-
const fn =
|
|
32
|
+
if (!propsSound[event]) continue
|
|
33
|
+
const fn = propsSound[event]
|
|
33
34
|
this.eventsFn.push(fn)
|
|
34
35
|
this.sound.on(event, fn);
|
|
35
36
|
}
|
|
@@ -51,7 +52,7 @@ export class Sound extends Directive {
|
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
onUpdate(props: any) {
|
|
54
|
-
const { volume, loop, mute, seek, playing, rate, spatial } = props
|
|
55
|
+
const { volume, loop, mute, seek, playing, rate, spatial } = props.value ?? props
|
|
55
56
|
if (volume != undefined) this.sound.volume(volume)
|
|
56
57
|
if (loop != undefined) this.sound.loop(loop)
|
|
57
58
|
if (mute != undefined) this.sound.mute(mute)
|
package/src/engine/reactive.ts
CHANGED
|
@@ -365,6 +365,36 @@ export function loop<T>(
|
|
|
365
365
|
el.destroy();
|
|
366
366
|
elementMap.delete(change.index!);
|
|
367
367
|
});
|
|
368
|
+
} else if (change.type === 'update' && change.index !== undefined && change.items.length === 1) {
|
|
369
|
+
const index = change.index;
|
|
370
|
+
const newItem = change.items[0];
|
|
371
|
+
|
|
372
|
+
// Check if the previous item at this index was effectively undefined or non-existent
|
|
373
|
+
if (index >= elements.length || elements[index] === undefined || !elementMap.has(index)) {
|
|
374
|
+
// Treat as add operation
|
|
375
|
+
const newElement = createElementFn(newItem as T, index);
|
|
376
|
+
if (newElement) {
|
|
377
|
+
elements.splice(index, 0, newElement); // Insert at the correct index
|
|
378
|
+
elementMap.set(index, newElement);
|
|
379
|
+
// Adjust indices in elementMap for subsequent elements might be needed if map relied on exact indices
|
|
380
|
+
// This simple implementation assumes keys are stable or createElementFn handles context correctly
|
|
381
|
+
} else {
|
|
382
|
+
console.warn(`Element creation returned null for index ${index} during add-like update.`);
|
|
383
|
+
}
|
|
384
|
+
} else {
|
|
385
|
+
// Treat as a standard update operation
|
|
386
|
+
const oldElement = elements[index];
|
|
387
|
+
oldElement.destroy();
|
|
388
|
+
const newElement = createElementFn(newItem as T, index);
|
|
389
|
+
if (newElement) {
|
|
390
|
+
elements[index] = newElement;
|
|
391
|
+
elementMap.set(index, newElement);
|
|
392
|
+
} else {
|
|
393
|
+
// Handle case where new element creation returns null
|
|
394
|
+
elements.splice(index, 1);
|
|
395
|
+
elementMap.delete(index);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
368
398
|
}
|
|
369
399
|
|
|
370
400
|
subscriber.next({
|
package/src/index.ts
CHANGED
|
@@ -12,4 +12,5 @@ export * from './utils/Ease'
|
|
|
12
12
|
export * from './utils/RadialGradient'
|
|
13
13
|
export * from './components/DisplayObject'
|
|
14
14
|
export { isObservable } from 'rxjs'
|
|
15
|
-
export * as Utils from './engine/utils'
|
|
15
|
+
export * as Utils from './engine/utils'
|
|
16
|
+
export * as Howl from 'howler'
|