rask-ui 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +923 -185
- package/dist/observation.d.ts +1 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +3 -16
- package/dist/tests/class.test.js +42 -0
- package/dist/tests/component.props.test.js +252 -6
- package/dist/tests/component.state.test.js +21 -15
- package/dist/tests/createState.test.js +8 -16
- package/dist/tests/observation.test.js +0 -37
- package/dist/vdom/ComponentVNode.d.ts.map +1 -1
- package/dist/vdom/ComponentVNode.js +26 -16
- package/dist/vdom/ElementVNode.d.ts +6 -0
- package/dist/vdom/ElementVNode.d.ts.map +1 -1
- package/dist/vdom/ElementVNode.js +30 -8
- package/dist/vdom/RootVNode.d.ts +3 -0
- package/dist/vdom/RootVNode.d.ts.map +1 -1
- package/dist/vdom/RootVNode.js +15 -0
- package/dist/vdom/TextVNode.d.ts.map +1 -1
- package/dist/vdom/TextVNode.js +3 -0
- package/dist/vdom/dom-utils.d.ts.map +1 -1
- package/dist/vdom/dom-utils.js +13 -3
- package/package.json +4 -3
|
@@ -20,5 +20,11 @@ export declare class ElementVNode extends AbstractVNode {
|
|
|
20
20
|
private setProp;
|
|
21
21
|
private patchProps;
|
|
22
22
|
private addEventListener;
|
|
23
|
+
/**
|
|
24
|
+
* Intelligently sync DOM to match children VNode order.
|
|
25
|
+
* Only performs DOM operations when elements are out of position.
|
|
26
|
+
* This is used by both patch() and rerender() to efficiently update children.
|
|
27
|
+
*/
|
|
28
|
+
private syncDOMChildren;
|
|
23
29
|
}
|
|
24
30
|
//# sourceMappingURL=ElementVNode.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ElementVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/ElementVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAUvC,qBAAa,YAAa,SAAQ,aAAa;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,GAAG,CAAC,CAA0D;IACtE,OAAO,CAAC,cAAc,CAAC,CAA6B;gBAElD,GAAG,EAAE,MAAM,EACX,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,EACxB,QAAQ,EAAE,KAAK,EAAE,EACjB,GAAG,CAAC,EAAE,MAAM;IASd,QAAQ,IAAI,IAAI;
|
|
1
|
+
{"version":3,"file":"ElementVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/ElementVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAUvC,qBAAa,YAAa,SAAQ,aAAa;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,GAAG,CAAC,CAA0D;IACtE,OAAO,CAAC,cAAc,CAAC,CAA6B;gBAElD,GAAG,EAAE,MAAM,EACX,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,EACxB,QAAQ,EAAE,KAAK,EAAE,EACjB,GAAG,CAAC,EAAE,MAAM;IASd,QAAQ,IAAI,IAAI;IAGhB,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI;IAkC3B;;;;OAIG;IACH,KAAK,CAAC,OAAO,EAAE,YAAY;IAM3B,OAAO;IAYP,OAAO,CAAC,OAAO,CAoCb;IACF,OAAO,CAAC,UAAU;IAGlB,OAAO,CAAC,gBAAgB;IAgBxB;;;;OAIG;IACH,OAAO,CAAC,eAAe;CAyBxB"}
|
|
@@ -18,10 +18,7 @@ export class ElementVNode extends AbstractVNode {
|
|
|
18
18
|
this.ref = ref;
|
|
19
19
|
}
|
|
20
20
|
rerender() {
|
|
21
|
-
|
|
22
|
-
.map((child) => child.getElements())
|
|
23
|
-
.flat();
|
|
24
|
-
this.elm.replaceChildren(...childrenElms);
|
|
21
|
+
this.syncDOMChildren();
|
|
25
22
|
}
|
|
26
23
|
mount(parent) {
|
|
27
24
|
this.parent = parent;
|
|
@@ -61,10 +58,7 @@ export class ElementVNode extends AbstractVNode {
|
|
|
61
58
|
this.patchProps(newNode.props);
|
|
62
59
|
this.props = newNode.props;
|
|
63
60
|
this.children = this.patchChildren(newNode.children);
|
|
64
|
-
|
|
65
|
-
.map((child) => child.getElements())
|
|
66
|
-
.flat();
|
|
67
|
-
this.elm.replaceChildren(...childrenElms);
|
|
61
|
+
this.syncDOMChildren();
|
|
68
62
|
}
|
|
69
63
|
unmount() {
|
|
70
64
|
this.children.forEach((child) => child.unmount());
|
|
@@ -123,4 +117,32 @@ export class ElementVNode extends AbstractVNode {
|
|
|
123
117
|
delete this.eventListeners[type];
|
|
124
118
|
}
|
|
125
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Intelligently sync DOM to match children VNode order.
|
|
122
|
+
* Only performs DOM operations when elements are out of position.
|
|
123
|
+
* This is used by both patch() and rerender() to efficiently update children.
|
|
124
|
+
*/
|
|
125
|
+
syncDOMChildren() {
|
|
126
|
+
const elm = this.elm;
|
|
127
|
+
let currentDomChild = elm.firstChild;
|
|
128
|
+
for (const child of this.children) {
|
|
129
|
+
const childNodes = child.getElements();
|
|
130
|
+
for (const node of childNodes) {
|
|
131
|
+
if (currentDomChild === node) {
|
|
132
|
+
// Already in correct position, advance pointer
|
|
133
|
+
currentDomChild = currentDomChild.nextSibling;
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// Insert (or move if it exists elsewhere in DOM)
|
|
137
|
+
elm.insertBefore(node, currentDomChild);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Remove any leftover nodes (shouldn't happen if unmount works correctly)
|
|
142
|
+
while (currentDomChild) {
|
|
143
|
+
const next = currentDomChild.nextSibling;
|
|
144
|
+
elm.removeChild(currentDomChild);
|
|
145
|
+
currentDomChild = next;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
126
148
|
}
|
package/dist/vdom/RootVNode.d.ts
CHANGED
|
@@ -6,9 +6,12 @@ export declare class RootVNode extends AbstractVNode {
|
|
|
6
6
|
children: VNode[];
|
|
7
7
|
componentStack: ComponentInstance[];
|
|
8
8
|
private lifecycleQueue;
|
|
9
|
+
private hasPendingMicroTask;
|
|
10
|
+
private pendingObservers;
|
|
9
11
|
constructor(rootNode: VNode, container: HTMLElement);
|
|
10
12
|
queueMount(cb: () => void): void;
|
|
11
13
|
queueUnmount(cb: () => void): void;
|
|
14
|
+
queueObserver(cb: () => void): void;
|
|
12
15
|
flushLifecycle(): void;
|
|
13
16
|
pushComponent(instance: ComponentInstance): void;
|
|
14
17
|
popComponent(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RootVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/RootVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAIrD,eAAO,IAAI,WAAW,EAAE,SAAS,GAAG,SAAS,CAAC;AAE9C,qBAAa,SAAU,SAAQ,aAAa;IAC1C,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,cAAc,EAAE,iBAAiB,EAAE,CAAM;IACzC,OAAO,CAAC,cAAc,CAGpB;
|
|
1
|
+
{"version":3,"file":"RootVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/RootVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAIrD,eAAO,IAAI,WAAW,EAAE,SAAS,GAAG,SAAS,CAAC;AAE9C,qBAAa,SAAU,SAAQ,aAAa;IAC1C,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,cAAc,EAAE,iBAAiB,EAAE,CAAM;IACzC,OAAO,CAAC,cAAc,CAGpB;IACF,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,gBAAgB,CAAyB;gBAErC,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW;IAMnD,UAAU,CAAC,EAAE,EAAE,MAAM,IAAI;IAIzB,YAAY,CAAC,EAAE,EAAE,MAAM,IAAI;IAG3B,aAAa,CAAC,EAAE,EAAE,MAAM,IAAI;IAa5B,cAAc;IAOd,aAAa,CAAC,QAAQ,EAAE,iBAAiB;IAIzC,YAAY;IAIZ,YAAY;IAIZ,YAAY;IAMZ,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE;IAGtB,KAAK,IAAI,IAAI;IACb,QAAQ,IAAI,IAAI;IAShB,OAAO,IAAI,IAAI;CAChB"}
|
package/dist/vdom/RootVNode.js
CHANGED
|
@@ -9,6 +9,8 @@ export class RootVNode extends AbstractVNode {
|
|
|
9
9
|
toMount: [],
|
|
10
10
|
toUnmount: [],
|
|
11
11
|
};
|
|
12
|
+
hasPendingMicroTask = false;
|
|
13
|
+
pendingObservers = [];
|
|
12
14
|
constructor(rootNode, container) {
|
|
13
15
|
super();
|
|
14
16
|
this.elm = container;
|
|
@@ -20,6 +22,19 @@ export class RootVNode extends AbstractVNode {
|
|
|
20
22
|
queueUnmount(cb) {
|
|
21
23
|
this.lifecycleQueue.toUnmount.push(cb);
|
|
22
24
|
}
|
|
25
|
+
queueObserver(cb) {
|
|
26
|
+
this.pendingObservers.push(cb);
|
|
27
|
+
if (!this.hasPendingMicroTask) {
|
|
28
|
+
this.hasPendingMicroTask = true;
|
|
29
|
+
queueMicrotask(() => {
|
|
30
|
+
this.hasPendingMicroTask = false;
|
|
31
|
+
const pendingObservers = this.pendingObservers;
|
|
32
|
+
this.pendingObservers = [];
|
|
33
|
+
pendingObservers.forEach((pendingObserver) => pendingObserver());
|
|
34
|
+
this.flushLifecycle();
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
23
38
|
flushLifecycle() {
|
|
24
39
|
this.lifecycleQueue.toUnmount.forEach((cb) => cb());
|
|
25
40
|
this.lifecycleQueue.toUnmount = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/TextVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,qBAAa,SAAU,SAAQ,aAAa;IAC1C,IAAI,EAAE,MAAM,CAAC;gBACD,IAAI,EAAE,MAAM;IAIxB,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI;IAe3B,KAAK,CAAC,OAAO,EAAE,SAAS;
|
|
1
|
+
{"version":3,"file":"TextVNode.d.ts","sourceRoot":"","sources":["../../src/vdom/TextVNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,qBAAa,SAAU,SAAQ,aAAa;IAC1C,IAAI,EAAE,MAAM,CAAC;gBACD,IAAI,EAAE,MAAM;IAIxB,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG,IAAI;IAe3B,KAAK,CAAC,OAAO,EAAE,SAAS;IAQxB,QAAQ,IAAI,IAAI;IAChB,OAAO;CAMR"}
|
package/dist/vdom/TextVNode.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dom-utils.d.ts","sourceRoot":"","sources":["../../src/vdom/dom-utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,IAAI,GAAG,IAAI,EAAE,QAO3B;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,CAc3D;AAGD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,QAQtE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,QAE3E;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,IAAI,QAOrB;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,QAe/C;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"dom-utils.d.ts","sourceRoot":"","sources":["../../src/vdom/dom-utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,IAAI,GAAG,IAAI,EAAE,QAO3B;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,CAc3D;AAGD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,QAQtE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,QAE3E;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,IAAI,QAOrB;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,QAe/C;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,QA0B3D"}
|
package/dist/vdom/dom-utils.js
CHANGED
|
@@ -59,16 +59,26 @@ export function isEventProp(name) {
|
|
|
59
59
|
}
|
|
60
60
|
export function setElementClass(elm, value) {
|
|
61
61
|
if (value === null || value === undefined) {
|
|
62
|
-
elm.
|
|
62
|
+
elm.removeAttribute("class");
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
if (typeof value === "string") {
|
|
66
|
-
|
|
66
|
+
if (value === "") {
|
|
67
|
+
elm.removeAttribute("class");
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
elm.className = value;
|
|
71
|
+
}
|
|
67
72
|
return;
|
|
68
73
|
}
|
|
69
74
|
// Handle object notation: { "class-name": true, "other-class": false }
|
|
70
75
|
const classes = Object.keys(value)
|
|
71
76
|
.filter((key) => value[key])
|
|
72
77
|
.join(" ");
|
|
73
|
-
|
|
78
|
+
if (classes === "") {
|
|
79
|
+
elm.removeAttribute("class");
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
elm.className = classes;
|
|
83
|
+
}
|
|
74
84
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rask-ui",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -19,10 +19,11 @@
|
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
|
-
"dist"
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md"
|
|
23
24
|
],
|
|
24
25
|
"scripts": {
|
|
25
|
-
"build": "tsc && cp src/jsx.d.ts dist/",
|
|
26
|
+
"build": "tsc && cp src/jsx.d.ts dist/ && cp ../../README.md .",
|
|
26
27
|
"dev": "tsc --watch",
|
|
27
28
|
"test": "vitest",
|
|
28
29
|
"test:ui": "vitest --ui",
|