mirror of
https://github.com/MercuryWorkshop/dreamlandjs.git
synced 2025-05-16 23:50:00 -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 = {
|
||||
[index: string]: any
|
||||
};
|
||||
type ElementType = string | Component<any, any>;
|
||||
type ElementType = Fragment | string | Component<any, any>;
|
||||
type Element = DLElement<any>;
|
||||
|
||||
interface ElementAttributesProperty {
|
||||
|
@ -42,6 +42,9 @@ type DLCSS = string;
|
|||
|
||||
declare var $el: HTMLElement;
|
||||
|
||||
type Fragment = { readonly fragment: unique symbol };
|
||||
declare var Fragment: Fragment;
|
||||
|
||||
interface Element {
|
||||
$: OuterComponentTypes & { [index: string | symbol]: any }
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ To get started with AliceJS, add this to the compileroptions of your `tsconfig.j
|
|||
```json
|
||||
"jsx":"react",
|
||||
"jsxFactory":"h",
|
||||
"jsxFragmentFactory":"YOU_CANT_USE_FRAGMENTS",
|
||||
"jsxFragmentFactory":"Fragment",
|
||||
"types": ["@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
|
||||
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 PROXY = Symbol();
|
||||
const STEPS = Symbol();
|
||||
const LISTENERS = Symbol();
|
||||
const IF = Symbol();
|
||||
const TRAPS = new Map;
|
||||
// This wraps the target in a proxy, doing 2 things:
|
||||
// - 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("");
|
||||
then ??= document.createTextNode("");
|
||||
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
|
||||
|
@ -164,7 +157,9 @@ export function useValue(references) {
|
|||
|
||||
// Actual JSX factory. Responsible for creating the HTML elements and all of the *reactive* syntactic sugar
|
||||
export function h(type, props, ...children) {
|
||||
if (type === Fragment) return children;
|
||||
if (typeof type === "function") {
|
||||
// functional components. create the stateful object
|
||||
let newthis = stateful(Object.create(type.prototype));
|
||||
|
||||
for (const name in props) {
|
||||
|
@ -222,7 +217,25 @@ export function h(type, props, ...children) {
|
|||
let xmlns = props?.xmlns;
|
||||
const elm = xmlns ? document.createElementNS(xmlns, type) : document.createElement(type);
|
||||
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -308,21 +321,16 @@ function JSXAddChild(child, cb) {
|
|||
if (isDLPtr(child)) {
|
||||
let appended = [];
|
||||
handle(child, (val) => {
|
||||
if (appended.length > 1) {
|
||||
// this is why we don't encourage arrays (jank)
|
||||
let v = appended[0]?.previousSibling;
|
||||
appended.forEach(n => n.remove());
|
||||
appended = JSXAddChild(val, cb);
|
||||
} else if (appended.length > 0) {
|
||||
let old = appended[0];
|
||||
appended = JSXAddChild(val, cb);
|
||||
if (appended[0]) {
|
||||
old.replaceWith(appended[0])
|
||||
} else {
|
||||
old.remove();
|
||||
}
|
||||
} else {
|
||||
appended = JSXAddChild(val, cb);
|
||||
appended = JSXAddChild(val, el => {
|
||||
if (v) {
|
||||
v.after(el);
|
||||
v = el;
|
||||
}
|
||||
else
|
||||
cb(el);
|
||||
});
|
||||
});
|
||||
} else if (child instanceof Node) {
|
||||
cb(child);
|
||||
|
@ -332,6 +340,7 @@ function JSXAddChild(child, cb) {
|
|||
for (const childchild of child) {
|
||||
elms = elms.concat(JSXAddChild(childchild, cb));
|
||||
}
|
||||
if (!elms[0]) elms = JSXAddChild("", cb);
|
||||
return elms;
|
||||
} else {
|
||||
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;
|
||||
|
||||
addEventListener("beforeunload", () => {
|
||||
localStorage.setItem(JSON.stringify(target));
|
||||
console.info("[dreamland.js]: saving " + ident);
|
||||
localStorage.setItem(ident, JSON.stringify(target));
|
||||
});
|
||||
|
||||
return stateful(target);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue