Skip to content

Instantly share code, notes, and snippets.

@gugadev
Last active December 2, 2023 07:44
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gugadev/9c1697f5718a06eb281b280d267419da to your computer and use it in GitHub Desktop.
Save gugadev/9c1697f5718a06eb281b280d267419da to your computer and use it in GitHub Desktop.
custom-elements-jsx-pragma
import React, { FunctionComponent, ReactChild } from 'react'
const listeners = Symbol('jsx-web-comp/event-listeners')
const eventPattern = /^onEvent/
const toKebabCase = (str: string): string => str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase()
export default function jsx (type: string | FunctionComponent, props: Record<string, any>, ...children: ReactChild[]) {
const isCustomElement = customElements.get(type as string)
const newProps = { ...props }
if (typeof type === 'string' && isCustomElement) {
newProps.ref = (element: any) => {
if (element) {
if (props) {
/** Map custom events as objects (must have onEvent prefix) */
const events = Object.entries(props).filter(([k, v]) => k.match(eventPattern)).map(([k, v]) => ({ [k]: v }))
/** Get only the complex props (objects and arrays) */
const complexProps = Object.entries(props).filter(([k, v]) => typeof v === 'object').map(([k, v]) => ({ [k]: v }))
for (const event of events) {
const [key, impl] = Object.entries(event)[0]
const eventName = toKebabCase(
key.replace('onEvent', '')
).replace('-', '')
/** Add the listeners Map if not present */
if (!element[listeners]) {
element[listeners] = new Map()
}
/** If the listener hasn't be attached, attach it */
if (!element[listeners].has(eventName)) {
element.addEventListener(eventName, impl)
/** Save a reference to avoid listening to the same value twice */
element[listeners].set(eventName, impl)
delete newProps[key]
}
}
for (const prop of complexProps) {
const [key, value] = Object.entries(prop)[0]
if (key === 'style' || key === 'ref') { continue }
delete newProps[key] // remove the complex prop from props
element[key] = value
}
}
}
}
}
return React.createElement.apply(null, [type, newProps, ...children])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment