68 lines
2.5 KiB
TypeScript
68 lines
2.5 KiB
TypeScript
import type { PropsBase, PropStates, StatesBase } from "../types.js";
|
|
import { State, type ValuesOfStateArray } from "./State.js";
|
|
|
|
export abstract class ComponentBase<Props extends PropsBase, States extends StatesBase> {
|
|
static propsToPropStates<Props extends PropsBase>(props: Props | PropStates<Props>) {
|
|
const propsState: Record<string, State<any>> = {};
|
|
Object.entries(props).forEach(([key, value]) => {
|
|
if (value instanceof State) {
|
|
propsState[key] = value;
|
|
}
|
|
else {
|
|
propsState[key] = new State(value);
|
|
}
|
|
});
|
|
return propsState as PropStates<Props>;
|
|
}
|
|
|
|
states: PropStates<States> = {} as PropStates<States>;
|
|
propStates: PropStates<Props>;
|
|
children: ComponentBase<any, any>[] = [];
|
|
mounted: boolean = false;
|
|
subscriberSymbols: { state: State<any>, symbol: Symbol }[] = [];
|
|
abstract node: Node;
|
|
|
|
constructor(props: PropStates<Props> | Props) {
|
|
this.propStates = ComponentBase.propsToPropStates(props);
|
|
this.init();
|
|
}
|
|
|
|
init(): void { }
|
|
protected abstract createNode(): Node;
|
|
|
|
abstract mount(target: Node): any;
|
|
abstract destroy(): any;
|
|
onMount(): void { };
|
|
onDestoy(): void { };
|
|
|
|
effect<const T extends State<any>[]>(callback: (...values: ValuesOfStateArray<T>) => void, states: T) {
|
|
states.forEach((state) => {
|
|
const symbol = state.subscribe(() => callback(...states.map(({ value }) => value) as ValuesOfStateArray<T>));
|
|
this.subscriberSymbols.push({ state, symbol });
|
|
})
|
|
}
|
|
derived<const T extends State<any>[], U>(callback: (...values: ValuesOfStateArray<T>) => U, states: T): State<U> {
|
|
const derivedState = new State<U>(undefined as U);
|
|
states.forEach((state) => {
|
|
const symbol = state.subscribe(() => {
|
|
const derivedValue = callback(...states.map(({ value }) => value) as ValuesOfStateArray<T>);
|
|
derivedState.set(derivedValue);
|
|
});
|
|
this.subscriberSymbols.push({ state, symbol });
|
|
});
|
|
return derivedState;
|
|
}
|
|
update<T extends (keyof Props | (string & {})), U>(
|
|
key: T,
|
|
value: T extends keyof Props ?
|
|
Props[T] extends State<U> ? U : Props[T] :
|
|
U
|
|
) {
|
|
let propState: State<any> = this.propStates[key];
|
|
if (!propState) {
|
|
propState = new State(value);
|
|
this.propStates[key] = propState;
|
|
}
|
|
propState.set(value);
|
|
}
|
|
} |