import type { IObjectOf , Path } from "@thi.ng/api" ; import { defView , defViewUnsafe } from "@thi.ng/atom/view" ; import { start } from "@thi.ng/hdom/start" ; import { ensureStateGreaterThan , ensureStateLessThan , EventBus , EV_SET_VALUE , EV_UPDATE_VALUE , FX_DISPATCH_NOW , trace , type , EffectDef , type , Event , type , EventDef , type , IDispatch } from "@thi.ng/interceptors" ; const EV_INC = "inc-counter" ; const EV_DEC = "dec-counter" ; const EV_ADD_COUNTER = "add-counter" ; const EV_ADD_VALUE = "add-value" ; const FX_ADD_COUNTER = "add-counter" ; const events = { [ EV_INC ] : [ ensureStateLessThan ( 100 , undefined , ( ) => console . warn ( "eek, reached max" ) ) , ( _ , [ __ , path ] ) => ( { [ FX_DISPATCH_NOW ] : [ EV_ADD_VALUE , [ path , 1 ] ] } ) , ] , [ EV_DEC ] : [ ensureStateGreaterThan ( 0 , undefined , ( ) => console . warn ( "eek, reached min" ) ) , ( _ , [ __ , path ] ) => ( { [ FX_DISPATCH_NOW ] : [ EV_ADD_VALUE , [ path , - 1 ] ] } ) , ] , [ EV_ADD_VALUE ] : [ trace , ( _ , [ __ , [ path , y ] ] ) => ( { [ FX_DISPATCH_NOW ] : [ EV_UPDATE_VALUE , [ path , ( x ) => x + y ] ] , } ) , ] , [ EV_ADD_COUNTER ] : ( state ) => ( { [ FX_DISPATCH_NOW ] : [ EV_ADD_VALUE , [ "nextID" , 1 ] ] , [ FX_ADD_COUNTER ] : { id : state . nextID , start : ~ ~ ( Math . random ( ) * 100 ) , color : [ "gold" , "orange" , "springgreen" , "yellow" , "cyan" ] [ ~ ~ ( Math . random ( ) * 5 ) ] , } , } ) , } ; const effects = { } ; const button = ( bus , event , label , id ? ) => [ "button" , { id , onclick : ( ) => bus . dispatch ( event ) } , label , ] ; const counter = ( bus , path , start = 0 , color ) => { const view = defViewUnsafe ( bus . state , path ) ; bus . dispatch ( [ EV_SET_VALUE , [ path , start ] ] ) ; return [ "div.counter" , { style : { background : color } } , ( ) => view . deref ( ) || 0 , [ "div" , button ( bus , [ EV_DEC , view . path ] , "-" ) , button ( bus , [ EV_INC , view . path ] , "+" ) , ] , ] ; } ; const app = ( ) => { const counters = [ ] ; const bus = new EventBus ( null , events , effects ) ; bus . addEffect ( FX_ADD_COUNTER , ( { id , color , start } , bus ) => counters . push ( counter ( bus , [ "counters" , id ] , start , color ) ) ) ; const json = defView ( bus . state , [ ] , ( state ) => JSON . stringify ( state , null , 2 ) ) ; bus . dispatch ( [ EV_SET_VALUE , [ "nextID" , 0 ] ] ) ; const root = ( ) => [ "div" , button ( bus , [ EV_ADD_COUNTER ] , "add counter" , "addcounter" ) , [ "div" , ... counters ] , [ "pre" , json ] , ] ; return ( ) => { if ( bus . processQueue ( ) ) { return root ; } } ; } ; start ( app ( ) ) ;