mirror of
https://github.com/MercuryWorkshop/dreamlandjs.git
synced 2025-05-17 07:50:01 -04:00
rewrite array reactivity entirely and fix if statemensts also add fragemetns lol
This commit is contained in:
parent
21a6b460a7
commit
a3aff2f248
4 changed files with 42 additions and 30 deletions
5
AliceJS.d.ts
vendored
5
AliceJS.d.ts
vendored
|
@ -2,7 +2,7 @@ declare namespace JSX {
|
||||||
export type IntrinsicElements = {
|
export type IntrinsicElements = {
|
||||||
[index: string]: any
|
[index: string]: any
|
||||||
};
|
};
|
||||||
type ElementType = string | Component<any, any>;
|
type ElementType = Fragment | string | Component<any, any>;
|
||||||
type Element = DLElement<any>;
|
type Element = DLElement<any>;
|
||||||
|
|
||||||
interface ElementAttributesProperty {
|
interface ElementAttributesProperty {
|
||||||
|
@ -42,6 +42,9 @@ type DLCSS = string;
|
||||||
|
|
||||||
declare var $el: HTMLElement;
|
declare var $el: HTMLElement;
|
||||||
|
|
||||||
|
type Fragment = { readonly fragment: unique symbol };
|
||||||
|
declare var Fragment: Fragment;
|
||||||
|
|
||||||
interface Element {
|
interface Element {
|
||||||
$: OuterComponentTypes & { [index: string | symbol]: any }
|
$: OuterComponentTypes & { [index: string | symbol]: any }
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ To get started with AliceJS, add this to the compileroptions of your `tsconfig.j
|
||||||
```json
|
```json
|
||||||
"jsx":"react",
|
"jsx":"react",
|
||||||
"jsxFactory":"h",
|
"jsxFactory":"h",
|
||||||
"jsxFragmentFactory":"YOU_CANT_USE_FRAGMENTS",
|
"jsxFragmentFactory":"Fragment",
|
||||||
"types": ["@mercuryworkshop/alicejs"],
|
"types": ["@mercuryworkshop/alicejs"],
|
||||||
```
|
```
|
||||||
and run `npm install @mercuryworkshop/alicejs`
|
and run `npm install @mercuryworkshop/alicejs`
|
||||||
|
|
59
js.js
59
js.js
|
@ -1,3 +1,5 @@
|
||||||
|
export const Fragment = Symbol();
|
||||||
|
|
||||||
// whether to return the true value from a stateful object or a "trap" containing the pointer
|
// whether to return the true value from a stateful object or a "trap" containing the pointer
|
||||||
let __use_trap = false;
|
let __use_trap = false;
|
||||||
|
|
||||||
|
@ -30,13 +32,14 @@ Object.defineProperty(window, "use", {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Object.assign(window, { isDLPtr, h, stateful, handle, useValue, $if });
|
Object.assign(window, { isDLPtr, h, stateful, handle, useValue, $if, Fragment });
|
||||||
|
|
||||||
|
|
||||||
const TARGET = Symbol();
|
const TARGET = Symbol();
|
||||||
const PROXY = Symbol();
|
const PROXY = Symbol();
|
||||||
const STEPS = Symbol();
|
const STEPS = Symbol();
|
||||||
const LISTENERS = Symbol();
|
const LISTENERS = Symbol();
|
||||||
|
const IF = Symbol();
|
||||||
const TRAPS = new Map;
|
const TRAPS = new Map;
|
||||||
// This wraps the target in a proxy, doing 2 things:
|
// This wraps the target in a proxy, doing 2 things:
|
||||||
// - whenever a property is accessed, return a "trap" that catches and records accessors
|
// - whenever a property is accessed, return a "trap" that catches and records accessors
|
||||||
|
@ -90,18 +93,8 @@ export function $if(condition, then, otherwise) {
|
||||||
otherwise ??= document.createTextNode("");
|
otherwise ??= document.createTextNode("");
|
||||||
then ??= document.createTextNode("");
|
then ??= document.createTextNode("");
|
||||||
if (!isDLPtr(condition)) return condition ? then : otherwise;
|
if (!isDLPtr(condition)) return condition ? then : otherwise;
|
||||||
let root = then;
|
|
||||||
handle(condition, v => {
|
|
||||||
if (v) {
|
|
||||||
root.replaceWith(then);
|
|
||||||
root = then;
|
|
||||||
} else {
|
|
||||||
root.replaceWith(otherwise);
|
|
||||||
root = otherwise;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return root;
|
return { [IF]: condition, then, otherwise };
|
||||||
}
|
}
|
||||||
|
|
||||||
// This lets you subscribe to a stateful object
|
// This lets you subscribe to a stateful object
|
||||||
|
@ -164,7 +157,9 @@ export function useValue(references) {
|
||||||
|
|
||||||
// Actual JSX factory. Responsible for creating the HTML elements and all of the *reactive* syntactic sugar
|
// Actual JSX factory. Responsible for creating the HTML elements and all of the *reactive* syntactic sugar
|
||||||
export function h(type, props, ...children) {
|
export function h(type, props, ...children) {
|
||||||
|
if (type === Fragment) return children;
|
||||||
if (typeof type === "function") {
|
if (typeof type === "function") {
|
||||||
|
// functional components. create the stateful object
|
||||||
let newthis = stateful(Object.create(type.prototype));
|
let newthis = stateful(Object.create(type.prototype));
|
||||||
|
|
||||||
for (const name in props) {
|
for (const name in props) {
|
||||||
|
@ -222,7 +217,25 @@ export function h(type, props, ...children) {
|
||||||
let xmlns = props?.xmlns;
|
let xmlns = props?.xmlns;
|
||||||
const elm = xmlns ? document.createElementNS(xmlns, type) : document.createElement(type);
|
const elm = xmlns ? document.createElementNS(xmlns, type) : document.createElement(type);
|
||||||
|
|
||||||
|
|
||||||
for (const child of children) {
|
for (const child of children) {
|
||||||
|
let cond = !isDLPtr(child) && child[IF];
|
||||||
|
if (cond) {
|
||||||
|
let appended = null;
|
||||||
|
handle(cond, v => {
|
||||||
|
let before = appended?.[0]?.previousSibling;
|
||||||
|
if (appended)
|
||||||
|
appended.forEach(a => a.remove());
|
||||||
|
|
||||||
|
appended = JSXAddChild(v ? child.then : child.otherwise, el => {
|
||||||
|
if (before) {
|
||||||
|
before.after(el)
|
||||||
|
before = el;
|
||||||
|
}
|
||||||
|
else elm.appendChild(el)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else
|
||||||
JSXAddChild(child, elm.appendChild.bind(elm));
|
JSXAddChild(child, elm.appendChild.bind(elm));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,21 +321,16 @@ function JSXAddChild(child, cb) {
|
||||||
if (isDLPtr(child)) {
|
if (isDLPtr(child)) {
|
||||||
let appended = [];
|
let appended = [];
|
||||||
handle(child, (val) => {
|
handle(child, (val) => {
|
||||||
if (appended.length > 1) {
|
let v = appended[0]?.previousSibling;
|
||||||
// this is why we don't encourage arrays (jank)
|
|
||||||
appended.forEach(n => n.remove());
|
appended.forEach(n => n.remove());
|
||||||
appended = JSXAddChild(val, cb);
|
appended = JSXAddChild(val, el => {
|
||||||
} else if (appended.length > 0) {
|
if (v) {
|
||||||
let old = appended[0];
|
v.after(el);
|
||||||
appended = JSXAddChild(val, cb);
|
v = el;
|
||||||
if (appended[0]) {
|
|
||||||
old.replaceWith(appended[0])
|
|
||||||
} else {
|
|
||||||
old.remove();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
appended = JSXAddChild(val, cb);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
cb(el);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
} else if (child instanceof Node) {
|
} else if (child instanceof Node) {
|
||||||
cb(child);
|
cb(child);
|
||||||
|
@ -332,6 +340,7 @@ function JSXAddChild(child, cb) {
|
||||||
for (const childchild of child) {
|
for (const childchild of child) {
|
||||||
elms = elms.concat(JSXAddChild(childchild, cb));
|
elms = elms.concat(JSXAddChild(childchild, cb));
|
||||||
}
|
}
|
||||||
|
if (!elms[0]) elms = JSXAddChild("", cb);
|
||||||
return elms;
|
return elms;
|
||||||
} else {
|
} else {
|
||||||
let node = document.createTextNode(child);
|
let node = document.createTextNode(child);
|
||||||
|
|
2
store.js
2
store.js
|
@ -4,8 +4,8 @@ export function $store(target, ident, type) {
|
||||||
target = JSON.parse(stored) ?? target;
|
target = JSON.parse(stored) ?? target;
|
||||||
|
|
||||||
addEventListener("beforeunload", () => {
|
addEventListener("beforeunload", () => {
|
||||||
localStorage.setItem(JSON.stringify(target));
|
|
||||||
console.info("[dreamland.js]: saving " + ident);
|
console.info("[dreamland.js]: saving " + ident);
|
||||||
|
localStorage.setItem(ident, JSON.stringify(target));
|
||||||
});
|
});
|
||||||
|
|
||||||
return stateful(target);
|
return stateful(target);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue