canvasengine 2.0.0-beta.38 → 2.0.0-beta.39

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.
Files changed (32) hide show
  1. package/dist/{DebugRenderer-DxJSMb9B.js → DebugRenderer-Rrw9FlTd.js} +2 -2
  2. package/dist/{DebugRenderer-DxJSMb9B.js.map → DebugRenderer-Rrw9FlTd.js.map} +1 -1
  3. package/dist/components/Button.d.ts +50 -3
  4. package/dist/components/Button.d.ts.map +1 -1
  5. package/dist/components/Joystick.d.ts +36 -0
  6. package/dist/components/Joystick.d.ts.map +1 -0
  7. package/dist/components/index.d.ts +1 -0
  8. package/dist/components/index.d.ts.map +1 -1
  9. package/dist/directives/Controls.d.ts +16 -7
  10. package/dist/directives/Controls.d.ts.map +1 -1
  11. package/dist/directives/GamepadControls.d.ts +3 -1
  12. package/dist/directives/GamepadControls.d.ts.map +1 -1
  13. package/dist/directives/JoystickControls.d.ts +172 -0
  14. package/dist/directives/JoystickControls.d.ts.map +1 -0
  15. package/dist/directives/index.d.ts +1 -0
  16. package/dist/directives/index.d.ts.map +1 -1
  17. package/dist/engine/reactive.d.ts.map +1 -1
  18. package/dist/{index-BgNWflRE.js → index-BQ99FClW.js} +5543 -5141
  19. package/dist/index-BQ99FClW.js.map +1 -0
  20. package/dist/index.global.js +7 -7
  21. package/dist/index.global.js.map +1 -1
  22. package/dist/index.js +59 -57
  23. package/package.json +1 -1
  24. package/src/components/Button.ts +168 -41
  25. package/src/components/Joystick.ts +361 -0
  26. package/src/components/index.ts +2 -1
  27. package/src/directives/Controls.ts +42 -8
  28. package/src/directives/GamepadControls.ts +40 -11
  29. package/src/directives/JoystickControls.ts +396 -0
  30. package/src/directives/index.ts +1 -0
  31. package/src/engine/reactive.ts +41 -14
  32. package/dist/index-BgNWflRE.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { h as a } from "./index-BgNWflRE.js";
2
- import { A as r, X as o, Y as n, q as l, v as c, r as p, C as S, d as u, U as m, W as g, ai as d, f as b, D as C, ah as h, af as T, w as j, j as w, G as D, t as f, c as v, I as E, K as O, M as k, Q as y, O as P, P as V, ag as x, R as A, z as B, S as G, g as H, e as M, B as N, y as R, J as q, L as F, T as I, x as K, b as U, H as z, N as J, V as L, ae as Q, ad as W, ab as X, k as Y, a2 as Z, a0 as _, a3 as $, l as aa, a7 as sa, ac as ea, m as ta, n as ia, Z as ra, o as oa, i as na, _ as la, p as ca, a8 as pa, a1 as Sa, a5 as ua, a4 as ma, aa as ga, $ as da, s as ba, a6 as Ca, a9 as ha, a as Ta, u as ja } from "./index-BgNWflRE.js";
1
+ import { h as a } from "./index-BQ99FClW.js";
2
+ import { A as r, Y as o, Z as n, q as l, v as c, r as p, C as S, d as u, W as m, X as g, ak as d, f as b, D as C, aj as h, ah as j, w as T, j as k, G as w, t as D, c as f, I as v, _ as y, J as E, K as O, M as P, U as V, O as x, P as A, ai as B, R as G, z as H, S as M, g as J, e as N, B as R, y as q, L as F, N as I, T as K, x as U, b as z, H as L, Q, V as W, ag as X, af as Y, ad as Z, k as _, a4 as $, a2 as aa, a5 as sa, l as ea, a9 as ta, ae as ia, m as ra, n as oa, $ as na, o as la, i as ca, a0 as pa, p as Sa, aa as ua, a3 as ma, a7 as ga, a6 as da, ac as ba, a1 as Ca, s as ha, a8 as ja, ab as Ta, a as ka, u as wa } from "./index-BQ99FClW.js";
3
3
  const e = a.Howler;
4
4
  export {
5
5
  r as ArraySubject,
@@ -16,62 +16,64 @@ export {
16
16
  b as Drag,
17
17
  C as Drop,
18
18
  h as EVENTS,
19
- T as Easing,
20
- j as Ellipse,
21
- w as Flash,
22
- D as GamepadControls,
23
- f as Graphics,
24
- v as Howl,
19
+ j as Easing,
20
+ T as Ellipse,
21
+ k as Flash,
22
+ w as GamepadControls,
23
+ D as Graphics,
24
+ f as Howl,
25
25
  e as Howler,
26
- E as Input,
26
+ v as Input,
27
+ y as Joystick,
28
+ E as JoystickControls,
27
29
  O as KeyboardControls,
28
- k as Mesh,
29
- y as NineSliceSprite,
30
- P as ObjectSubject,
31
- V as ParticlesEmitter,
32
- x as RadialGradient,
33
- A as Rect,
34
- B as Scene,
35
- G as Scheduler,
36
- H as Shake,
37
- M as Sound,
38
- N as Sprite,
39
- R as Svg,
40
- q as Text,
41
- F as TilingSprite,
42
- I as Transition,
43
- K as Triangle,
44
- U as Utils,
45
- z as Video,
46
- J as Viewport,
47
- L as ViewportFollow,
48
- Q as animatedSequence,
49
- W as animatedSignal,
50
- X as bootstrapCanvas,
51
- Y as computed,
52
- Z as cond,
53
- _ as createComponent,
54
- $ as currentSubscriptionsTracker,
55
- aa as effect,
56
- sa as h,
57
- ea as isAnimatedSignal,
58
- ta as isArraySubject,
59
- ia as isComputed,
60
- ra as isElement,
61
- oa as isObjectSubject,
62
- na as isObservable,
63
- la as isPrimitive,
64
- ca as isSignal,
65
- pa as isTrigger,
66
- Sa as loop,
67
- ua as mount,
68
- ma as mountTracker,
69
- ga as on,
70
- da as registerComponent,
71
- ba as signal,
72
- Ca as tick,
73
- ha as trigger,
74
- Ta as useDefineProps,
75
- ja as useProps
30
+ P as Mesh,
31
+ V as NineSliceSprite,
32
+ x as ObjectSubject,
33
+ A as ParticlesEmitter,
34
+ B as RadialGradient,
35
+ G as Rect,
36
+ H as Scene,
37
+ M as Scheduler,
38
+ J as Shake,
39
+ N as Sound,
40
+ R as Sprite,
41
+ q as Svg,
42
+ F as Text,
43
+ I as TilingSprite,
44
+ K as Transition,
45
+ U as Triangle,
46
+ z as Utils,
47
+ L as Video,
48
+ Q as Viewport,
49
+ W as ViewportFollow,
50
+ X as animatedSequence,
51
+ Y as animatedSignal,
52
+ Z as bootstrapCanvas,
53
+ _ as computed,
54
+ $ as cond,
55
+ aa as createComponent,
56
+ sa as currentSubscriptionsTracker,
57
+ ea as effect,
58
+ ta as h,
59
+ ia as isAnimatedSignal,
60
+ ra as isArraySubject,
61
+ oa as isComputed,
62
+ na as isElement,
63
+ la as isObjectSubject,
64
+ ca as isObservable,
65
+ pa as isPrimitive,
66
+ Sa as isSignal,
67
+ ua as isTrigger,
68
+ ma as loop,
69
+ ga as mount,
70
+ da as mountTracker,
71
+ ba as on,
72
+ Ca as registerComponent,
73
+ ha as signal,
74
+ ja as tick,
75
+ Ta as trigger,
76
+ ka as useDefineProps,
77
+ wa as useProps
76
78
  };
77
79
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvasengine",
3
- "version": "2.0.0-beta.38",
3
+ "version": "2.0.0-beta.39",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,10 +1,13 @@
1
- import { effect, signal, computed } from "@signe/reactive";
1
+ import { effect, signal, computed, isSignal } from "@signe/reactive";
2
2
  import { FederatedPointerEvent } from "pixi.js";
3
3
  import { h } from "../engine/signal";
4
4
  import { useDefineProps } from "../hooks/useProps";
5
5
  import { Container } from "./Container";
6
- import { Rect } from "./Graphic";
6
+ import { Rect, Circle, Ellipse } from "./Graphic";
7
7
  import { Text } from "./Text";
8
+ import { ControlsDirective } from "../directives/Controls";
9
+ import { JoystickControls } from "../directives/JoystickControls";
10
+ import { Element } from "../engine/reactive";
8
11
 
9
12
  /**
10
13
  * Button states for visual feedback
@@ -82,6 +85,16 @@ export interface ButtonProps {
82
85
  visible?: boolean;
83
86
  /** Button cursor */
84
87
  cursor?: string;
88
+ /** Controls instance to automatically apply button events to (e.g., ControlsDirective or JoystickControls) */
89
+ controls?: ControlsDirective | JoystickControls | any;
90
+ /** Name of the control to trigger with applyControl when button is clicked */
91
+ controlName?: string;
92
+ /** Shape of the button background: 'rect', 'circle', or 'ellipse' */
93
+ shape?: 'rect' | 'circle' | 'ellipse';
94
+ /** Custom background component or element (replaces default background if provided) */
95
+ background?: Element | any;
96
+ /** Custom children components for button content (takes priority over text if provided) */
97
+ children?: Element[];
85
98
  }
86
99
 
87
100
  /**
@@ -94,18 +107,52 @@ export interface ButtonProps {
94
107
  * The button is built using a Container with background and text elements,
95
108
  * providing reactive state management and event handling.
96
109
  *
97
- * @param props - Button configuration including text, styling, and event handlers
110
+ * ## Features
111
+ *
112
+ * - **Controls Integration**: Automatically trigger controls via `applyControl` when clicked
113
+ * - **Multiple Shapes**: Support for rect, circle, and ellipse shapes
114
+ * - **Custom Content**: Use children components for custom button content
115
+ * - **Custom Background**: Provide a custom background component
116
+ *
117
+ * @param props - Button configuration including text, styling, controls, shape, and event handlers
98
118
  * @returns A reactive Button component
99
119
  * @example
100
120
  * ```typescript
101
121
  * // Simple button with text and click handler
102
122
  * const simpleButton = Button({
103
123
  * text: "Click Me",
104
- * onClick: () => console.log("Button clicked!"),
124
+ * click: () => console.log("Button clicked!"),
105
125
  * width: 150,
106
126
  * height: 50
107
127
  * });
108
128
  *
129
+ * // Button with controls integration
130
+ * const jumpButton = Button({
131
+ * text: "Jump",
132
+ * controls: controlsInstance,
133
+ * controlName: "jump",
134
+ * width: 120,
135
+ * height: 40
136
+ * });
137
+ *
138
+ * // Circular button
139
+ * const circleButton = Button({
140
+ * text: "Action",
141
+ * shape: "circle",
142
+ * width: 100,
143
+ * height: 100
144
+ * });
145
+ *
146
+ * // Button with custom content (children)
147
+ * const customButton = Button({
148
+ * shape: "circle",
149
+ * width: 80,
150
+ * height: 80,
151
+ * children: [
152
+ * h(Sprite, { image: "icon.png", width: 50, height: 50 })
153
+ * ]
154
+ * });
155
+ *
109
156
  * // Styled button with custom colors
110
157
  * const styledButton = Button({
111
158
  * text: "Styled Button",
@@ -149,7 +196,7 @@ export function Button(props: ButtonProps) {
149
196
 
150
197
  // Define reactive props with defaults
151
198
  const defineProps = useDefineProps(props);
152
- const { text, disabled, width, height, style } = defineProps({
199
+ const { text, disabled, width, height, style, shape, controlName } = defineProps({
153
200
  text: {
154
201
  type: String,
155
202
  default: ""
@@ -169,9 +216,26 @@ export function Button(props: ButtonProps) {
169
216
  style: {
170
217
  type: Object,
171
218
  default: () => ({})
219
+ },
220
+ shape: {
221
+ type: String,
222
+ default: "rect"
223
+ },
224
+ controlName: {
225
+ type: String,
226
+ default: undefined
172
227
  }
173
228
  });
174
229
 
230
+ // Helper function to get controls instance (handles signals like Joystick)
231
+ const getControls = () => {
232
+ if (!props.controls) return null;
233
+ if (isSignal(props.controls)) {
234
+ return props.controls();
235
+ }
236
+ return props.controls;
237
+ };
238
+
175
239
  // Update button state based on disabled and interaction states
176
240
  effect(() => {
177
241
  const isDisabled = disabled();
@@ -202,25 +266,119 @@ export function Button(props: ButtonProps) {
202
266
  isPressed.set(false);
203
267
  props.hoverLeave?.(event);
204
268
  },
205
- pointerdown: (event: FederatedPointerEvent) => {
269
+ pointerdown: async (event: FederatedPointerEvent) => {
206
270
  if (!disabled()) {
207
271
  isPressed.set(true);
208
272
  props.pressDown?.(event);
273
+
274
+ // Apply control if controls and controlName are provided
275
+ const controls = getControls();
276
+ const name = controlName();
277
+ if (controls && name && controls.applyControl) {
278
+ await controls.applyControl(name, true);
279
+ }
209
280
  }
210
281
  },
211
- pointerup: (event: FederatedPointerEvent) => {
282
+ pointerup: async (event: FederatedPointerEvent) => {
212
283
  if (!disabled() && isPressed()) {
213
284
  isPressed.set(false);
214
285
  props.pressUp?.(event);
286
+
287
+ // Apply control release if controls and controlName are provided
288
+ const controls = getControls();
289
+ const name = controlName();
290
+ if (controls && name && controls.applyControl) {
291
+ await controls.applyControl(name, false);
292
+ }
215
293
  }
216
294
  },
217
- pointertap: (event: FederatedPointerEvent) => {
295
+ pointertap: async (event: FederatedPointerEvent) => {
218
296
  if (!disabled()) {
219
297
  props.click?.(event);
298
+
299
+ // Apply control if controls and controlName are provided (press and release)
300
+ const controls = getControls();
301
+ const name = controlName();
302
+ if (controls && name && controls.applyControl) {
303
+ await controls.applyControl(name);
304
+ }
220
305
  }
221
306
  }
222
307
  };
223
308
 
309
+ // Generate background element
310
+ const getBackgroundElement = () => {
311
+ // If custom background is provided, use it
312
+ if (props.background) {
313
+ return props.background;
314
+ }
315
+
316
+ // Otherwise, use shape-based background
317
+ const currentShape = shape();
318
+ const bgColor = computed(() => {
319
+ const currentStyle = style();
320
+ const backgroundColor = currentStyle.backgroundColor || {
321
+ [ButtonState.Normal]: "#007bff",
322
+ [ButtonState.Hover]: "#0056b3",
323
+ [ButtonState.Pressed]: "#004085",
324
+ [ButtonState.Disabled]: "#6c757d"
325
+ };
326
+ const state = currentState();
327
+ return backgroundColor[state] || backgroundColor[ButtonState.Normal];
328
+ });
329
+
330
+ if (currentShape === 'circle') {
331
+ // For circle, use the smaller dimension as radius
332
+ const radius = computed(() => Math.min(width(), height()) / 2);
333
+ return h(Circle, {
334
+ radius: radius,
335
+ x: computed(() => width() / 2),
336
+ y: computed(() => height() / 2),
337
+ color: bgColor
338
+ });
339
+ } else if (currentShape === 'ellipse') {
340
+ return h(Ellipse, {
341
+ width: width,
342
+ height: height,
343
+ color: bgColor
344
+ });
345
+ } else {
346
+ // Default: rect
347
+ return h(Rect, {
348
+ width: width,
349
+ height: height,
350
+ color: bgColor
351
+ });
352
+ }
353
+ };
354
+
355
+ // Generate content element(s)
356
+ const getContentElements = () => {
357
+ // If children are provided, use them (priority over text)
358
+ if (props.children && props.children.length > 0) {
359
+ return props.children;
360
+ }
361
+
362
+ // Otherwise, use text
363
+ return [
364
+ h(Text, {
365
+ text: text,
366
+ x: computed(() => width() / 2),
367
+ y: computed(() => height() / 2),
368
+ anchor: { x: 0.5, y: 0.5 },
369
+ style: computed(() => {
370
+ const currentStyle = style();
371
+ const textStyle = currentStyle.text || {};
372
+ return {
373
+ fontSize: textStyle.fontSize || 16,
374
+ fontFamily: textStyle.fontFamily || "Arial",
375
+ fill: textStyle.color || "#ffffff"
376
+ };
377
+ })()
378
+ })
379
+ ];
380
+ };
381
+
224
382
  // Return Container with h() children
225
383
  return h(Container, {
226
384
  x: props.x,
@@ -232,38 +390,7 @@ export function Button(props: ButtonProps) {
232
390
  cursor: props.cursor || "pointer",
233
391
  ...eventHandlers
234
392
  }, [
235
- // Background element (either sprite or graphics)
236
- h(Rect, {
237
- width: width,
238
- height: height,
239
- color: computed(() => {
240
- const currentStyle = style();
241
- const backgroundColor = currentStyle.backgroundColor || {
242
- [ButtonState.Normal]: "#007bff",
243
- [ButtonState.Hover]: "#0056b3",
244
- [ButtonState.Pressed]: "#004085",
245
- [ButtonState.Disabled]: "#6c757d"
246
- };
247
- const state = currentState();
248
- return backgroundColor[state] || backgroundColor[ButtonState.Normal];
249
- })
250
- }),
251
-
252
- // Text element
253
- h(Text, {
254
- text: text,
255
- x: computed(() => width() / 2),
256
- y: computed(() => height() / 2),
257
- anchor: { x: 0.5, y: 0.5 },
258
- style: computed(() => {
259
- const currentStyle = style();
260
- const textStyle = currentStyle.text || {};
261
- return {
262
- fontSize: textStyle.fontSize || 16,
263
- fontFamily: textStyle.fontFamily || "Arial",
264
- fill: textStyle.color || "#ffffff"
265
- };
266
- })()
267
- })
393
+ getBackgroundElement(),
394
+ ...getContentElements()
268
395
  ]);
269
396
  }