11/** @license MIT modified from Vadim Demedes's https://github.com/vadimdemedes/dom-chef */
2- type Attributes = JSX . IntrinsicElements [ 'div' ] ;
3- type DocumentFragmentFunction = ( props ?: any ) => DocumentFragment ;
4- type ElementFunction = ( props ?: any ) => HTMLElement ;
52
63declare global {
74 namespace JSX {
8- interface Element extends HTMLElement , DocumentFragment {
9- addEventListener : HTMLElement [ 'addEventListener' ] ;
10- removeEventListener : HTMLElement [ 'removeEventListener' ] ;
11- className : HTMLElement [ 'className' ] ;
5+ type Element = HTMLElement | DocumentFragment ;
6+ interface IntrinsicElements {
7+ [ elemName : string ] : Record < string , unknown > ;
128 }
139 }
1410}
1511
16- interface JSXElementClassDocumentFragment extends DocumentFragment , JSX . ElementClass { }
17- interface Fragment {
18- prototype : JSXElementClassDocumentFragment ;
19- new ( ) : JSXElementClassDocumentFragment ;
20- }
12+ type Child = Node | string | number | boolean | null | undefined | Child [ ] ;
13+
14+ type DocumentFragmentFunction = ( props ?: any ) => DocumentFragment ;
15+ type ElementFunction = ( props ?: any ) => HTMLElement ;
2116
2217// https://github.com/preactjs/preact/blob/1bbd687c/src/constants.js#L3
2318const IS_NON_DIMENSIONAL = / a c i t | e x (?: s | g | n | p | $ ) | r p h | g r i d | o w s | m n c | n t w | i n e [ c h ] | z o o | ^ o r d | i t e r a / i;
@@ -38,35 +33,55 @@ const setAttribute = (element: HTMLElement, name: string, value: string) => {
3833 if ( value !== undefined && value !== null ) element . setAttribute ( name , value ) ;
3934} ;
4035
41- const addChildren = ( parent : Element | DocumentFragment , children : Node [ ] ) => {
36+ const addChildren = ( parent : Node , children : Child [ ] ) => {
4237 for ( const child of children ) {
4338 if ( child instanceof Node ) {
4439 parent . appendChild ( child ) ;
4540 } else if ( Array . isArray ( child ) ) {
4641 addChildren ( parent , child ) ;
4742 } else if ( typeof child !== 'boolean' && typeof child !== 'undefined' && child !== null ) {
48- parent . appendChild ( document . createTextNode ( child ) ) ;
43+ parent . appendChild ( document . createTextNode ( String ( child ) ) ) ;
4944 }
5045 }
5146} ;
5247
5348// https://github.com/facebook/react/blob/3f899089/packages/react-dom/src/shared/DOMProperty.js#L288-L322
5449const FALSIFIABLE_ATTRIBUTES = [ 'contentEditable' , 'draggable' , 'spellCheck' , 'value' ] ;
5550
56- export const h = (
51+ export function h < K extends keyof HTMLElementTagNameMap > (
52+ type : K ,
53+ attributes ?: any ,
54+ ...children : Child [ ]
55+ ) : HTMLElementTagNameMap [ K ] ;
56+ export function h (
57+ type : DocumentFragmentFunction ,
58+ attributes ?: any ,
59+ ...children : Child [ ]
60+ ) : DocumentFragment ;
61+ export function h < T extends HTMLElement > (
62+ type : ( props : any ) => T ,
63+ attributes ?: any ,
64+ ...children : Child [ ]
65+ ) : T ;
66+ export function h (
67+ type : string ,
68+ attributes ?: any ,
69+ ...children : Child [ ]
70+ ) : HTMLElement ;
71+ export function h (
5772 type : DocumentFragmentFunction | ElementFunction | string ,
58- attributes ?: Attributes ,
59- ...children : Node [ ]
60- ) => {
73+ attributes ?: any ,
74+ ...children : Child [ ]
75+ ) : JSX . Element {
6176 if ( typeof type !== 'string' ) {
6277 const element = type ( attributes ) ;
6378 addChildren ( element , children ) ;
64- return element ;
79+ return element as JSX . Element ;
6580 }
6681
6782 const element = document . createElement ( type ) ;
6883 addChildren ( element , children ) ;
69- if ( ! attributes ) return element ;
84+ if ( ! attributes ) return element as JSX . Element ;
7085
7186 for ( let [ name , value ] of Object . entries ( attributes ) ) {
7287 if ( name === 'htmlFor' ) name = 'for' ;
@@ -75,19 +90,19 @@ export const h = (
7590 const existingClassname = element . getAttribute ( 'class' ) ?? '' ;
7691 setAttribute ( element , 'class' , ( existingClassname + ' ' + String ( value ) ) . trim ( ) ) ;
7792 } else if ( name === 'style' ) {
78- setCSSProps ( element , value ) ;
93+ setCSSProps ( element , value as CSSStyleDeclaration ) ;
7994 } else if ( name . startsWith ( 'on' ) ) {
8095 const eventName = name . slice ( 2 ) . toLowerCase ( ) . replace ( / ^ - / , '' ) ;
81- element . addEventListener ( eventName , value ) ;
82- } else if ( name === 'dangerouslySetInnerHTML' && '__html' in value ) {
83- element . innerHTML = value . __html ;
96+ element . addEventListener ( eventName , value as EventListenerOrEventListenerObject ) ;
97+ } else if ( name === 'dangerouslySetInnerHTML' && value && ( value as any ) . __html ) {
98+ element . innerHTML = ( value as any ) . __html ;
8499 } else if ( name !== 'key' && ( FALSIFIABLE_ATTRIBUTES . includes ( name ) || value !== false ) ) {
85- setAttribute ( element , name , value === true ? '' : value ) ;
100+ setAttribute ( element , name , value === true ? '' : String ( value ) ) ;
86101 }
87102 }
88103
89- return element ;
90- } ;
104+ return element as JSX . Element ;
105+ }
91106
92107// eslint-disable-next-line @typescript-eslint/no-unused-vars
93- export const Fragment = ( unused : any ) => document . createDocumentFragment ( ) ;
108+ export const Fragment = ( unused ? : any ) => document . createDocumentFragment ( ) ;
0 commit comments