From 8c5a8d65dfda9447258e572cc6a6f3733e349492 Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Fri, 7 Feb 2025 15:23:08 -0500 Subject: [PATCH 1/2] empty --- .vscode/settings.json | 3 - app.js | 57 ----------- apptest.js | 7 -- appx.js | 26 ----- index.html | 10 -- lib/gale/gale.js | 72 ------------- lib/test.d.ts | 6 -- lib/test.js | 4 - lib/van/hmr.js | 62 ----------- lib/van/van.d.ts | 48 --------- lib/van/van.js | 227 ----------------------------------------- lib/van/van.members.js | 8 -- lib/vanx/hmr.js | 8 -- lib/vanx/vanx.d.ts | 24 ----- lib/vanx/vanx.js | 5 - tsconfig.json | 6 -- 16 files changed, 573 deletions(-) delete mode 100644 .vscode/settings.json delete mode 100644 app.js delete mode 100644 apptest.js delete mode 100644 appx.js delete mode 100644 index.html delete mode 100644 lib/gale/gale.js delete mode 100644 lib/test.d.ts delete mode 100644 lib/test.js delete mode 100644 lib/van/hmr.js delete mode 100644 lib/van/van.d.ts delete mode 100644 lib/van/van.js delete mode 100644 lib/van/van.members.js delete mode 100644 lib/vanx/hmr.js delete mode 100644 lib/vanx/vanx.d.ts delete mode 100644 lib/vanx/vanx.js delete mode 100644 tsconfig.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 6f3a291..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "liveServer.settings.port": 5501 -} \ No newline at end of file diff --git a/app.js b/app.js deleted file mode 100644 index b8a99ad..0000000 --- a/app.js +++ /dev/null @@ -1,57 +0,0 @@ -//@ts-check -import Gale from "./lib/gale/gale.js"; -import Van from "./lib/van/van.js"; -import HMR from "./lib/van/hmr.js"; - -const css = Gale({ - Board:{ - padding: "1rem", - background: "blue", - color: "white" - } -}) - - -const Components = { - Title() - { - const titleString = Van.state("title"); - return ()=> div({class:css("Board"), onclick(){ - titleString.val = Math.random(); - }}, titleString.val); - } -} - -const {div} = Van.tags; -Van.add(document.querySelector("#app"), Components.Title()); - - -const World = { - Round: Van.state(0), - Turn: Van.state(0), - Energy: Van.state([4, 4, 4]) -}; - -/** @typedef {[From:number, To:number]} Transfer */ - -/** @typedef {{Transfers:Transfer[], Power:number, Vector:number[], Charge:number, Effect:string}} Ability */ - -/** @type Ability */ -const Ability = { - Transfers:[], - Power:1, - Vector:[], - Charge:0, - Effect:"damage" -}; - - -/** @typedef {{}} Character */ - -function shuffleArray(array) { - for (let i = array.length - 1; i > 0; i--) { - let j = Math.floor(Math.random() * (i + 1)); - [array[i], array[j]] = [array[j], array[i]]; - } - return array; -} \ No newline at end of file diff --git a/apptest.js b/apptest.js deleted file mode 100644 index 12271df..0000000 --- a/apptest.js +++ /dev/null @@ -1,7 +0,0 @@ -import Test from "./lib/test.js"; - - -/** @type {Test.de} */ -const thing =()=>{} - -console.log(Test.default("a", "b")); \ No newline at end of file diff --git a/appx.js b/appx.js deleted file mode 100644 index 611a498..0000000 --- a/appx.js +++ /dev/null @@ -1,26 +0,0 @@ -import vanX from "./lib/vanx/vanx.js"; -import Van from "./lib/van/van.js"; - - -const {span, input, button} = Van.tags; - - -const data = vanX.reactive({name: {first: "Tao", last: "Xin"}}); -const flatDerived = vanX.calc(() => `${data.name.first} ${data.name.last}`); - -const Name = () => { - - return span( - "First name: ", - input({type: "text", value: () => data.name.first, - oninput: e => data.name.first = e.target.value}), " ", - "Last name: ", - input({type: "text", value: () => data.name.last, - oninput: e => data.name.last = e.target.value}), " ", - //"Full name: ", () => derived.fullName, " ", - "CALC:", flatDerived, - button({onclick: () => data.name = {first: "Tao", last: "Xin"}}, "Reset"), - ) - } - - Van.add(document.body, Name()); \ No newline at end of file diff --git a/index.html b/index.html deleted file mode 100644 index 50a7af0..0000000 --- a/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - -

Le App

-
- - - - \ No newline at end of file diff --git a/lib/gale/gale.js b/lib/gale/gale.js deleted file mode 100644 index 4646e3a..0000000 --- a/lib/gale/gale.js +++ /dev/null @@ -1,72 +0,0 @@ -// @ts-check -const KeyQuery = "@"; -const KeyPseudo = ":"; -const KeyChild = "."; -const KeyGroup = "^"; - -/** @typedef { Partial & {[key: `${KeyQuery|KeyPseudo|KeyChild|KeyGroup}${string}`]: UserStyles } } UserStyles */ -/** @typedef {Record} UserSheet */ - - -/** - * @template Obj - * @typedef { { [Key in keyof Obj]: Obj[Key] extends object ? Key | CollectKeys : Key }[keyof Obj] } CollectKeys - */ - -/** - * @template Keys - * @typedef { Keys extends `${KeyChild|KeyGroup}${infer Rest}` ? Keys : never } FilterKeys - */ -/** - * @template A - * @template B - * @typedef {A extends string ? B extends string ? `${A}${B}` : never : never } CrossMultiply - */ - -/** - * @template Rec - * @typedef { keyof Rec | { [K in keyof Rec]: K extends string ? CrossMultiply>> : never }[keyof Rec] } CrossMultiplyRecord - */ - - -/** @type {(selector:string, obj:UserStyles)=>string} */ -const Tier=(selector, obj)=> -{ - const styles = Object.keys(obj).map((key)=> - { - const value = obj[key]; - switch(key[0]) - { - case KeyQuery : - return Tier(`@media(max-width:${key.substring(KeyQuery.length)})`, value); - case KeyPseudo : - return Tier(`&${key}`, value); - case KeyChild : - return Tier(`${key}`, value); - case KeyGroup : - return Tier(`&:hover .${key.substring(KeyGroup.length)}`, value); - } - return `${ key.replace(/([a-z])([A-Z])/g, '$1-$2') }: ${value};` - }); - return `${selector}{${styles.join("\n")}}`; -} - -let i = 0; -/** @type {(sheet:UserSheet&T)=> ((...args:CrossMultiplyRecord[])=>string)&{css:string}} */ -export default (sheet)=> -{ - const id = i ? "_"+i : ""; - i++; - const css = Object.keys(sheet).map(key=>Tier("."+key, sheet[key])).join(`\n`); - globalThis.document?.head.insertAdjacentHTML("beforeend", ``); - const classes =(...args)=>{ - /** @type {(needle:string, str:string)=>string} */ - const extractLast =(needle, str)=>{ - const ind = str.lastIndexOf(needle)+needle.length; - return ind ? str.substring(ind) : str; - } - return args.map((arg)=>extractLast(KeyGroup, extractLast(KeyChild, arg))).join(id+" ")+id; - } - classes.css = css; - return classes; -} \ No newline at end of file diff --git a/lib/test.d.ts b/lib/test.d.ts deleted file mode 100644 index 4144124..0000000 --- a/lib/test.d.ts +++ /dev/null @@ -1,6 +0,0 @@ - -export type defaultType = (a:string, b:string)=>string; - -declare const members:defaultType - -export default members \ No newline at end of file diff --git a/lib/test.js b/lib/test.js deleted file mode 100644 index a6ea423..0000000 --- a/lib/test.js +++ /dev/null @@ -1,4 +0,0 @@ -export default function(a, b) -{ - return a + "---" + b; -} \ No newline at end of file diff --git a/lib/van/hmr.js b/lib/van/hmr.js deleted file mode 100644 index 31867ce..0000000 --- a/lib/van/hmr.js +++ /dev/null @@ -1,62 +0,0 @@ -//@ts-check -import * as Van from "./van.members.js"; - -const Gateway = { - Time: 0, - Temp:{}, - Tick() - { - for(let k in Gateway.Temp) - { - localStorage.setItem(k, Gateway.Temp[k]); - } - Gateway.Temp = {}; - Gateway.Time = 0; - }, - Save(key, value) - { - Gateway.Temp[key] = value; - if(!Gateway.Time) - { - Gateway.Time = setTimeout(Gateway.Tick, 500); - } - }, - Load(key) - { - return localStorage.getItem(key); - } -} - -/** - * HMR Wrapper for Van.state - * @template T - * @param {T} value - initial value - * @param {string} key - Storage ID - * @returns {Van.State} - */ -export default function(value, key) -{ - const type = typeof value; - let reader =(data)=>data; - let writer =(data)=> data.toString(); - - if(type === "object") - { - reader = JSON.parse; - writer = JSON.stringify; - } - else if(type === "number") - { - reader = parseFloat; - } - else if(type === "boolean") - { - reader =(data)=> data === "true"; - } - - const stringValue = Gateway.Load(key); - const signal = Van.state(/**@type{T}*/(stringValue ? reader(stringValue) : value)); - Van.derive(()=>Gateway.Save(key, writer(signal.val))); - - return signal; -} \ No newline at end of file diff --git a/lib/van/van.d.ts b/lib/van/van.d.ts deleted file mode 100644 index 969f3e0..0000000 --- a/lib/van/van.d.ts +++ /dev/null @@ -1,48 +0,0 @@ -export interface State { - val: T - readonly oldVal: T - readonly rawVal: T -} - -// Defining readonly view of State for covariance. -// Basically we want StateView to implement StateView -export type StateView = Readonly> - -export type Val = State | T - -export type Primitive = string | number | boolean | bigint - -export type PropValue = Primitive | ((e: any) => void) | null - -export type PropValueOrDerived = PropValue | StateView | (() => PropValue) - -export type Props = Record & { class?: PropValueOrDerived; is?: string } - -export type PropsWithKnownKeys = Partial<{[K in keyof ElementType]: PropValueOrDerived}> - -export type ValidChildDomValue = Primitive | Node | null | undefined - -export type BindingFunc = ((dom?: Node) => ValidChildDomValue) | ((dom?: Element) => Element) - -export type ChildDom = ValidChildDomValue | StateView | BindingFunc | readonly ChildDom[] - -export type TagFunc = (first?: Props & PropsWithKnownKeys | ChildDom, ...rest: readonly ChildDom[]) => Result - -type Tags = Readonly>> & { - [K in keyof HTMLElementTagNameMap]: TagFunc -} - -declare function state(): State -declare function state(initVal: T): State - -export interface Van { - readonly state: typeof state - readonly derive: (f: () => T) => State - readonly add: (dom: Element, ...children: readonly ChildDom[]) => Element - readonly tags: Tags & ((namespaceURI: string) => Readonly>>) - readonly hydrate: (dom: T, f: (dom: T) => T | null | undefined) => T -} - -declare const van: Van - -export default van diff --git a/lib/van/van.js b/lib/van/van.js deleted file mode 100644 index fb1200e..0000000 --- a/lib/van/van.js +++ /dev/null @@ -1,227 +0,0 @@ -// This file consistently uses `let` keyword instead of `const` for reducing the bundle size. - -// Global variables - aliasing some builtin symbols to reduce the bundle size. -let protoOf = Object.getPrototypeOf -let changedStates, derivedStates, curDeps, curNewDerives, alwaysConnectedDom = {isConnected: 1} -let gcCycleInMs = 1000, statesToGc, propSetterCache = {} -let objProto = protoOf(alwaysConnectedDom), funcProto = protoOf(protoOf), _undefined - -let addAndScheduleOnFirst = (set, s, f, waitMs) => - (set ?? (setTimeout(f, waitMs), new Set)).add(s) - -let runAndCaptureDeps = (f, deps, arg) => { - let prevDeps = curDeps - curDeps = deps - try { - return f(arg) - } catch (e) { - console.error(e) - return arg - } finally { - curDeps = prevDeps - } -} - -let keepConnected = l => l.filter(b => b._dom?.isConnected) - -let addStatesToGc = d => statesToGc = addAndScheduleOnFirst(statesToGc, d, () => { - for (let s of statesToGc) - s._bindings = keepConnected(s._bindings), - s._listeners = keepConnected(s._listeners) - statesToGc = _undefined -}, gcCycleInMs) - -let stateProto = { - get val() { - curDeps?._getters?.add(this) - return this.rawVal - }, - - get oldVal() { - curDeps?._getters?.add(this) - return this._oldVal - }, - - set val(v) { - curDeps?._setters?.add(this) - if (v !== this.rawVal) { - this.rawVal = v - this._bindings.length + this._listeners.length ? - (derivedStates?.add(this), changedStates = addAndScheduleOnFirst(changedStates, this, updateDoms)) : - this._oldVal = v - } - }, -} - -let state = initVal => ({ - __proto__: stateProto, - rawVal: initVal, - _oldVal: initVal, - _bindings: [], - _listeners: [], -}) - -let bind = (f, dom) => { - let deps = {_getters: new Set, _setters: new Set}, binding = {f}, prevNewDerives = curNewDerives - curNewDerives = [] - let newDom = runAndCaptureDeps(f, deps, dom) - newDom = (newDom ?? document).nodeType ? newDom : new Text(newDom) - for (let d of deps._getters) - deps._setters.has(d) || (addStatesToGc(d), d._bindings.push(binding)) - for (let l of curNewDerives) l._dom = newDom - curNewDerives = prevNewDerives - return binding._dom = newDom -} - -let derive = (f, s = state(), dom) => { - let deps = {_getters: new Set, _setters: new Set}, listener = {f, s} - listener._dom = dom ?? curNewDerives?.push(listener) ?? alwaysConnectedDom - s.val = runAndCaptureDeps(f, deps, s.rawVal) - for (let d of deps._getters) - deps._setters.has(d) || (addStatesToGc(d), d._listeners.push(listener)) - return s -} - -let add = (dom, ...children) => { - for (let c of children.flat(Infinity)) { - let protoOfC = protoOf(c ?? 0) - let child = protoOfC === stateProto ? bind(() => c.val) : - protoOfC === funcProto ? bind(c) : c - child != _undefined && dom.append(child) - } - return dom -} - -let tag = (ns, name, ...args) => { - let [{is, ...props}, ...children] = protoOf(args[0] ?? 0) === objProto ? args : [{}, ...args] - let dom = ns ? document.createElementNS(ns, name, {is}) : document.createElement(name, {is}) - for (let [k, v] of Object.entries(props)) { - let getPropDescriptor = proto => proto ? - Object.getOwnPropertyDescriptor(proto, k) ?? getPropDescriptor(protoOf(proto)) : - _undefined - let cacheKey = name + "," + k - let propSetter = propSetterCache[cacheKey] ??= getPropDescriptor(protoOf(dom))?.set ?? 0 - let setter = k.startsWith("on") ? - (v, oldV) => { - let event = k.slice(2) - dom.removeEventListener(event, oldV) - dom.addEventListener(event, v) - } : - propSetter ? propSetter.bind(dom) : dom.setAttribute.bind(dom, k) - let protoOfV = protoOf(v ?? 0) - k.startsWith("on") || protoOfV === funcProto && (v = derive(v), protoOfV = stateProto) - protoOfV === stateProto ? bind(() => (setter(v.val, v._oldVal), dom)) : setter(v) - } - return add(dom, children) -} - -let handler = ns => ({get: (_, name) => tag.bind(_undefined, ns, name)}) - -let update = (dom, newDom) => newDom ? newDom !== dom && dom.replaceWith(newDom) : dom.remove() - - -//let updateDoms = () => { -// let iter = 0, derivedStatesArray = [...changedStates].filter(s => s.rawVal !== s._oldVal) -// do { -// derivedStates = new Set -// for (let l of new Set(derivedStatesArray.flatMap(s => s._listeners = keepConnected(s._listeners)))) -// derive(l.f, l.s, l._dom), l._dom = _undefined -// } while (++iter < 100 && (derivedStatesArray = [...derivedStates]).length) -// let changedStatesArray = [...changedStates].filter(s => s.rawVal !== s._oldVal) -// changedStates = _undefined -// for (let b of new Set(changedStatesArray.flatMap(s => s._bindings = keepConnected(s._bindings)))) -// update(b._dom, bind(b.f, b._dom)), b._dom = _undefined -// for (let s of changedStatesArray) s._oldVal = s.rawVal -//} -/*********************************************** */ -const Gateway = { - Time: 0, - Temp:{}, - Tick() - { - for(let k in Gateway.Temp) - { - localStorage.setItem(k, Gateway.Temp[k]); - } - Gateway.Temp = {}; - Gateway.Time = 0; - }, - Save(key, value) - { - Gateway.Temp[key] = value; - if(!Gateway.Time) - { - Gateway.Time = setTimeout(Gateway.Tick, 500); - } - }, - Load(key) - { - return localStorage.getItem(key); - } -} - -function pathHash(/** @type {HTMLElement} */element) -{ - const path = []; - while (element && element !== document.body) { - - const parent = element.parentElement - path.unshift(Array.from(parent.children).indexOf(element)); // Push the index of the current element at the start of the path - element = parent; - } - return path.join('-'); // Return the path as a string, e.g., "1-0-0-2" -} - -/** - * Logs a relationship between a state and a DOM element. - * @param {any} state - The state object being tracked. - * @param {Element} dom - The DOM element affected by the state. - */ -const trackStateDomRelationship = (state, doms) => { - doms.forEach(dom => { - if(dom) - { - const hash = pathHash(dom); - Gateway.Save(hash, JSON.stringify(state)); - } - }); -}; - -// Enhanced updateDoms function -let updateDoms = () => { - let iter = 0, derivedStatesArray = [...changedStates].filter(s => s.rawVal !== s._oldVal) - do { - derivedStates = new Set - for (let l of new Set(derivedStatesArray.flatMap(s => s._listeners = keepConnected(s._listeners)))) - derive(l.f, l.s, l._dom), l._dom = _undefined - } while (++iter < 100 && (derivedStatesArray = [...derivedStates]).length) - let changedStatesArray = [...changedStates].filter(s => s.rawVal !== s._oldVal) - changedStates = _undefined - - const _block = new Set(changedStatesArray.flatMap(s =>{ - trackStateDomRelationship(s.rawVal, s._bindings.map(b=>b._dom)); - s.rawVal = "FORCE"; - return s._bindings = keepConnected(s._bindings); - })); - - for (let b of _block) { - update(b._dom, bind(b.f, b._dom)); - b._dom = _undefined; - } - - // Update old values for changed states - for (let s of changedStatesArray) { - s._oldVal = s.rawVal; - } -}; - -// Debugging helper to log the state-DOM relationships -globalThis.Divulge = () => console.log(Gateway.Temp); -globalThis.path = pathHash; -/*********************************************** */ - -export default { - tags: new Proxy(ns => new Proxy(tag, handler(ns)), handler()), - hydrate: (dom, f) => update(dom, bind(f, dom)), - add, state, derive, -} \ No newline at end of file diff --git a/lib/van/van.members.js b/lib/van/van.members.js deleted file mode 100644 index 86a03a4..0000000 --- a/lib/van/van.members.js +++ /dev/null @@ -1,8 +0,0 @@ -export * from "./van.js"; -import Van from "./van.js"; - -export const add = Van.add; -export const derive = Van.derive; -export const state = Van.state; -export const hydrate = Van.hydrate; -export const tags = Van.tags; \ No newline at end of file diff --git a/lib/vanx/hmr.js b/lib/vanx/hmr.js deleted file mode 100644 index 3827085..0000000 --- a/lib/vanx/hmr.js +++ /dev/null @@ -1,8 +0,0 @@ -import * as VanX from "./vanx.js"; - -const HMR =()=> -{ - -} - -VanX.default.reactive \ No newline at end of file diff --git a/lib/vanx/vanx.d.ts b/lib/vanx/vanx.d.ts deleted file mode 100644 index 373a3f8..0000000 --- a/lib/vanx/vanx.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as Van from "../van/van.members.js"; - -export type StateOf = { readonly [K in keyof T]: Van.State } -export type ValueType = T extends (infer V)[] ? V : T[keyof T] -export type KeyType = T extends unknown[] ? number : string -export type ReplacementFunc = - T extends (infer V)[] ? (items: V[]) => readonly V[] : - (items: [string, T[keyof T]][]) => readonly [string, T[keyof T]][] - -declare const vanX:{ - calc: (f: () => R) => R - reactive: (obj: T) => T - noreactive: (obj: T) => T, - stateFields: (obj: T) => StateOf - raw: (obj: T) => T, - list: ( - container: (() => ElementType) | ElementType, items: T, - itemFunc: (v: Van.State>, - deleter: () => void, k: KeyType) => Node - ) => ElementType, - replace: (obj: T, replacement: ReplacementFunc | T) => T, - compact: (obj: T) => T, -} -export default vanX; diff --git a/lib/vanx/vanx.js b/lib/vanx/vanx.js deleted file mode 100644 index 6387bb5..0000000 --- a/lib/vanx/vanx.js +++ /dev/null @@ -1,5 +0,0 @@ -import van from "../van/van.js"; -let e,t,r,{fromEntries:o,entries:l,keys:n,hasOwn:f,getPrototypeOf:a}=Object,{get:i,set:y,deleteProperty:c,ownKeys:s}=Reflect, -{state:m,derive:d,add:u}=van, -b=1e3,w=Symbol(),A=Symbol(),S=Symbol(),_=Symbol(),g=Symbol(),p=Symbol(),P=e=>(e[A]=1,e),v=e=>e instanceof Object&&!(e instanceof Function)&&!e[p],h=e=>{if(e?.[A]){let t=m();return d(()=>{let r=e();v(t.rawVal)&&v(r)?B(t.rawVal,r):t.val=x(r)}),t}return m(x(e))},F=e=>{let t=Array.isArray(e)?[]:{__proto__:a(e)};for(let[r,o]of l(e))t[r]=h(o);return t[S]=[],t[_]=m(1),t},O={get:(e,t,r)=>t===w?e:f(e,t)?Array.isArray(e)&&"length"===t?(e[_].val,e.length):e[t].val:i(e,t,r),set:(e,o,l,n)=>f(e,o)?Array.isArray(e)&&"length"===o?(l!==e.length&&++e[_].val,e.length=l,1):(e[o].val=x(l),1):o in e?y(e,o,l,n):y(e,o,h(l))&&(++e[_].val,C(e).forEach(E.bind(t,n,o,e[o],r)),1),deleteProperty:(e,t)=>(c(e,t)&&R(e,t),++e[_].val),ownKeys:e=>(e[_].val,s(e))},x=e=>!v(e)||e[w]?e:new Proxy(F(e),O),D=e=>(e[p]=1,e),j=e=>e[w],K=a(m()),N=e=>new Proxy(e,{get:(e,t,r)=>a(e[t]??0)===K?{val:k(e[t].rawVal)}:i(e,t,r)}),k=e=>e?.[w]?new Proxy(N(e[w]),O):e,C=e=>e[S]=e[S].filter(e=>e.t.isConnected),E=(e,t,r,o,{t:l,f:f})=>{let a=Array.isArray(e),i=a?Number(t):t;u(l,()=>l[g][t]=f(r,()=>delete e[t],i)),a&&!o&&i!==e.length-1&&l.insertBefore(l.lastChild,l[g][n(e).find(e=>Number(e)>i)])},R=(e,t)=>{for(let r of C(e)){let e=r.t[g];e[t]?.remove(),delete e[t]}},T=r=>(e??(setTimeout(()=>(e.forEach(C),e=t),b),e=new Set)).add(r),q=(e,t,r)=>{let o={t:e instanceof Function?e():e,f:r},n=t[w];o.t[g]={},n[S].push(o),T(n);for(let[e,r]of l(n))E(t,e,r,1,o);return o.t},z=(e,t)=>{for(let[r,o]of l(t)){let t=e[r];v(t)&&v(o)?z(t,o):e[r]=o}for(let r in e)f(t,r)||delete e[r];let r=n(t),o=Array.isArray(e);if(o||n(e).some((e,t)=>e!==r[t])){let l=e[w];if(o)e.length=t.length;else{++l[_].val;let e={...l};for(let e of r)delete l[e];for(let t of r)l[t]=e[t]}for(let{t:e}of C(l)){let{firstChild:t,[g]:o}=e;for(let l of r)t===o[l]?t=t.nextSibling:e.insertBefore(o[l],t)}}return e},B=(e,n)=>{r=1;try{return z(e,n instanceof Function?Array.isArray(e)?n(e.filter(e=>1)):o(n(l(e))):n)}finally{r=t}},G=e=>Array.isArray(e)?e.filter(e=>1).map(G):v(e)?o(l(e).map(([e,t])=>[e,G(t)])):e; -export default {calc:P,reactive:x,noreactive:D,stateFields:j,raw:k,list:q,replace:B,compact:G} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 8942f42..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "compilerOptions": { - "checkJs": true, - "lib": ["ES2024", "DOM"] - } -} \ No newline at end of file From 0f2499105ace29a7948d0f0398e35d87ec3b058e Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Fri, 7 Feb 2025 15:24:17 -0500 Subject: [PATCH 2/2] replace contents --- app.js | 32 +++++++++++++++++++ deno.json | 15 +++++++++ hmr.js | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ index.html | 29 +++++++++++++++++ van.d.ts | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 255 insertions(+) create mode 100644 app.js create mode 100644 deno.json create mode 100644 hmr.js create mode 100644 index.html create mode 100644 van.d.ts diff --git a/app.js b/app.js new file mode 100644 index 0000000..9783997 --- /dev/null +++ b/app.js @@ -0,0 +1,32 @@ +const CSS = Gale({ + Button:{ + padding: "20px", + background: "blue", + borderRadius: "20px", + color: "white", + fontWeight: "bolder", + ":hover":{ + background: "yellow" + } + } +}); + +const state = vanX.reactive({key1:"value1", key2:"value2", count:7}, "THING") +console.log(state); + +van.add +( + document.body, + van.tags.div + ( + { + class:CSS("Button"), + onclick() + { + state.count++; + } + } + , ()=>state.count + ) +); + diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..3c0c54e --- /dev/null +++ b/deno.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "checkJs": true, + "lib": [ + "dom", + "dom.iterable", + "dom.asynciterable", + "deno.ns", + "deno.unstable" + ] + }, + "imports": { + "entry": "./app.js" + } +} diff --git a/hmr.js b/hmr.js new file mode 100644 index 0000000..6bda29c --- /dev/null +++ b/hmr.js @@ -0,0 +1,92 @@ +//@ts-check +// hmr +const HMR = globalThis.HMR = { + Time: 0, + /** @type {Record} */ + Temp:{}, + Tick() + { + for(const k in HMR.Temp) + { + sessionStorage.setItem(k, HMR.Temp[k]); + } + HMR.Temp = {}; + HMR.Time = 0; + }, + /** @type {(key:string, value:string)=>void} */ + Save(key, value) + { + this.Temp[key] = value; + if(!this.Time) + { + this.Time = setTimeout(this.Tick, 500); + } + console.log("SAVE", key, value); + }, + /** @type {(key:string)=>string|null} */ + Load(key) + { + const value = sessionStorage.getItem(key); + console.log("LOAD", key, value); + return value; + }, + + /** @type {string|undefined} */ + _ID: undefined, + _index: 0, + /** @type {(id:string|undefined = undefined)=>void} */ + StartID(id) + { + this._index = 0; + this._ID = id; + }, + NextID() + { + return this._ID ? this._ID + "_" + (this._index++) + "_" : ""; + }, + + BindVan() + { + //bind Van + const origninalState = globalThis.van.state; + globalThis.van.state =(value, key="")=> + { + const type = typeof value; + let reader =d=>d; + let writer =d=>d?.toString() || null; + + switch(type) + { + case "boolean" : + reader =(data)=> data === "true"; break; + case "number" : + reader = parseFloat; break; + case "object" : + reader = JSON.parse; + writer = JSON.stringify; + break; + } + + const fullKey = "HMR_" + HMR.NextID() + key; + const stringValue = HMR.Load(fullKey); + const signal = origninalState(/**@type{T}*/(stringValue ? reader(stringValue) : value)); + van.derive(()=>HMR.Save(fullKey, writer(signal.val))); + + return signal; + }; + }, + + BindVanX() + { + //bind VanX + const originalReactive = globalThis.vanX.reactive; + globalThis.vanX.reactive =(obj, id)=> + { + HMR.StartID(id); + const state = originalReactive(obj); + HMR.StartID(); + return state; + } + } + +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..e9b9b9b --- /dev/null +++ b/index.html @@ -0,0 +1,29 @@ + + + + + Document + + + + + + + + + + \ No newline at end of file diff --git a/van.d.ts b/van.d.ts new file mode 100644 index 0000000..f29e88b --- /dev/null +++ b/van.d.ts @@ -0,0 +1,87 @@ +export {} +declare global +{ + namespace Van { + + interface State { + val: T + readonly oldVal: T + readonly rawVal: T + } + + // Defining readonly view of State for covariance. + // Basically we want StateView to implement StateView + type StateView = Readonly> + + type Val = State | T + + type Primitive = string | number | boolean | bigint + + // deno-lint-ignore no-explicit-any + type PropValue = Primitive | ((e: any) => void) | null + + type PropValueOrDerived = PropValue | StateView | (() => PropValue) + + type Props = Record & { class?: PropValueOrDerived; is?: string } + + type PropsWithKnownKeys = Partial<{[K in keyof ElementType]: PropValueOrDerived}> + + type ValidChildDomValue = Primitive | Node | null | undefined + + type BindingFunc = ((dom?: Node) => ValidChildDomValue) | ((dom?: Element) => Element) + + type ChildDom = ValidChildDomValue | StateView | BindingFunc | readonly ChildDom[] + + type TagFunc = (first?: Props & PropsWithKnownKeys | ChildDom, ...rest: readonly ChildDom[]) => Result + + type Tags = Readonly>> & { + [K in keyof HTMLElementTagNameMap]: TagFunc + } + } + const van:{ + readonly state: (initVal: T, HMRKey?:string)=> Van.State + readonly derive: (f: () => T) => Van.State + readonly add: (dom: Element, ...children: readonly Van.ChildDom[]) => Element + readonly tags: Van.Tags & ((namespaceURI: string) => Readonly>>) + readonly hydrate: (dom: T, f: (dom: T) => T | null | undefined) => T + }; + + + namespace VanX + { + type StateOf = { readonly [K in keyof T]: Van.State } + type ValueType = T extends (infer V)[] ? V : T[keyof T] + type KeyType = T extends unknown[] ? number : string + type ReplacementFunc = + T extends (infer V)[] ? (items: V[]) => readonly V[] : + (items: [string, T[keyof T]][]) => readonly [string, T[keyof T]][] + } + const vanX:{ + readonly calc: (f: () => R) => R + readonly reactive: (obj: T, HMRKey?:string) => T + readonly noreactive: (obj: T) => T + readonly stateFields: (obj: T) => VanX.StateOf + readonly raw: (obj: T) => T + readonly list: (container: (() => ElementType) | ElementType, items: T,itemFunc: (v: Van.State>, deleter: () => void, k: VanX.KeyType) => Node) => ElementType + readonly replace: (obj: T, replacement: VanX.ReplacementFunc | T) => T + readonly compact: (obj: T) => T + }; + + namespace Gale { + type KeyQuery = "@"; + type KeyPseudo = ":"; + type KeyChild = "."; + type KeyGroup = "^"; + type UserStyles = Partial & {[key: `${KeyQuery|KeyPseudo|KeyChild|KeyGroup}${string}`]: UserStyles } + type UserSheet = Record + type CollectKeys = {[Key in keyof Obj]: Obj[Key] extends object ? Key | CollectKeys : Key }[keyof Obj] + type FilterKeys = Keys extends `${KeyChild|KeyGroup}${infer Rest}` ? Keys : never + type CrossMultiply = A extends string ? B extends string ? `${A}${B}` : never : never + type CrossMultiplyRecord = keyof Rec | { [K in keyof Rec]: K extends string ? CrossMultiply>> : never }[keyof Rec] + type Tier = (selector:string, obj:UserStyles)=>string; + type CreateSheet = (sheet:UserSheet&T)=> ((...args:CrossMultiplyRecord[])=>string)&{css:string} + } + + const Gale:Gale.CreateSheet + +} \ No newline at end of file