Skip to content

Instantly share code, notes, and snippets.

@WojtekCodesToday
Created April 7, 2023 17:26
Show Gist options
  • Select an option

  • Save WojtekCodesToday/7d7aa6fb21c0acae76cb0e0021cfac1e to your computer and use it in GitHub Desktop.

Select an option

Save WojtekCodesToday/7d7aa6fb21c0acae76cb0e0021cfac1e to your computer and use it in GitHub Desktop.

Revisions

  1. WojtekCodesToday created this gist Apr 7, 2023.
    96 changes: 96 additions & 0 deletions roost.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,96 @@
    const roost = {
    elements: {},
    render: function (json, parent = document.body) {
    if (typeof json === 'string') {
    const element = document.createElement('div');
    element.innerHTML = json.trim();

    if (parent) {
    parent.appendChild(element.firstChild);
    }

    return element.firstChild;
    }

    const element = document.createElement(json.type);

    if (json.props) {
    Object.keys(json.props).forEach(name => {
    if (name.startsWith('on')) {
    const eventType = name.substring(2).toLowerCase();
    element.addEventListener(eventType, json.props[name]);
    } else {
    element.setAttribute(name, json.props[name]);
    }
    });
    }

    if (parent) {
    parent.appendChild(element);
    }

    if (json.children) {
    json.children.forEach(child => this.render(child, element));
    }

    return element;
    },
    jsx: function (jsx) {
    const pattern = /<(\w+)\s*\/?>/g;
    const elements = [];
    let match;
    let last = 0;
    while ((match = pattern.exec(jsx))) {
    if (match.index > last) {
    const text = jsx.substring(last, match.index);
    elements.push({ type: "text", value: text });
    }
    const tagName = match[1];
    const selfClosing = match[0].endsWith("/");
    const props = {};
    const propPattern = /(\w+)="([^"]*)"/g;
    let propMatch;
    while ((propMatch = propPattern.exec(match[0]))) {
    const propName = propMatch[1];
    const propValue = propMatch[2];
    props[propName] = propValue;
    }
    elements.push({ type: "element", tagName, selfClosing, props });
    last = pattern.lastIndex;
    }
    if (last < jsx.length) {
    const text = jsx.substring(last);
    elements.push({ type: "text", value: text });
    }
    return elements;
    },
    convertToDOM: function (json) {
    const elements = [];
    for (const item of json) {
    if (item.type === "text") {
    elements.push(document.createTextNode(item.value));
    } else if (item.type === "element") {
    const element = document.createElement(item.tagName);
    for (const [key, value] of Object.entries(item.props)) {
    if (key === "className") {
    element.setAttribute("class", value);
    } else if (key === "id") {
    element.setAttribute("id", value);
    } else {
    element.setAttribute(key, value);
    }
    }
    if (!item.selfClosing) {
    const children = this.convertToDOM(item.children);
    for (const child of children) {
    element.appendChild(child);
    }
    }
    elements.push(element);
    }
    }
    return elements;
    },
    };

    export default roost;