canvasengine 2.0.0-beta.41 → 2.0.0-beta.43

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 (53) hide show
  1. package/dist/{DebugRenderer-BxfW34YG.js → DebugRenderer-K2IZBznP.js} +2 -2
  2. package/dist/{DebugRenderer-BxfW34YG.js.map → DebugRenderer-K2IZBznP.js.map} +1 -1
  3. package/dist/components/Button.d.ts +3 -0
  4. package/dist/components/Button.d.ts.map +1 -1
  5. package/dist/components/DOMElement.d.ts.map +1 -1
  6. package/dist/components/Graphic.d.ts +1 -1
  7. package/dist/components/Graphic.d.ts.map +1 -1
  8. package/dist/components/index.d.ts +1 -0
  9. package/dist/components/index.d.ts.map +1 -1
  10. package/dist/components/types/DisplayObject.d.ts +12 -16
  11. package/dist/components/types/DisplayObject.d.ts.map +1 -1
  12. package/dist/directives/FocusNavigation.d.ts +71 -0
  13. package/dist/directives/FocusNavigation.d.ts.map +1 -0
  14. package/dist/directives/KeyboardControls.d.ts.map +1 -1
  15. package/dist/directives/ViewportFollow.d.ts.map +1 -1
  16. package/dist/engine/FocusManager.d.ts +174 -0
  17. package/dist/engine/FocusManager.d.ts.map +1 -0
  18. package/dist/engine/bootstrap.d.ts +33 -1
  19. package/dist/engine/bootstrap.d.ts.map +1 -1
  20. package/dist/engine/reactive.d.ts +20 -0
  21. package/dist/engine/reactive.d.ts.map +1 -1
  22. package/dist/hooks/useFocus.d.ts +61 -0
  23. package/dist/hooks/useFocus.d.ts.map +1 -0
  24. package/dist/{index-BnuKipxl.js → index-B4hYyfVE.js} +5479 -4677
  25. package/dist/index-B4hYyfVE.js.map +1 -0
  26. package/dist/index.d.ts +3 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.global.js +7 -7
  29. package/dist/index.global.js.map +1 -1
  30. package/dist/index.js +70 -63
  31. package/package.json +2 -2
  32. package/src/components/Button.ts +7 -4
  33. package/src/components/Canvas.ts +1 -1
  34. package/src/components/DOMContainer.ts +27 -2
  35. package/src/components/DOMElement.ts +37 -29
  36. package/src/components/DisplayObject.ts +15 -3
  37. package/src/components/FocusContainer.ts +372 -0
  38. package/src/components/Graphic.ts +43 -48
  39. package/src/components/Sprite.ts +4 -2
  40. package/src/components/Viewport.ts +65 -26
  41. package/src/components/index.ts +2 -1
  42. package/src/components/types/DisplayObject.ts +7 -4
  43. package/src/directives/Controls.ts +1 -1
  44. package/src/directives/ControlsBase.ts +1 -1
  45. package/src/directives/FocusNavigation.ts +252 -0
  46. package/src/directives/KeyboardControls.ts +12 -8
  47. package/src/directives/ViewportFollow.ts +8 -5
  48. package/src/engine/FocusManager.ts +495 -0
  49. package/src/engine/bootstrap.ts +69 -2
  50. package/src/engine/reactive.ts +54 -18
  51. package/src/hooks/useFocus.ts +94 -0
  52. package/src/index.ts +3 -0
  53. package/dist/index-BnuKipxl.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,82 +1,89 @@
1
- import { h as a } from "./index-BnuKipxl.js";
2
- import { A as r, _ as o, $ as n, t as l, x as c, v as p, C as S, d as m, Y as u, Z as d, an as g, f as b, D as C, am as k, ak as h, y as j, j as T, G as w, w as D, c as E, I as f, a0 as v, J as y, K as O, M as P, X as V, O as x, P as A, al as B, R as G, H, S as M, g as F, e as J, L as N, B as R, Q as q, U as z, T as I, z as K, b as U, N as L, W as Q, V as W, aj as X, ai as Y, ag as Z, k as _, a7 as $, a5 as aa, a8 as sa, l as ea, ac as ta, ah as ia, m as ra, n as oa, a1 as na, a4 as la, o as ca, i as pa, a2 as Sa, p as ma, ad as ua, q as da, a6 as ga, aa as ba, a9 as Ca, af as ka, a3 as ha, s as ja, ab as Ta, ae as wa, r as Da, a as Ea, u as fa } from "./index-BnuKipxl.js";
1
+ import { h as a } from "./index-B4hYyfVE.js";
2
+ import { A as r, a4 as i, a5 as n, B as l, M as c, H as u, C as p, k as m, a2 as S, a3 as g, au as d, m as C, D as b, at as h, ar as k, N as j, o as E, a7 as T, a as f, G as w, L as D, j as F, I as v, a6 as y, J as O, K as M, U as x, a1 as A, O as P, X as V, as as B, R as G, W as H, S as q, n as I, l as J, Y as N, Q as R, _ as z, $ as K, T as U, P as L, g as Q, Z as W, a0 as X, V as Y, aq as Z, ap as _, an as $, p as aa, ae as sa, ac as ea, af as ta, q as oa, f as ra, aj as ia, ao as na, s as la, t as ca, a8 as ua, ab as pa, v as ma, i as Sa, a9 as ga, w as da, ak as Ca, x as ba, ad as ha, ah as ka, ag as ja, am as Ea, r as Ta, aa as fa, y as wa, ai as Da, al as Fa, z as va, b as ya, e as Oa, c as Ma, d as xa, u as Aa } from "./index-B4hYyfVE.js";
3
3
  const e = a.Howler;
4
4
  export {
5
5
  r as ArraySubject,
6
- o as Button,
6
+ i as Button,
7
7
  n as ButtonState,
8
8
  l as Canvas,
9
9
  c as Circle,
10
- p as Container,
11
- S as ControlsBase,
10
+ u as Container,
11
+ p as ControlsBase,
12
12
  m as ControlsDirective,
13
- u as DOMContainer,
14
- d as DOMElement,
15
- g as DisplayObject,
16
- b as Drag,
17
- C as Drop,
18
- k as EVENTS,
19
- h as Easing,
13
+ S as DOMContainer,
14
+ g as DOMElement,
15
+ d as DisplayObject,
16
+ C as Drag,
17
+ b as Drop,
18
+ h as EVENTS,
19
+ k as Easing,
20
20
  j as Ellipse,
21
- T as Flash,
21
+ E as Flash,
22
+ T as FocusContainer,
23
+ f as FocusManager,
22
24
  w as GamepadControls,
23
25
  D as Graphics,
24
- E as Howl,
26
+ F as Howl,
25
27
  e as Howler,
26
- f as Input,
27
- v as Joystick,
28
- y as JoystickControls,
29
- O as KeyboardControls,
30
- P as Mesh,
31
- V as NineSliceSprite,
32
- x as ObjectSubject,
33
- A as ParticlesEmitter,
28
+ v as Input,
29
+ y as Joystick,
30
+ O as JoystickControls,
31
+ M as KeyboardControls,
32
+ x as Mesh,
33
+ A as NineSliceSprite,
34
+ P as ObjectSubject,
35
+ V as ParticlesEmitter,
34
36
  B as RadialGradient,
35
37
  G as Rect,
36
38
  H as Scene,
37
- M as Scheduler,
38
- F as Shake,
39
+ q as Scheduler,
40
+ I as Shake,
39
41
  J as Sound,
40
42
  N as Sprite,
41
43
  R as Svg,
42
- q as Text,
43
- z as TilingSprite,
44
- I as Transition,
45
- K as Triangle,
46
- U 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 isElementFrozen,
64
- ca as isObjectSubject,
65
- pa as isObservable,
66
- Sa as isPrimitive,
67
- ma as isSignal,
68
- ua as isTrigger,
69
- da as linkedSignal,
70
- ga as loop,
71
- ba as mount,
72
- Ca as mountTracker,
73
- ka as on,
74
- ha as registerComponent,
75
- ja as signal,
76
- Ta as tick,
77
- wa as trigger,
78
- Da as untracked,
79
- Ea as useDefineProps,
80
- fa as useProps
44
+ z as Text,
45
+ K as TilingSprite,
46
+ U as Transition,
47
+ L as Triangle,
48
+ Q as Utils,
49
+ W as Video,
50
+ X as Viewport,
51
+ Y as ViewportFollow,
52
+ Z as animatedSequence,
53
+ _ as animatedSignal,
54
+ $ as bootstrapCanvas,
55
+ aa as computed,
56
+ sa as cond,
57
+ ea as createComponent,
58
+ ta as currentSubscriptionsTracker,
59
+ oa as effect,
60
+ ra as focusManager,
61
+ ia as h,
62
+ na as isAnimatedSignal,
63
+ la as isArraySubject,
64
+ ca as isComputed,
65
+ ua as isElement,
66
+ pa as isElementFrozen,
67
+ ma as isObjectSubject,
68
+ Sa as isObservable,
69
+ ga as isPrimitive,
70
+ da as isSignal,
71
+ Ca as isTrigger,
72
+ ba as linkedSignal,
73
+ ha as loop,
74
+ ka as mount,
75
+ ja as mountTracker,
76
+ Ea as on,
77
+ Ta as registerAllComponents,
78
+ fa as registerComponent,
79
+ wa as signal,
80
+ Da as tick,
81
+ Fa as trigger,
82
+ va as untracked,
83
+ ya as useDefineProps,
84
+ Oa as useFocusChange,
85
+ Ma as useFocusIndex,
86
+ xa as useFocusedElement,
87
+ Aa as useProps
81
88
  };
82
89
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvasengine",
3
- "version": "2.0.0-beta.41",
3
+ "version": "2.0.0-beta.43",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "dependencies": {
11
11
  "@barvynkoa/particle-emitter": "^0.0.1",
12
- "@pixi/layout": "^3.0.2",
12
+ "@pixi/layout": "^3.2.0",
13
13
  "@signe/reactive": "^2.6.0",
14
14
  "howler": "^2.2.4",
15
15
  "joypad.js": "^2.3.5",
@@ -1,4 +1,4 @@
1
- import { effect, signal, computed, isSignal } from "@signe/reactive";
1
+ import { effect, signal, computed, isSignal, Signal } from "@signe/reactive";
2
2
  import { FederatedPointerEvent } from "pixi.js";
3
3
  import { h } from "../engine/signal";
4
4
  import { useDefineProps } from "../hooks/useProps";
@@ -95,6 +95,8 @@ export interface ButtonProps {
95
95
  background?: Element | any;
96
96
  /** Custom children components for button content (takes priority over text if provided) */
97
97
  children?: Element[];
98
+ /** Focus index for the button */
99
+ tabindex?: number | Signal<number>;
98
100
  }
99
101
 
100
102
  /**
@@ -270,7 +272,7 @@ export function Button(props: ButtonProps) {
270
272
  if (!disabled()) {
271
273
  isPressed.set(true);
272
274
  props.pressDown?.(event);
273
-
275
+
274
276
  // Apply control if controls and controlName are provided
275
277
  const controls = getControls();
276
278
  const name = controlName();
@@ -283,7 +285,7 @@ export function Button(props: ButtonProps) {
283
285
  if (!disabled() && isPressed()) {
284
286
  isPressed.set(false);
285
287
  props.pressUp?.(event);
286
-
288
+
287
289
  // Apply control release if controls and controlName are provided
288
290
  const controls = getControls();
289
291
  const name = controlName();
@@ -295,7 +297,7 @@ export function Button(props: ButtonProps) {
295
297
  pointertap: async (event: FederatedPointerEvent) => {
296
298
  if (!disabled()) {
297
299
  props.click?.(event);
298
-
300
+
299
301
  // Apply control if controls and controlName are provided (press and release)
300
302
  const controls = getControls();
301
303
  const name = controlName();
@@ -388,6 +390,7 @@ export function Button(props: ButtonProps) {
388
390
  alpha: props.alpha,
389
391
  visible: props.visible,
390
392
  cursor: props.cursor || "pointer",
393
+ tabindex: props.tabindex,
391
394
  ...eventHandlers
392
395
  }, [
393
396
  getBackgroundElement(),
@@ -24,7 +24,7 @@ interface CanvasElement extends Element<ComponentInstance> {
24
24
  };
25
25
  }
26
26
 
27
- registerComponent("Canvas", class Canvas extends DisplayObject(Container) {});
27
+ registerComponent("Canvas", class Canvas extends DisplayObject(Container) { });
28
28
 
29
29
  export interface CanvasProps extends Props {
30
30
  cursorStyles?: () => any;
@@ -109,12 +109,37 @@ export class CanvasDOMContainer extends DisplayObject(PixiDOMContainer) {
109
109
  disableLayout = true;
110
110
 
111
111
  onInit(props: any) {
112
- const div = h(DOMElement, { element: "div" }, props.children) as unknown as Element<CanvasDOMElement>;
112
+ // Handle internal _scopeClass prop for scoped CSS
113
+ const scopeClass = props._scopeClass;
114
+ let divProps: any = { element: "div" };
115
+
116
+ if (scopeClass) {
117
+ // Merge scope class with existing attrs.class
118
+ divProps.attrs = { ...props.attrs };
119
+ if (divProps.attrs.class) {
120
+ // If class exists, merge it with scope class
121
+ if (typeof divProps.attrs.class === 'string') {
122
+ divProps.attrs.class = `${scopeClass} ${divProps.attrs.class}`;
123
+ } else if (Array.isArray(divProps.attrs.class)) {
124
+ divProps.attrs.class = [scopeClass, ...divProps.attrs.class];
125
+ } else if (typeof divProps.attrs.class === 'object') {
126
+ // For object format, add scope class as true
127
+ divProps.attrs.class = { [scopeClass]: true, ...divProps.attrs.class };
128
+ }
129
+ } else {
130
+ // No existing class, just add scope class
131
+ divProps.attrs.class = scopeClass;
132
+ }
133
+ } else if (props.attrs) {
134
+ divProps.attrs = props.attrs;
135
+ }
136
+
137
+ const div = h(DOMElement, divProps, props.children) as unknown as Element<CanvasDOMElement>;
113
138
  this.element = div.componentInstance.element;
114
139
  }
115
140
  }
116
141
 
117
- export interface CanvasDOMContainer extends DisplayObjectProps {}
142
+ export interface CanvasDOMContainer extends DisplayObjectProps { }
118
143
 
119
144
  registerComponent("DOMContainer", CanvasDOMContainer);
120
145
 
@@ -12,22 +12,22 @@ import { isSignal } from "@signe/reactive";
12
12
 
13
13
  interface DOMContainerProps extends DisplayObjectProps {
14
14
  element:
15
- | string
16
- | {
17
- value: HTMLElement;
18
- };
15
+ | string
16
+ | {
17
+ value: HTMLElement;
18
+ };
19
19
  textContent?: string;
20
20
  attrs?: Record<string, any> & {
21
21
  class?:
22
- | string
23
- | string[]
24
- | Record<string, boolean>
25
- | { items?: string[] }
26
- | { value?: string | string[] | Record<string, boolean> };
22
+ | string
23
+ | string[]
24
+ | Record<string, boolean>
25
+ | { items?: string[] }
26
+ | { value?: string | string[] | Record<string, boolean> };
27
27
  style?:
28
- | string
29
- | Record<string, string | number>
30
- | { value?: string | Record<string, string | number> };
28
+ | string
29
+ | Record<string, string | number>
30
+ | { value?: string | Record<string, string | number> };
31
31
  };
32
32
  onBeforeDestroy?: OnHook;
33
33
  }
@@ -234,11 +234,11 @@ export class CanvasDOMElement {
234
234
  // Special handling for form submit events
235
235
  if (event === "submit" && this.element.tagName.toLowerCase() === "form") {
236
236
  e.preventDefault(); // Stop form submission propagation
237
-
237
+
238
238
  // Collect all form data
239
239
  const formData = new FormData(this.element as HTMLFormElement);
240
240
  const formObject: Record<string, any> = {};
241
-
241
+
242
242
  // Convert FormData to plain object
243
243
  formData.forEach((value, key) => {
244
244
  if (formObject[key]) {
@@ -252,7 +252,7 @@ export class CanvasDOMElement {
252
252
  formObject[key] = value;
253
253
  }
254
254
  });
255
-
255
+
256
256
  // Call the event handler with event and form data
257
257
  props.attrs[event]?.(e, formObject);
258
258
  } else {
@@ -292,9 +292,9 @@ export class CanvasDOMElement {
292
292
  // Set initial value from signal
293
293
  (
294
294
  this.element as
295
- | HTMLInputElement
296
- | HTMLTextAreaElement
297
- | HTMLSelectElement
295
+ | HTMLInputElement
296
+ | HTMLTextAreaElement
297
+ | HTMLSelectElement
298
298
  ).value = this.valueSignal();
299
299
 
300
300
  // Listen for input events and update the signal
@@ -314,7 +314,15 @@ export class CanvasDOMElement {
314
314
  onUpdate(props: DOMContainerProps) {
315
315
  if (!this.element) return;
316
316
  for (const [key, value] of Object.entries(props.attrs || {})) {
317
- if (key === "class") {
317
+ if (key === "tabindex") {
318
+ // Handle tabindex attribute
319
+ const tabindexValue = isSignal(value) ? value() : value;
320
+ if (tabindexValue !== undefined && tabindexValue !== null) {
321
+ this.element.setAttribute('tabindex', String(tabindexValue));
322
+ } else {
323
+ this.element.removeAttribute('tabindex');
324
+ }
325
+ } else if (key === "class") {
318
326
  const classList = value.items || value.value || value;
319
327
 
320
328
  // Clear existing classes first
@@ -355,26 +363,26 @@ export class CanvasDOMElement {
355
363
  // Update the DOM element value if the signal value changed
356
364
  const currentValue = (
357
365
  this.element as
358
- | HTMLInputElement
359
- | HTMLTextAreaElement
360
- | HTMLSelectElement
366
+ | HTMLInputElement
367
+ | HTMLTextAreaElement
368
+ | HTMLSelectElement
361
369
  ).value;
362
370
  const signalValue = value();
363
371
  if (currentValue !== signalValue) {
364
372
  (
365
373
  this.element as
366
- | HTMLInputElement
367
- | HTMLTextAreaElement
368
- | HTMLSelectElement
374
+ | HTMLInputElement
375
+ | HTMLTextAreaElement
376
+ | HTMLSelectElement
369
377
  ).value = signalValue;
370
378
  }
371
379
  } else {
372
380
  // If it's not a signal, set the value directly
373
381
  (
374
382
  this.element as
375
- | HTMLInputElement
376
- | HTMLTextAreaElement
377
- | HTMLSelectElement
383
+ | HTMLInputElement
384
+ | HTMLTextAreaElement
385
+ | HTMLSelectElement
378
386
  ).value = value;
379
387
  }
380
388
  } else if (!EVENTS.includes(key)) {
@@ -412,7 +420,7 @@ export class CanvasDOMElement {
412
420
  }
413
421
  }
414
422
 
415
- export interface CanvasDOMElement extends DisplayObjectProps {}
423
+ export interface CanvasDOMElement extends DisplayObjectProps { }
416
424
 
417
425
  registerComponent("DOMElement", CanvasDOMElement);
418
426
 
@@ -597,15 +597,27 @@ export function DisplayObject(extendClass) {
597
597
 
598
598
  // Object properties
599
599
  setObjectFit(objectFit: ObjectFit) {
600
- this.layout = { objectFit };
600
+ try {
601
+ this.layout = { objectFit };
602
+ } catch (error) {
603
+ // Ignore layout errors in test environments or when yoga-layout is not available
604
+ }
601
605
  }
602
606
 
603
607
  setObjectPosition(objectPosition: ObjectPosition) {
604
- this.layout = { objectPosition };
608
+ try {
609
+ this.layout = { objectPosition };
610
+ } catch (error) {
611
+ // Ignore layout errors in test environments or when yoga-layout is not available
612
+ }
605
613
  }
606
614
 
607
615
  setTransformOrigin(transformOrigin: TransformOrigin) {
608
- this.layout = { transformOrigin };
616
+ try {
617
+ this.layout = { transformOrigin };
618
+ } catch (error) {
619
+ // Ignore layout errors in test environments or when yoga-layout is not available
620
+ }
609
621
  }
610
622
  };
611
623
  }