1- import { diffKeys , DiffStatus , IndexKey } from 'web-utility' ;
2-
3- export type DataObject = Record < string , any > ;
4-
5- export interface VNode {
6- key ?: IndexKey ;
7- text ?: string ;
8- tagName ?: string ;
9- props ?: DataObject ;
10- style ?: DataObject ;
11- children ?: VNode [ ] ;
12- node ?: Node ;
13- }
1+ import { diffKeys , DiffStatus } from 'web-utility' ;
2+
3+ import { DataObject , VNode } from './VDOM' ;
144
155export class DOMRenderer {
166 propsMap : DataObject = { className : 'class' , htmlFor : 'for' } ;
177
8+ attrsMap = Object . fromEntries (
9+ Object . entries ( this . propsMap ) . map ( item => item . reverse ( ) )
10+ ) ;
11+ eventPattern = / ^ o n \w + / ;
12+
1813 protected keyOf = ( { key, text, props } : VNode , index ?: number ) =>
1914 key || props ?. id || text || index ;
2015
@@ -25,7 +20,8 @@ export class DOMRenderer {
2520 node : T ,
2621 oldProps : DataObject = { } ,
2722 newProps : DataObject = { } ,
28- onDelete ?: ( node : T , key : string ) => any
23+ onDelete ?: ( node : T , key : string ) => any ,
24+ onAdd ?: ( node : T , key : string , value : any ) => any
2925 ) {
3026 const { group } = diffKeys (
3127 Object . keys ( oldProps ) ,
@@ -39,7 +35,8 @@ export class DOMRenderer {
3935 ...( group [ DiffStatus . New ] || [ ] )
4036 ] )
4137 if ( oldProps [ key ] !== newProps [ key ] )
42- Reflect . set ( node , key , newProps [ key ] ) ;
38+ if ( onAdd instanceof Function ) onAdd ( node , key , newProps [ key ] ) ;
39+ else Reflect . set ( node , key , newProps [ key ] ) ;
4340 }
4441
4542 protected createNode ( vNode : VNode ) {
@@ -91,7 +88,13 @@ export class DOMRenderer {
9188 oldVNode . node as Element ,
9289 oldVNode . props ,
9390 newVNode . props ,
94- ( node , key ) => node . removeAttribute ( this . propsMap [ key ] || key )
91+ ( node , key ) =>
92+ this . eventPattern . test ( key )
93+ ? ( node [ key . toLowerCase ( ) ] = null )
94+ : node . removeAttribute ( this . propsMap [ key ] || key ) ,
95+ ( node , key , value ) =>
96+ ( node [ this . eventPattern . test ( key ) ? key . toLowerCase ( ) : key ] =
97+ value )
9598 ) ;
9699 this . updateProps (
97100 ( oldVNode . node as HTMLElement ) . style ,
@@ -108,4 +111,38 @@ export class DOMRenderer {
108111
109112 return newVNode ;
110113 }
114+
115+ toVNode = ( node : Node ) : VNode => {
116+ if ( node instanceof Text ) return { node, text : node . nodeValue } ;
117+
118+ if ( ! ( node instanceof Element ) ) return ;
119+
120+ const { tagName, attributes, style, childNodes } = node as HTMLElement ;
121+
122+ const vNode : VNode = { node, tagName : tagName . toLowerCase ( ) } ;
123+
124+ const props = Array . from (
125+ attributes ,
126+ ( { name, value } ) =>
127+ name !== 'style' && [ this . attrsMap [ name ] || name , value ]
128+ ) . filter ( Boolean ) ;
129+
130+ if ( props [ 0 ] ) vNode . props = Object . fromEntries ( props ) ;
131+
132+ const styles = Array . from ( style , key => [ key , style [ key ] ] ) ;
133+
134+ if ( styles [ 0 ] ) vNode . style = Object . fromEntries ( styles ) ;
135+
136+ const children = Array . from ( childNodes , this . toVNode ) . filter ( Boolean ) ;
137+
138+ if ( children [ 0 ] ) vNode . children = children ;
139+
140+ return vNode ;
141+ } ;
142+
143+ render ( vNode : VNode , node : Element = document . body ) {
144+ const root = this . toVNode ( node ) ;
145+
146+ return this . patch ( root , { ...root , children : [ vNode ] } ) ;
147+ }
111148}
0 commit comments