aboutsummaryrefslogtreecommitdiffstats
path: root/VegaData/wwwroot/framework.js
diff options
context:
space:
mode:
Diffstat (limited to 'VegaData/wwwroot/framework.js')
-rw-r--r--VegaData/wwwroot/framework.js166
1 files changed, 166 insertions, 0 deletions
diff --git a/VegaData/wwwroot/framework.js b/VegaData/wwwroot/framework.js
new file mode 100644
index 0000000..d1e6cc6
--- /dev/null
+++ b/VegaData/wwwroot/framework.js
@@ -0,0 +1,166 @@
+const targetMap = new WeakMap();
+let activeEffect = null;
+
+const root = document.getElementById("root");
+
+function createElement(tagName, props = {}, children = []) {
+ const el = document.createElement(tagName);
+
+ for (const [key, value] of Object.entries(props || {})) {
+ if (key.startsWith("on") && typeof value === "function") {
+ el.addEventListener(key.substring(2).toLowerCase(), value);
+ } else if (key === "style" && typeof value === "object") {
+ Object.assign(el.style, value);
+ } else {
+ el.setAttribute(key, value);
+ }
+ }
+
+ const appendChild = (child) => {
+ if (Array.isArray(child)) {
+ child.forEach(appendChild);
+ } else if (typeof child === "function") {
+ const placeholder = document.createTextNode("");
+ el.appendChild(placeholder);
+ e(() => {
+ placeholder.textContent = child() ?? "";
+ });
+ } else if (child instanceof Node) {
+ el.appendChild(child);
+ } else if (child != null) {
+ el.appendChild(document.createTextNode(String(child)));
+ }
+ };
+
+ children.forEach(appendChild);
+ return el;
+}
+
+function track(target, key) {
+ if (!activeEffect) {
+ return;
+ }
+ let depsMap = targetMap.get(target);
+ if (!depsMap) {
+ depsMap = new Map();
+ targetMap.set(target, depsMap);
+ }
+
+ let dep = depsMap.get(key);
+ if (!dep) {
+ dep = new Set();
+ depsMap.set(key, dep);
+ }
+
+ dep.add(activeEffect);
+}
+
+function trigger(target, key) {
+ const depsMap = targetMap.get(target);
+ if (!depsMap) {
+ return;
+ }
+
+ const dep = depsMap.get(key);
+ if (dep) {
+ dep.forEach((effect) => effect());
+ }
+}
+
+//**
+// Create a reactive value, the value is at .value.
+// To use this in element props you need to supply the .value read as a function.
+// */
+export function r(target) {
+ target = { value: target };
+ return new Proxy(target, {
+ get(obj, key, receiver) {
+ track(obj, key);
+ return Reflect.get(obj, key, receiver);
+ },
+ set(obj, key, value, receiver) {
+ const result = Reflect.set(obj, key, value, receiver);
+ trigger(obj, key);
+ return result;
+ },
+ });
+}
+
+//**
+// Run code when value changes
+// */
+export function e(fn) {
+ let active = true;
+
+ const runner = () => {
+ if (active) {
+ activeEffect = runner;
+ fn();
+ activeEffect = null;
+ }
+ };
+
+ runner();
+
+ runner.stop = () => {
+ active = false;
+ };
+
+ return runner;
+}
+
+export function gqp(key) {
+ return new URLSearchParams(location.search).get(key)
+}
+
+export function sqp(query) {
+ if ('URLSearchParams' in window) {
+ const url = new URL(window.location)
+ for (const key of Object.keys(query)) {
+ const value = encodeURIComponent(query[key])
+ if (!value || value === "") url.searchParams.delete(key)
+ else url.searchParams.set(key, value)
+ }
+ history.pushState(null, '', url);
+ }
+}
+
+//**
+// Combine elements
+// */
+export function c(a, b) {
+ const normalize = (x) => (x == null ? [] : Array.isArray(x) ? x : [x]);
+
+ return [...normalize(a), ...normalize(b)];
+}
+
+//**
+// Mount element to a target (target is #root by default)
+// */
+export async function m(component, target = root) {
+ if (typeof component === "function") {
+ component = await component();
+ }
+ if (Array.isArray(component)) {
+ target.append(...component);
+ } else {
+ target.appendChild(component);
+ }
+}
+
+export function css(styleObject) {
+ return Object.entries(styleObject).map(([key, value]) => {
+ const kebabKey = key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
+ return `${kebabKey}: ${value}`;
+ }).join("; ");
+}
+
+//**
+// Create element
+// */
+export function t(name, props, ...children) {
+ if (typeof name === "function") {
+ return name({ ...props, children });
+ }
+ return createElement(name, props, children);
+}