canvasengine 2.0.0-beta.13 → 2.0.0-beta.14

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/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "canvasengine",
3
- "version": "2.0.0-beta.13",
3
+ "version": "2.0.0-beta.14",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "dependencies": {
8
8
  "@barvynkoa/particle-emitter": "^0.0.1",
9
- "@signe/reactive": "^1.1.0",
9
+ "@signe/reactive": "^2.3.3",
10
10
  "howler": "^2.2.4",
11
11
  "pixi-filters": "^6.0.5",
12
12
  "pixi-viewport": "^6.0.3",
@@ -1,35 +1,31 @@
1
- import { effect, Signal } from "@signe/reactive";
1
+ import { Effect, effect, Signal } from "@signe/reactive";
2
2
  import { Graphics as PixiGraphics } from "pixi.js";
3
3
  import { createComponent, registerComponent } from "../engine/reactive";
4
4
  import { DisplayObject } from "./DisplayObject";
5
5
  import { DisplayObjectProps } from "./types/DisplayObject";
6
6
  import { useProps } from "../hooks/useProps";
7
+ import { SignalOrPrimitive } from "./types";
7
8
 
8
9
  interface GraphicsProps extends DisplayObjectProps {
9
10
  draw?: (graphics: PixiGraphics) => void;
10
11
  }
11
12
 
12
13
  interface RectProps extends DisplayObjectProps {
13
- width: number;
14
- height: number;
15
- color: string;
14
+ color: SignalOrPrimitive<string>;
16
15
  }
17
16
 
18
17
  interface CircleProps extends DisplayObjectProps {
19
- radius: number;
20
- color: string;
18
+ radius: SignalOrPrimitive<number>;
19
+ color: SignalOrPrimitive<string>;
21
20
  }
22
21
 
23
22
  interface EllipseProps extends DisplayObjectProps {
24
- width: number;
25
- height: number;
26
- color: string;
23
+ color: SignalOrPrimitive<string>;
27
24
  }
28
25
 
29
26
  interface TriangleProps extends DisplayObjectProps {
30
- base: number;
31
- height: number;
32
- color: string;
27
+ base: SignalOrPrimitive<number>;
28
+ color: SignalOrPrimitive<string>;
33
29
  }
34
30
 
35
31
  interface SvgProps extends DisplayObjectProps {
@@ -37,15 +33,21 @@ interface SvgProps extends DisplayObjectProps {
37
33
  }
38
34
 
39
35
  class CanvasGraphics extends DisplayObject(PixiGraphics) {
36
+ clearEffect: Effect;
40
37
  onInit(props) {
41
38
  super.onInit(props);
42
39
  if (props.draw) {
43
- effect(() => {
40
+ this.clearEffect = effect(() => {
44
41
  this.clear();
45
42
  props.draw?.(this);
46
43
  });
47
44
  }
48
45
  }
46
+
47
+ onDestroy() {
48
+ this.clearEffect.subscription.unsubscribe();
49
+ super.onDestroy();
50
+ }
49
51
  }
50
52
 
51
53
  interface CanvasGraphics extends PixiGraphics {}
@@ -1,5 +1,7 @@
1
1
  import * as PIXI from "pixi.js";
2
2
  import { SignalOrPrimitive } from ".";
3
+ import { DragProps } from "../../directives/Drag";
4
+ import { ViewportFollowProps } from "../../directives/ViewportFollow";
3
5
 
4
6
  export type FlexDirection = 'row' | 'column' | 'row-reverse' | 'column-reverse';
5
7
  export type JustifyContent = 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around';
@@ -37,6 +39,11 @@ export interface DisplayObjectProps {
37
39
  blendMode?: SignalOrPrimitive<PIXI.BLEND_MODES>;
38
40
  blur?: SignalOrPrimitive<number>;
39
41
 
42
+ // Directives
43
+ drag?: DragProps;
44
+ viewportFollow?: ViewportFollowProps;
45
+
46
+ // Events
40
47
  click?: PIXI.FederatedEventHandler;
41
48
  mousedown?: PIXI.FederatedEventHandler;
42
49
  mouseenter?: PIXI.FederatedEventHandler;
@@ -1,4 +1,4 @@
1
- import { effect, isSignal, signal } from '@signe/reactive';
1
+ import { effect, isComputed, isSignal, signal } from '@signe/reactive';
2
2
  import { Container, Rectangle, Point, FederatedPointerEvent } from 'pixi.js';
3
3
  import { Directive, registerDirective } from '../engine/directive';
4
4
  import { Element } from '../engine/reactive';
@@ -6,6 +6,19 @@ import { snap } from 'popmotion';
6
6
  import { addContext } from '../hooks/addContext';
7
7
  import { Subscription } from 'rxjs';
8
8
  import { useProps } from '../hooks/useProps';
9
+ import { SignalOrPrimitive } from '../components/types';
10
+
11
+ export type DragProps = {
12
+ move?: (event: FederatedPointerEvent) => void;
13
+ start?: () => void;
14
+ end?: () => void;
15
+ snap?: SignalOrPrimitive<number>;
16
+ direction?: SignalOrPrimitive<'x' | 'y' | 'all'>;
17
+ viewport?: {
18
+ edgeThreshold?: SignalOrPrimitive<number>;
19
+ maxSpeed?: SignalOrPrimitive<number>;
20
+ };
21
+ }
9
22
 
10
23
  export class Drop extends Directive {
11
24
  private elementRef: Element<Container> | null = null;
@@ -147,12 +160,19 @@ export class Drag extends Directive {
147
160
  this.lastPointerPosition.copyFrom(event.global);
148
161
 
149
162
  const { x: xProp, y: yProp } = propObservables as any;
150
- if (xProp !== undefined && isSignal(xProp)) {
151
- // xProp.set(instance.position.x)
152
- }
153
- if (yProp !== undefined && isSignal(yProp)) {
154
- // yProp.set(instance.position.y)
163
+
164
+ const updatePosition = (prop: any, value: number) => {
165
+ if (isComputed(prop)) {
166
+ prop.dependencies.forEach(dependency => {
167
+ dependency.set(value)
168
+ })
169
+ } else if (isSignal(prop)) {
170
+ prop.set(value)
171
+ }
155
172
  }
173
+
174
+ if (xProp !== undefined) updatePosition(xProp, instance.position.x)
175
+ if (yProp !== undefined) updatePosition(yProp, instance.position.y)
156
176
  }
157
177
 
158
178
  /**
@@ -1,23 +1,45 @@
1
1
  import { ComponentInstance } from '../components/DisplayObject';
2
+ import { SignalOrPrimitive } from '../components/types';
2
3
  import { Directive, registerDirective } from '../engine/directive';
3
4
  import { Element } from '../engine/reactive';
4
5
  import { error } from '../engine/utils';
6
+ import { useProps } from '../hooks/useProps';
7
+
8
+ export type ViewportFollowProps = {
9
+ viewportFollow?: boolean | {
10
+ speed?: SignalOrPrimitive<number>;
11
+ acceleration?: SignalOrPrimitive<number>;
12
+ radius?: SignalOrPrimitive<number>;
13
+ };
14
+ }
5
15
 
6
16
  export class ViewportFollow extends Directive {
7
17
  onInit(element: Element<ComponentInstance>) {
8
18
 
9
19
  }
10
20
  onMount(element: Element) {
11
- this.onUpdate(element.props, element)
21
+ this.onUpdate(element.props.viewportFollow, element)
12
22
  }
13
- onUpdate(props: any, element: Element) {
14
- const { viewportFollow } = element.props
23
+ onUpdate(viewportFollow: any, element: Element) {
15
24
  const { viewport } = element.props.context
16
25
  if (!viewport) {
17
26
  throw error('ViewportFollow directive requires a Viewport component to be mounted in the same context')
18
27
  }
19
28
  if (viewportFollow) {
20
- viewport.follow(element.componentInstance)
29
+ if (viewportFollow === true) {
30
+ viewport.follow(element.componentInstance)
31
+ } else {
32
+ const options = useProps(viewportFollow, {
33
+ speed: undefined,
34
+ acceleration: undefined,
35
+ radius: undefined
36
+ })
37
+ viewport.follow(element.componentInstance, {
38
+ speed: options.speed(),
39
+ acceleration: options.acceleration(),
40
+ radius: options.radius()
41
+ })
42
+ }
21
43
  } else {
22
44
  viewport.plugins.remove('follow')
23
45
  }
@@ -1,4 +1,4 @@
1
- import { Signal, WritableArraySignal, WritableObjectSignal, isSignal } from "@signe/reactive";
1
+ import { ArrayChange, ObjectChange, Signal, WritableArraySignal, WritableObjectSignal, isComputed, isSignal, signal } from "@signe/reactive";
2
2
  import {
3
3
  Observable,
4
4
  Subject,
@@ -17,25 +17,6 @@ export interface Props {
17
17
  [key: string]: any;
18
18
  }
19
19
 
20
- export type ArrayChange<T> = {
21
- type: "add" | "remove" | "update" | "init" | "reset";
22
- index?: number;
23
- items: T[];
24
- };
25
-
26
- export type ObjectChange<T> = {
27
- type: "add" | "remove" | "update" | "init" | "reset";
28
- key?: string;
29
- value?: T;
30
- items: T[];
31
- };
32
-
33
- type ElementObservable<T> = Observable<
34
- (ArrayChange<T> | ObjectChange<T>) & {
35
- value: Element | Element[];
36
- }
37
- >;
38
-
39
20
  type NestedSignalObjects = {
40
21
  [Key in string]: NestedSignalObjects | Signal<any>;
41
22
  };
@@ -104,11 +85,11 @@ function destroyElement(element: Element | Element[]) {
104
85
  }
105
86
  element.propSubscriptions.forEach((sub) => sub.unsubscribe());
106
87
  element.effectSubscriptions.forEach((sub) => sub.unsubscribe());
88
+ element.effectUnmounts.forEach((fn) => fn?.());
107
89
  for (let name in element.directives) {
108
90
  element.directives[name].onDestroy?.(element);
109
91
  }
110
92
  element.componentInstance.onDestroy?.(element.parent as any);
111
- element.effectUnmounts.forEach((fn) => fn?.());
112
93
  }
113
94
 
114
95
  /**
@@ -309,9 +290,17 @@ export function createComponent(tag: string, props?: Props): Element {
309
290
  * @returns {Observable} An observable that emits the list of created child elements.
310
291
  */
311
292
  export function loop<T>(
312
- itemsSubject: WritableArraySignal<T[]> | WritableObjectSignal<T>,
293
+ itemsSubject: any,
313
294
  createElementFn: (item: T, index: number | string) => Element | null
314
295
  ): FlowObservable {
296
+
297
+ if (isComputed(itemsSubject) && itemsSubject.dependencies.size == 0) {
298
+ itemsSubject = signal(itemsSubject());
299
+ }
300
+ else if (!isSignal(itemsSubject)) {
301
+ itemsSubject = signal(itemsSubject);
302
+ }
303
+
315
304
  return defer(() => {
316
305
  let elements: Element[] = [];
317
306
  let elementMap = new Map<string | number, Element>();