Skip to content

Commit 723eab9

Browse files
committed
refactor(Types): update type handling in components to use more generic Element types; enhance type definitions for better flexibility and maintainability
1 parent febcd1d commit 723eab9

File tree

17 files changed

+120
-77
lines changed

17 files changed

+120
-77
lines changed

packages/core/src/components/DOMContainer.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ export class CanvasDOMContainer extends DisplayObject(PixiDOMContainer) {
296296
this.element = div.componentInstance.element;
297297
}
298298

299-
async onMount(element: Element<DisplayObject>, index?: number) {
299+
async onMount(element: Element<any>, index?: number) {
300300
await super.onMount(element, index);
301301
this.syncCanvasSizeEffect();
302302
this.applyElementSize();
@@ -308,11 +308,11 @@ export class CanvasDOMContainer extends DisplayObject(PixiDOMContainer) {
308308
this.applyElementSize();
309309
}
310310

311-
protected onLayoutComputed() {
311+
onLayoutComputed() {
312312
this.applyElementSize();
313313
}
314314

315-
async onDestroy(parent: Element<DisplayObject>, afterDestroy?: () => void) {
315+
async onDestroy(parent: Element<any>, afterDestroy?: () => void) {
316316
const _afterDestroy = () => {
317317
if (this.canvasSizeEffect) {
318318
this.canvasSizeEffect.subscription?.unsubscribe();

packages/core/src/components/DOMElement.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import { DisplayObjectProps } from "./types/DisplayObject";
1010
import { isObservable } from "../engine/utils";
1111
import { isSignal } from "@signe/reactive";
1212

13-
interface DOMContainerProps extends DisplayObjectProps {
14-
element:
13+
export interface DOMElementProps extends DisplayObjectProps {
14+
element?:
1515
| string
1616
| {
1717
value: HTMLElement;
@@ -32,6 +32,14 @@ interface DOMContainerProps extends DisplayObjectProps {
3232
onBeforeDestroy?: OnHook;
3333
}
3434

35+
export interface DOMContainerProps extends DOMElementProps {
36+
element:
37+
| string
38+
| {
39+
value: HTMLElement;
40+
};
41+
}
42+
3543
/**
3644
* DOMContainer class for managing DOM elements within the canvas engine
3745
*
@@ -233,7 +241,7 @@ export class CanvasDOMElement {
233241
}
234242
if (typeof value === "object") {
235243
for (const [className, shouldAdd] of Object.entries(value)) {
236-
const resolved = isSignal(shouldAdd) ? shouldAdd() : shouldAdd;
244+
const resolved = isSignal(shouldAdd as any) ? (shouldAdd as any)() : shouldAdd;
237245
if (resolved) {
238246
tokens.push(className);
239247
}
@@ -347,12 +355,15 @@ export class CanvasDOMElement {
347355
}
348356
}
349357

350-
onInit(props: DOMContainerProps) {
358+
onInit(props: DOMElementProps) {
351359
if (typeof props.element === "string") {
352360
this.element = document.createElement(props.element);
353361
this.isFormElementType = this.isFormElement(props.element);
354362
} else {
355-
this.element = props.element.value;
363+
this.element = props.element?.value;
364+
if (!this.element) {
365+
throw new Error("DOMElement requires a valid element.");
366+
}
356367
this.isFormElementType = this.isFormElement(this.element.tagName);
357368
}
358369
if (props.onBeforeDestroy || props["on-before-destroy"]) {
@@ -433,7 +444,7 @@ export class CanvasDOMElement {
433444
}
434445
}
435446

436-
onUpdate(props: DOMContainerProps) {
447+
onUpdate(props: DOMElementProps) {
437448
if (!this.element) return;
438449
for (const [key, value] of Object.entries(props.attrs || {})) {
439450
if (key === "tabindex") {

packages/core/src/components/DOMSprite.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { createComponent, Element, registerComponent } from "../engine/reactive"
44
import { ComponentFunction } from "../engine/signal";
55
import { arrayEquals, fps2ms, isBrowser, isFunction, preciseNow } from "../engine/utils";
66
import { DisplayObjectProps } from "./types/DisplayObject";
7-
import { CanvasDOMElement } from "./DOMElement";
7+
import { CanvasDOMElement, DOMElementProps } from "./DOMElement";
88
import { OnHook } from "./DisplayObject";
99
import { Tick } from "../directives/Scheduler";
1010
import {
@@ -21,7 +21,7 @@ export interface DOMSpriteFrame {
2121
height: number;
2222
}
2323

24-
export interface DOMSpriteProps extends DisplayObjectProps {
24+
export interface DOMSpriteProps extends DOMElementProps {
2525
image?: string;
2626
rectangle?: DOMSpriteFrame | { value?: DOMSpriteFrame };
2727
frames?: DOMSpriteFrame[];
@@ -149,9 +149,10 @@ export class CanvasDOMSprite extends CanvasDOMElement {
149149
private playingSubscription?: Subscription;
150150
private playingSignal?: Signal<boolean>;
151151

152-
onInit(props: DOMSpriteProps) {
153-
this.elementType = props.element ?? "div";
154-
const nextProps = this.mergeEventAttrs({ ...props, element: this.elementType });
152+
onInit(props: DOMElementProps) {
153+
const spriteProps = props as DOMSpriteProps;
154+
this.elementType = spriteProps.element ?? "div";
155+
const nextProps = this.mergeEventAttrs({ ...spriteProps, element: this.elementType });
155156
this.tickSignal = nextProps.context?.tick;
156157
this.applyProps(nextProps);
157158
super.onInit(nextProps as any);
@@ -167,8 +168,8 @@ export class CanvasDOMSprite extends CanvasDOMElement {
167168
this.updateAnimationLoop();
168169
}
169170

170-
onUpdate(props: DOMSpriteProps) {
171-
const nextProps = this.mergeEventAttrs(props);
171+
onUpdate(props: DOMElementProps) {
172+
const nextProps = this.mergeEventAttrs(props as DOMSpriteProps);
172173
super.onUpdate(nextProps as any);
173174
this.applyProps(nextProps);
174175
this.render();
@@ -195,7 +196,9 @@ export class CanvasDOMSprite extends CanvasDOMElement {
195196
rectangle?: DOMSpriteFrame | { value?: DOMSpriteFrame } | Signal<DOMSpriteFrame | undefined>
196197
): DOMSpriteFrame | undefined {
197198
if (!rectangle) return undefined;
198-
const signalResolved = isSignal(rectangle) ? rectangle() : rectangle;
199+
const signalResolved = isSignal(rectangle as any)
200+
? (rectangle as Signal<DOMSpriteFrame | undefined>)()
201+
: rectangle;
199202
if (!signalResolved) return undefined;
200203
const resolved = (signalResolved as any).value ?? signalResolved;
201204
if (!resolved) return undefined;
@@ -211,7 +214,7 @@ export class CanvasDOMSprite extends CanvasDOMElement {
211214
): DOMSpriteSheetDefinition | Promise<DOMSpriteSheetDefinition | undefined> | undefined {
212215
if (!definition) return undefined;
213216
const signalResolved = isSignal(definition as any)
214-
? (definition as any)()
217+
? (definition as Signal<DOMSpriteSheetDefinition | undefined>)()
215218
: definition;
216219
if (!signalResolved) return undefined;
217220
return (signalResolved as any).value ?? signalResolved;
@@ -251,10 +254,12 @@ export class CanvasDOMSprite extends CanvasDOMElement {
251254
(prev, val) => ({ ...prev, [val]: (definition as any)[val] }),
252255
{}
253256
);
254-
const optionsTextures = {
257+
const optionsTextures: DOMSpriteTextureOptionsMerging = {
255258
...baseOptions,
256259
...textures[animationName],
257-
} as DOMSpriteTextureOptionsMerging;
260+
spriteWidth: 0,
261+
spriteHeight: 0,
262+
};
258263
optionsTextures.image =
259264
(textures[animationName] as any).image ?? definition.image;
260265

@@ -536,7 +541,8 @@ export class CanvasDOMSprite extends CanvasDOMElement {
536541
}
537542

538543
private bindSheetParams(context: Element<CanvasDOMElement>) {
539-
const params = context.propObservables?.sheet?.params as any;
544+
const sheetProps = context.propObservables?.sheet as any;
545+
const params = sheetProps?.params as any;
540546
if (!params || typeof params !== "object") return;
541547
for (const key in params) {
542548
const value = params[key];
@@ -645,7 +651,7 @@ export class CanvasDOMSprite extends CanvasDOMElement {
645651
this.lastTickTimestamp = undefined;
646652

647653
if (this.tickSignal?.observable) {
648-
this.tickSubscription = this.tickSignal.observable.subscribe((result: any) => {
654+
this.tickSubscription = (this.tickSignal.observable as any).subscribe((result: any) => {
649655
const tick = result?.value ?? result;
650656
if (!tick) return;
651657
if (this.sheetCurrentAnimation) {

packages/core/src/components/DisplayObject.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type {
99
TransformOrigin,
1010
} from "./types/DisplayObject";
1111
import { signal } from "@signe/reactive";
12-
import { BlurFilter, ObservablePoint } from "pixi.js";
12+
import { BlurFilter, ObservablePoint, type Point, type Rectangle } from "pixi.js";
1313
import * as FILTERS from "pixi-filters";
1414
import { isPercent } from "../utils/functions";
1515
import { BehaviorSubject, filter, Subject } from "rxjs";
@@ -20,9 +20,11 @@ export interface ComponentInstance extends PixiMixins.ContainerOptions {
2020
onInit?(props: Props): void;
2121
onUpdate?(props: Props): void;
2222
onDestroy?(parent: Element, afterDestroy: () => void): void;
23-
onMount?(context: Element, index?: number): void;
23+
onMount?(context: Element<any>, index?: number): void;
2424
setWidth(width: number): void;
2525
setHeight(height: number): void;
26+
getLocalBounds?(): Rectangle;
27+
getGlobalPosition?(): Point;
2628
}
2729

2830
export const EVENTS = [
@@ -121,17 +123,17 @@ export function DisplayObject(extendClass) {
121123
// Store computed layout box dimensions
122124
#computedLayoutBox: { width?: number; height?: number } | null = null;
123125
// Store reference to element for freeze checking
124-
#element: Element<DisplayObject> | null = null;
126+
#element: Element<any> | null = null;
125127

126128
/**
127129
* Get the element reference for freeze checking
128130
* @returns The element reference or null
129131
*/
130-
protected getElement(): Element<DisplayObject> | null {
132+
getElement(): Element<any> | null {
131133
return this.#element;
132134
}
133135

134-
protected onLayoutComputed(_event: any) {}
136+
onLayoutComputed(_event: any) {}
135137

136138
get deltaRatio() {
137139
return this.#canvasContext?.scheduler?.tick.value.deltaRatio;
@@ -196,7 +198,7 @@ export function DisplayObject(extendClass) {
196198
this.subjectInit.next(this);
197199
}
198200

199-
async onMount(element: Element<DisplayObject>, index?: number) {
201+
async onMount(element: Element<any>, index?: number) {
200202
if (this.destroyed) return
201203
this.#element = element;
202204
this.#canvasContext = element.props.context;

packages/core/src/components/FocusContainer.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { applyDirective } from "../engine/directive";
33
import { ComponentFunction } from "../engine/signal";
44
import { DisplayObjectProps } from "./types/DisplayObject";
55
import { focusManager, ScrollOptions } from "../engine/FocusManager";
6-
import { signal, Signal, isSignal } from "@signe/reactive";
6+
import { signal, Signal, WritableSignal, WritableObjectSignal, isSignal } from "@signe/reactive";
77
import { CanvasViewport } from "./Viewport";
88
import { Controls } from "../directives/ControlsBase";
99
// Import FocusNavigation directive to ensure it's registered
@@ -24,6 +24,9 @@ export interface FocusContainerProps extends DisplayObjectProps {
2424
onFocusChange?: (index: number, element: Element | null) => void;
2525
autoScroll?: boolean | ScrollOptions;
2626
viewport?: CanvasViewport;
27+
context?: {
28+
viewport?: CanvasViewport;
29+
};
2730
}
2831

2932
/**
@@ -65,8 +68,8 @@ export interface FocusContainerProps extends DisplayObjectProps {
6568
*/
6669
export class CanvasFocusContainer {
6770
private containerId: string = '';
68-
private currentIndexSignal: Signal<number | null> | null = null;
69-
private focusedElementSignal: Signal<Element | null> | null = null;
71+
private currentIndexSignal: WritableSignal<number | null> | null = null;
72+
private focusedElementSignal: WritableSignal<Element | null> | WritableObjectSignal<Element | null> | null = null;
7073
private registeredFocusables: Set<number> = new Set();
7174

7275
/**
@@ -80,7 +83,7 @@ export class CanvasFocusContainer {
8083

8184
// Create signals for current index and focused element
8285
const currentIndex = signal<number | null>(null);
83-
const focusedElement = signal<Element | null>(null);
86+
const focusedElement = signal<Element | null>(null) as WritableSignal<Element | null> | WritableObjectSignal<Element | null>;
8487

8588
this.currentIndexSignal = currentIndex;
8689
this.focusedElementSignal = focusedElement;
@@ -145,7 +148,7 @@ export class CanvasFocusContainer {
145148
// element.effectSubscriptions.push(subscription);
146149
// }
147150

148-
focusManager.setTabindex(this.containerId, element.propObservables.tabindex);
151+
focusManager.setTabindex(this.containerId, element.propObservables?.tabindex as any);
149152

150153
// Register all focusable children initially
151154
// Use setTimeout to ensure children are mounted

packages/core/src/components/Sprite.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ export class CanvasSprite extends DisplayObject(PixiSprite) {
299299
}
300300
}
301301

302-
async onMount(params: Element<CanvasSprite>) {
302+
async onMount(params: Element<any>) {
303303
// Set #element manually for freeze checking before calling super.onMount
304304
// We need to set it early so update() can check freeze state
305305
(this as any)['#element'] = params;

packages/core/src/components/Text.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class CanvasText extends DisplayObject(PixiText) {
4848
* @param {Element<CanvasText>} element - The element being mounted with parent and props.
4949
* @param {number} [index] - The index of the component among its siblings.
5050
*/
51-
async onMount(element: Element<CanvasText>, index?: number): Promise<void> {
51+
async onMount(element: Element<any>, index?: number): Promise<void> {
5252
const { props } = element;
5353
await super.onMount(element, index);
5454
const tick: Signal = props.context.tick;

packages/core/src/components/Viewport.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Subscription } from 'rxjs';
33
import { createComponent, registerComponent, Element, Props } from '../engine/reactive';
44
import { DisplayObject, ComponentInstance } from './DisplayObject';
55
import { effect, Signal } from '@signe/reactive';
6-
import { Graphics, Container } from 'pixi.js';
6+
import { Graphics, Container, ContainerChild, IRenderLayer } from 'pixi.js';
77

88
const EVENTS = [
99
'bounce-x-end',
@@ -73,8 +73,8 @@ export class CanvasViewport extends DisplayObject(Container) {
7373
return this.viewport.addChild(...children)
7474
}
7575

76-
addChildAt<U extends any>(child: U, index: number): U {
77-
return this.viewport.addChildAt(child, index)
76+
addChildAt<T extends ContainerChild | IRenderLayer>(child: T, index: number): T {
77+
return this.viewport.addChildAt(child, index) as T
7878
}
7979

8080
onInit(props) {
@@ -90,7 +90,7 @@ export class CanvasViewport extends DisplayObject(Container) {
9090
* @param {Element<CanvasViewport>} element - The element being mounted. Its `props` property (of type ViewportProps) contains component properties and context.
9191
* @param {number} [index] - The index of the component among its siblings.
9292
*/
93-
async onMount(element: Element<CanvasViewport>, index?: number): Promise<void> {
93+
async onMount(element: Element<any>, index?: number): Promise<void> {
9494
element.props.context.viewport = this.viewport
9595
await super.onMount(element, index);
9696
const { props } = element;
@@ -211,4 +211,4 @@ registerComponent('Viewport', CanvasViewport)
211211

212212
export function Viewport(props: ViewportProps) {
213213
return createComponent('Viewport', props);
214-
}
214+
}

packages/core/src/directives/Controls.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export class ControlsDirective extends Directive {
3636
* Initialize the controls directive
3737
* Sets up keyboard, gamepad, and joystick controls if available
3838
*/
39-
onInit(element: Element) {
39+
onInit(element: Element<any>) {
4040
this.element = element;
4141
const value = element.props.controls?.value ?? element.props.controls;
4242
if (!value) return;
@@ -71,7 +71,7 @@ export class ControlsDirective extends Directive {
7171
// Subscribe to freeze prop if it's a signal
7272
const freezeProp = element.propObservables?.freeze ?? element.props?.freeze;
7373
if (isSignal(freezeProp)) {
74-
this.freezeSubscription = (freezeProp as Signal<boolean>).observable.subscribe((isFrozen) => {
74+
this.freezeSubscription = ((freezeProp as Signal<boolean>).observable as any).subscribe((isFrozen) => {
7575
if (isFrozen) {
7676
this.stopInputs();
7777
} else {
@@ -84,13 +84,13 @@ export class ControlsDirective extends Directive {
8484
/**
8585
* Mount hook (no specific action needed)
8686
*/
87-
onMount(element: Element) { }
87+
onMount(element: Element<any>) { }
8888

8989
/**
9090
* Update controls configuration
9191
* Updates both keyboard and gamepad controls
9292
*/
93-
onUpdate(props: any, element: Element) {
93+
onUpdate(props: any, element: Element<any>) {
9494
const value = props.controls?.value ?? props.controls;
9595
if (value) {
9696
if (this.keyboardControls) {
@@ -115,7 +115,7 @@ export class ControlsDirective extends Directive {
115115
/**
116116
* Cleanup and destroy all control systems
117117
*/
118-
onDestroy(element: Element) {
118+
onDestroy(element: Element<any>) {
119119
if (this.freezeSubscription) {
120120
this.freezeSubscription.unsubscribe();
121121
this.freezeSubscription = null;

packages/core/src/directives/FocusNavigation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export class FocusNavigationDirective extends Directive {
6969

7070
// Handle controls prop updates if it's a signal
7171
if (isSignal(controlsProp)) {
72-
this.controlsSubscription = (controlsProp as Signal<Controls>).observable.subscribe((controls) => {
72+
this.controlsSubscription = ((controlsProp as Signal<Controls>).observable as any).subscribe((controls) => {
7373
if (controls) {
7474
this.controlsDirective?.onUpdate({ controls }, element);
7575
}

0 commit comments

Comments
 (0)