Created
October 31, 2021 07:26
-
-
Save LachlanArthur/5954fcfe45257a6c32ae59687633165d to your computer and use it in GitHub Desktop.
JSX Shim
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface ExtraAttributes { | |
role: string, | |
style: string | ( Partial<CSSStyleDeclaration> & Record<string, string> ), | |
classList: string[], | |
charset: string, | |
} | |
declare var React; | |
declare namespace JSX { | |
interface Element extends HTMLElement, SVGElement { } | |
type IntrinsicElements = { | |
[ P in keyof HTMLElementTagNameMap ]: Partial<Omit<HTMLElementTagNameMap[ P ], keyof ExtraAttributes> & ExtraAttributes> | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type ElementAttributes = { [ key: string ]: any } | null; | |
type ElementChildren = Array<HTMLElement | string>; | |
type ElementConstructor = ( ( attributes?: ElementAttributes ) => HTMLElement ); | |
type ElementTagName = string | typeof DocumentFragment | ElementConstructor; | |
function isFragment( element: any ): element is typeof DocumentFragment { | |
return element === DocumentFragment; | |
} | |
function newElement( tagName: ElementTagName ) { | |
if ( typeof tagName === 'string' ) { | |
return document.createElement( tagName ); | |
} | |
if ( isFragment( tagName ) ) { | |
return document.createDocumentFragment(); | |
} | |
return tagName(); | |
} | |
function appendChildren( element: HTMLElement | DocumentFragment, children: ElementChildren ) { | |
for ( const child of children ) { | |
if ( typeof child === 'string' ) { | |
element.appendChild( document.createTextNode( child ) ); | |
} else { | |
element.appendChild( child ); | |
} | |
} | |
} | |
function populateAttributes( element: HTMLElement, attributes?: ElementAttributes ) { | |
if ( typeof attributes === 'undefined' || attributes === null ) { | |
attributes = {}; | |
} | |
for ( const [ key, value ] of Object.entries( attributes ) ) { | |
switch ( key ) { | |
// Attributes | |
default: | |
element.setAttribute( key, value ); | |
break; | |
// Object properties | |
case 'dataset': | |
Object.assign( element[ key ], value ); | |
break; | |
// Scalar properties | |
case 'className': | |
case 'htmlFor': | |
( element as any )[ key ] = value; | |
break; | |
case 'classList': | |
element.classList.add( ...value.filter( String ) ); | |
break; | |
case 'style': | |
if ( typeof value === 'string' ) { | |
element.setAttribute( key, value ); | |
} else for ( const [ cssKey, cssValue ] of Object.entries( value as Record<string, string> ) ) { | |
element.style.setProperty( cssKey, cssValue ); | |
} | |
break; | |
} | |
} | |
} | |
function createElement( tagName: ElementTagName, attributes?: ElementAttributes, ...children: ElementChildren ): HTMLElement | DocumentFragment { | |
const element = newElement( tagName ); | |
if ( !( element instanceof DocumentFragment ) ) { | |
populateAttributes( element, attributes ); | |
} | |
appendChildren( element, children ); | |
return element; | |
} | |
export const Fragment = DocumentFragment; | |
const React = { | |
createElement, | |
Fragment, | |
}; | |
export default React; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment