Skip to content

Instantly share code, notes, and snippets.

@LachlanArthur
Created October 31, 2021 07:26
Show Gist options
  • Save LachlanArthur/5954fcfe45257a6c32ae59687633165d to your computer and use it in GitHub Desktop.
Save LachlanArthur/5954fcfe45257a6c32ae59687633165d to your computer and use it in GitHub Desktop.
JSX Shim
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>
}
}
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