@benev/slate
Version:
frontend web stuff
75 lines (63 loc) • 1.89 kB
text/typescript
import {ob} from "../../tools/ob.js"
import {StateTree} from "../state_tree.js"
export namespace ZipAction {
export type Blueprint<S> = {[key: string]: Blueprint<S> | Fn<S, any>}
export type SetState<S> = (state: S) => void
export type Fn<S, P extends any[]> = (
(state: S, setState: (newState: S) => void) =>
(...params: P) => void
)
export type Callable<B extends Blueprint<any>> = {
[P in keyof B]: B[P] extends Blueprint<any>
? Callable<B[P]>
: B[P] extends Fn<any, any>
? ReturnType<B[P]>
: never
}
export function actualize<S, B extends Blueprint<S>>(tree: StateTree<S>, blueprint: B) {
return ob(blueprint).map(value => {
if (typeof value === "function") {
return (...params: any[]) => {
tree.transmute(state => {
const setState = (newState: S) => { state = newState }
value(state, setState)(...params)
return state
})
}
}
else {
return (actualize as any)(tree, value)
}
}) as Callable<B>
}
export function fn<S>() {
return <F extends Fn<S, any[]>>(fn: F) => fn
}
export function blueprint<S>() {
return <B extends Blueprint<S>>(blueprint: B) => blueprint
}
export type Helpers<S, H> = (state: S, setState: ZipAction.SetState<S>) => H
export const prepFn = <S, H>(
helpers: Helpers<S, H>
) => <P extends any[]>(
fun: (helpers: H) => (...params: P) => void
): ZipAction.Fn<S, P> => (
(state, setState) => (...params) => {
fun(helpers(state, setState))(...params)
return state
}
)
export const prepBlueprint = <S, H>(
helpers: Helpers<S, H>
) => <B extends Blueprint<S>>(
makeBp: (action: <P extends any[]>(f: (helpers: H) => (...params: P) => void) => Fn<S, P>) => B
) => (
makeBp(prepFn<S, H>(helpers))
)
export function prep<S, H>(helpers: Helpers<S, H>) {
return {
action: prepFn(helpers),
blueprint: prepBlueprint(helpers),
}
}
}