From e79e241236775a917207c99bf0ddec28d0c2a59d Mon Sep 17 00:00:00 2001 From: Geoff Doty Date: Sat, 4 May 2024 20:34:27 -0400 Subject: [PATCH] first pass --- .gitignore | 5 ++++ README.md | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ src/app.js | 52 +++++++++++++++++++++++++++++++++++++++ src/index.js | 5 ++++ src/tag.js | 23 +++++++++++++++++ test/index.html | 32 ++++++++++++++++++++++++ 6 files changed, 182 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 src/app.js create mode 100644 src/index.js create mode 100644 src/tag.js create mode 100644 test/index.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..846ca29 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.vscode/ + +node_modules/ + +.scratch/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..fc438ae --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +# Tagged + +> Minimal Javascript UI Library + +This is an experimental composable ui library that takes ideas from Elm Architecture, but without the doctrine - this is Javascript! + +## Features +- No Virtual Dom +- No Build System +- No Over Engineering +- ~100 lines of code +- Totally inefficient rendering (at scale) + +## Overview + +the `app` builder takes an `opts` object that expects it to include: + +- `data` as initial data `{object}` +- `methods` as `{object}` with functions definitions +- `view` as `{function}` that returns valid dom + +and a querySelector compatible `selector` to mount the ui. + +`app` returns: + +- a object that returns a `state` object that you can use to update in other components +- `methods` you can call outside the app component + +### Example + +```html + + +
+``` + +### Inspired By + +- hyperapp +- mithril +- Elm Architecture + +## Todo + +- Methods +- Update API: state, actions + +> WORK-IN-PROGRESS diff --git a/src/app.js b/src/app.js new file mode 100644 index 0000000..aea05c1 --- /dev/null +++ b/src/app.js @@ -0,0 +1,52 @@ +export default function app(opts, selector = "body") { + // initial setup + let data = {}; + let view = () => null; + let methods = {}; + + // query helper + const $ = document.querySelector.bind(document); + + // state helper + const state = (state) => { + if(typeof state === "object") { + data = {...data, ...state}; + } + + // update ui + render(); + + // return current state + return data; + } + + const render = () => { + $(selector).replaceChildren(view(data, methods)); + } + + // setup view + if (opts.view && typeof opts.view === "function") { + view = opts?.view; + } + + // setup data + if (opts.data && typeof opts.data === "object") { + // wrap data in state object + data = state(opts.data); + } + + // setup methods + if (opts.methods && typeof opts.methods === "object") { + methods = opts.methods; + } + + // mount view + if (opts.view && selector) { + render(); + } + + return { + state, + methods, + }; +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..6a5d272 --- /dev/null +++ b/src/index.js @@ -0,0 +1,5 @@ +import tag from "./tag.js"; +import app from "./app.js"; + +export {app}; +export const h = tag; diff --git a/src/tag.js b/src/tag.js new file mode 100644 index 0000000..8cc9dec --- /dev/null +++ b/src/tag.js @@ -0,0 +1,23 @@ +/** + * Creates new DOM element(s) from tag name(s) and attributes + * + * @param {string} tag - tag to create + * @param {...any} args - attributes and/or child tag elements + * + * @returns {HTMLElement} The created DOM element(s) + */ +export default function tag(tag, ...args) { + const el = document.createElement(tag); + + args.forEach((arg) => { + if (typeof arg === "string" || typeof arg === "number") { + el.appendChild(document.createTextNode(arg)); + } else if (Array.isArray(arg)) { + el.append(...arg); + } else { + Object.assign(el, arg); + } + }); + + return el; +} diff --git a/test/index.html b/test/index.html new file mode 100644 index 0000000..b6b6f97 --- /dev/null +++ b/test/index.html @@ -0,0 +1,32 @@ + + + + + + + Tagged UI Creation Lib + + +
+ Tagged Loading... +
+ + + \ No newline at end of file