import { BIND_SUFFIX , BoundHandler , BoundNode , HANDLER_KEY , NODE_KEY , setState } from '../element/src/compile' ; import { compileTemplate } from './../element' ; import { EventDispatcher , ReadymadeEventTarget } from './../event' ; export type EventHandler = ( ) => void ; export const EMIT_KEY = '$emit' ; export const LISTEN_KEY = '$listen' ; interface EventMeta { key : string ; handler : EventHandler ; } interface ElementMeta { autoDefine ? : boolean ; custom ? : { extends : string ; } ; eventMap ? : { [ key ] : EventMeta ; } ; mode ? : 'closed' | 'open' ; selector : string ; style ? : string | any [ ] ; template ? : string | any [ ] ; } const html = ( ... args ) => { return args ; } ; const css = ( ... args ) => { return args ; } ; const noop = ( ) => { } ; function Component ( meta ) { if ( ! meta ) { console . error ( 'Component must include ElementMeta to compile' ) ; return ; } return ( target ) => { compileTemplate ( meta , target ) ; if ( meta . autoDefine === undefined ) { meta . autoDefine = true ; } if ( meta . autoDefine === true && customElements . get ( meta . selector ) === undefined ) { if ( meta . selector && ! meta . custom ) { customElements . define ( meta . selector , target ) ; } else if ( meta . selector && meta . custom ) { customElements . define ( meta . selector , target , meta . custom ) ; } else { customElements . define ( meta . selector , target ) ; } } return target ; } ; } function State ( property ? ) { return function decorator ( target , key , descriptor ) { async function bindState ( ) { this . $state = this [ key ] ( ) ; this . ɵɵstate = { } ; this . ɵɵstate [ HANDLER_KEY ] = new BoundHandler ( this ) ; this . ɵɵstate [ NODE_KEY ] = new BoundNode ( this . shadowRoot ? this . shadowRoot : this ) ; this . ɵɵstate . $changes = new ReadymadeEventTarget ( ) ; this . ɵstate = new Proxy ( this . $state , this . ɵɵstate [ 'handler' + BIND_SUFFIX ] ) ; for ( const prop in this . $state ) { this . ɵstate [ prop ] = this . $state [ prop ] ; } } target . setState = setState ; target . bindState = function onBind ( ) { bindState . call ( this ) ; } ; } ; } function Emitter ( eventName ? , options ? , channelName ? ) { return function decorator ( target , key , descriptor ) { const channel = channelName ? channelName : 'default' ; let prop = '' ; if ( eventName ) { prop = EMIT_KEY + channel + eventName ; } else { prop = EMIT_KEY + channel ; } function addEvent ( name ? , chan ? ) { if ( ! this . emitter ) { this . emitter = new EventDispatcher ( this , chan ) ; } if ( name ) { this . emitter . set ( name , new CustomEvent ( name , options ? options : { } ) ) ; } if ( chan && ! this . emitter . channels [ chan ] ) { this . emitter . setChannel ( chan ) ; } } function bindEmitters ( ) { for ( const property in this ) { if ( property . includes ( EMIT_KEY ) ) { this [ property ] . call ( this ) ; } } } if ( ! target [ prop ] ) { target [ prop ] = function ( ) { addEvent . call ( this , eventName , channelName ) ; } ; } target . bindEmitters = function onEmitterInit ( ) { bindEmitters . call ( this ) ; } ; } ; } function Listen ( eventName , channelName ? ) { return function decorator ( target , key , descriptor ) { const symbolHandler = Symbol ( key ) ; let prop = '' ; if ( channelName ) { prop = LISTEN_KEY + eventName + channelName ; } else { prop = LISTEN_KEY + eventName ; } function addListener ( name , chan ) { const handler = ( this [ symbolHandler ] = ( ... args ) => { descriptor . value . apply ( this , args ) ; } ) ; if ( ! this . emitter ) { this . emitter = new EventDispatcher ( this , chan ? chan : null ) ; } this . elementMeta . eventMap [ prop ] = { key : name , handler : key } ; this . addEventListener ( name , handler ) ; } function removeListener ( ) { this . removeEventListener ( eventName , this [ symbolHandler ] ) ; } function addListeners ( ) { for ( const property in this ) { if ( property . includes ( LISTEN_KEY ) ) { this [ property ] . onListener . call ( this ) ; } } } if ( ! target [ prop ] ) { target [ prop ] = { } ; target [ prop ] . onListener = function onInitWrapper ( ) { addListener . call ( this , eventName , channelName ) ; } ; target [ prop ] . onDestroyListener = function onDestroyWrapper ( ) { removeListener . call ( this , eventName , channelName ) ; } ; } target . bindListeners = function onListenerInit ( ) { addListeners . call ( this ) ; } ; } ; } export { EventMeta , ElementMeta , Component , State , Emitter , Listen , html , css , noop } ;