Last active
November 4, 2022 22:43
-
-
Save adminy/504f8b6da3ace826f2715b439f132537 to your computer and use it in GitHub Desktop.
JSX Real DoM Magic Framework
This file contains 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
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Site Title</title> | |
<link href="https://cdn.jsdelivr.net/gh/hung1001/font-awesome-pro@4cac1a6/css/all.css" rel="stylesheet" type="text/css" /> | |
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css"> | |
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> | |
</head> | |
<body> | |
<script type="text/babel" data-type="module" src="index.js"></script> <!-- data-plugins="syntax-jsx,transform-modules-commonjs" data-presets="no-strict" --> | |
</body> | |
</html> |
This file contains 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
import React from './magic.mjs' | |
const [value, setValue] = React.useState(0) | |
const SubSubComp = ({param}) => { | |
return <div>{param} - {value}</div> | |
} | |
const SubComp = () => ( | |
<h2 class='subtitle'> | |
<button onClick={() => console.log('lol', setValue(val => val + 1))} class='button'>+</button> | |
<span>Subtitle Count: {value} </span> | |
<br /> | |
<SubSubComp param={value} /> | |
</h2> | |
) | |
const App = () => ( | |
<div> | |
<h1 class='title'>Hello ... Good day</h1> | |
<span class='subtitle'>I say</span> | |
<SubComp /> | |
</div> | |
) | |
React.render(App) |
This file contains 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
const addProps = (element, props) => { | |
for (const prop in (props || {})) { | |
const isEvent = prop.startsWith('on') | |
const eventName = prop.slice(2, prop.length).toLowerCase() | |
const value = props[prop] | |
isEvent && element.addEventListener(eventName, value) | |
!isEvent && element.setAttribute(prop, value) | |
} | |
} | |
// const getCaller = function x(a,b,c){function d(e,f){d=f}c=(b=Error)[a='prepareStackTrace'];b.captureStackTrace(b[a]=d,x);d.stack;b[a]=c;return d} | |
// const calls = (new Error().stack).split('\n').slice(2).map(line => line.split(' at ')[1].split('(')[0].trim()).filter(line => !line.startsWith('Object.')).slice(0, -1) | |
const useState = value => { | |
const listeners = [] | |
const get = listener => { | |
typeof listener === 'function' && listeners.push(listener) | |
// !listener && (hasToUpdateANonListener = true) | |
return value | |
} | |
const update = updateCallback => { | |
value = updateCallback(value) | |
listeners.map(fn => fn(value)) | |
return value | |
} | |
class MagicValue { | |
[Symbol.toPrimitive]() { | |
console.error('You cannot convert useState variable to primitive!') | |
} | |
get = get | |
} | |
return [new MagicValue(), update] | |
} | |
const prepareChild = child => child.nodeName ? child : document.createTextNode( | |
typeof child === 'string' ? child : JSON.stringify(child) | |
) | |
const addChildren = async (element, children) => { | |
for (const childPromise of children) { | |
let child = await Promise.resolve(childPromise) | |
// the child can be a function, in which case we resolve to a "reactive" value | |
let childElem = null | |
if (child.constructor.name === 'MagicValue') | |
child = child.get(newVal => { | |
const newChild = prepareChild(newVal) | |
childElem.replaceWith(newChild) | |
childElem = newChild | |
}) | |
childElem = element.appendChild(prepareChild(child)) | |
} | |
} | |
const createElement = (name, props, ...children) => { | |
if (typeof name === 'function') { | |
const elements = name(props) | |
name.listen = () => elements.replaceWith(name(props)) | |
return elements | |
} | |
else { | |
const element = document.createElement(name) | |
addProps(element, props) | |
addChildren(element, children) | |
return element | |
} | |
} | |
const Render = (() => { | |
let mainTree = null | |
let oldTree = null | |
const render = main => { | |
mainTree = main | |
oldTree = main() | |
document.body.appendChild(oldTree) | |
} | |
const cleanup = val => { | |
document.body.removeChild(oldTree) | |
render(mainTree) | |
return val | |
} | |
return { render, cleanup } | |
})() | |
window.Render = Render | |
export default { createElement, render: Render.render, useState } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment