ks-fwork 3.0.4 → 4.0.0
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/dist/ks-fwork.js +37 -2
- package/package.json +1 -1
- package/src/component.js +11 -1
- package/src/destroy-dom.js +2 -0
- package/src/mount-dom.js +4 -1
- package/src/scheduler.js +28 -0
package/dist/ks-fwork.js
CHANGED
|
@@ -195,6 +195,31 @@ function extractChildren(vNode) {
|
|
|
195
195
|
return children;
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
+
let isScheduled = false;
|
|
199
|
+
const jobs = [];
|
|
200
|
+
function enqueueJob(job) {
|
|
201
|
+
jobs.push(job);
|
|
202
|
+
scheduleUpdate();
|
|
203
|
+
}
|
|
204
|
+
function scheduleUpdate() {
|
|
205
|
+
if (isScheduled) return;
|
|
206
|
+
isScheduled = true;
|
|
207
|
+
queueMicrotask(processJobs);
|
|
208
|
+
}
|
|
209
|
+
function processJobs() {
|
|
210
|
+
while (jobs.length > 0) {
|
|
211
|
+
const job = jobs.shift();
|
|
212
|
+
try {
|
|
213
|
+
Promise.resolve(job()).catch((error) => {
|
|
214
|
+
console.error(`[scheduler]: ${error}`);
|
|
215
|
+
});
|
|
216
|
+
} catch (error) {
|
|
217
|
+
console.error(`[scheduler]: ${error}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
isScheduled = false;
|
|
221
|
+
}
|
|
222
|
+
|
|
198
223
|
function destroyDOM(vNode) {
|
|
199
224
|
const { type } = vNode;
|
|
200
225
|
switch (type) {
|
|
@@ -212,6 +237,7 @@ function destroyDOM(vNode) {
|
|
|
212
237
|
}
|
|
213
238
|
case DOM_TYPES.COMPONENT: {
|
|
214
239
|
vNode.component.unmount();
|
|
240
|
+
enqueueJob(() => vNode.component.onUnmounted());
|
|
215
241
|
break;
|
|
216
242
|
}
|
|
217
243
|
default: {
|
|
@@ -287,7 +313,7 @@ function extractPropsAndEvents(vNode) {
|
|
|
287
313
|
return { props, events }
|
|
288
314
|
}
|
|
289
315
|
|
|
290
|
-
function mountDOM(vNode, parentEl, index
|
|
316
|
+
function mountDOM(vNode, parentEl, index, hostComponent = null) {
|
|
291
317
|
switch (vNode.type) {
|
|
292
318
|
case DOM_TYPES.TEXT: {
|
|
293
319
|
createTextNode(vNode, parentEl, index);
|
|
@@ -303,6 +329,8 @@ function mountDOM(vNode, parentEl, index = undefined, hostComponent = null) {
|
|
|
303
329
|
}
|
|
304
330
|
case DOM_TYPES.COMPONENT: {
|
|
305
331
|
createComponentNode(vNode, parentEl, index, hostComponent);
|
|
332
|
+
enqueueJob(() => vNode.component.onMounted());
|
|
333
|
+
break;
|
|
306
334
|
}
|
|
307
335
|
default: {
|
|
308
336
|
throw new Error(`Can't mount virtual node of type: ${vNode.type}`);
|
|
@@ -640,7 +668,8 @@ class Dispatcher {
|
|
|
640
668
|
}
|
|
641
669
|
}
|
|
642
670
|
|
|
643
|
-
|
|
671
|
+
const emptyFn = () => {};
|
|
672
|
+
function defineComponent({ render, state, onMounted = emptyFn, onUnmounted = emptyFn, ...methods }) {
|
|
644
673
|
class Component {
|
|
645
674
|
#isMounted = false;
|
|
646
675
|
#vNode = null;
|
|
@@ -655,6 +684,12 @@ function defineComponent({ render, state, ...methods }) {
|
|
|
655
684
|
this.#eventHandlers = eventHandlers;
|
|
656
685
|
this.#parentComponent = parentComponent;
|
|
657
686
|
}
|
|
687
|
+
onMounted() {
|
|
688
|
+
return Promise.resolve(onMounted.call(this));
|
|
689
|
+
}
|
|
690
|
+
onUnmounted() {
|
|
691
|
+
return Promise.resolve(onUnmounted.call(this));
|
|
692
|
+
}
|
|
658
693
|
get elements() {
|
|
659
694
|
if (this.#vNode == null) {
|
|
660
695
|
return [];
|
package/package.json
CHANGED
package/src/component.js
CHANGED
|
@@ -7,7 +7,9 @@ import { hasOwnProperty } from "./utils/objects.js";
|
|
|
7
7
|
import equal from 'fast-deep-equal';
|
|
8
8
|
import { Dispatcher } from "./dispatcher.js";
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
const emptyFn = () => {};
|
|
11
|
+
|
|
12
|
+
export function defineComponent({ render, state, onMounted = emptyFn, onUnmounted = emptyFn, ...methods }) {
|
|
11
13
|
class Component {
|
|
12
14
|
#isMounted = false;
|
|
13
15
|
#vNode = null;
|
|
@@ -24,6 +26,14 @@ export function defineComponent({ render, state, ...methods }) {
|
|
|
24
26
|
this.#parentComponent = parentComponent;
|
|
25
27
|
}
|
|
26
28
|
|
|
29
|
+
onMounted() {
|
|
30
|
+
return Promise.resolve(onMounted.call(this));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
onUnmounted() {
|
|
34
|
+
return Promise.resolve(onUnmounted.call(this));
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
get elements() {
|
|
28
38
|
// If vNode is null, return an empty array
|
|
29
39
|
if (this.#vNode == null) {
|
package/src/destroy-dom.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { removeEventListeners } from './events.js'
|
|
2
2
|
import { DOM_TYPES } from "./h.js";
|
|
3
|
+
import { enqueueJob } from "./scheduler.js";
|
|
3
4
|
|
|
4
5
|
// Recursively destroy a virtual node (and its subtree).
|
|
5
6
|
export function destroyDOM(vNode) {
|
|
@@ -23,6 +24,7 @@ export function destroyDOM(vNode) {
|
|
|
23
24
|
|
|
24
25
|
case DOM_TYPES.COMPONENT: {
|
|
25
26
|
vNode.component.unmount();
|
|
27
|
+
enqueueJob(() => vNode.component.onUnmounted());
|
|
26
28
|
break;
|
|
27
29
|
}
|
|
28
30
|
|
package/src/mount-dom.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { DOM_TYPES } from "./h.js";
|
|
2
2
|
import { setAttributes } from './attributes.js'
|
|
3
3
|
import { addEventListeners } from "./events.js";
|
|
4
|
+
import { enqueueJob } from "./scheduler.js";
|
|
4
5
|
import { extractPropsAndEvents } from "./utils/props.js";
|
|
5
6
|
|
|
6
7
|
// Recursively mount a virtual node (and its subtree) into a real parent DOM element.
|
|
7
|
-
export function mountDOM(vNode, parentEl, index
|
|
8
|
+
export function mountDOM(vNode, parentEl, index, hostComponent = null) {
|
|
8
9
|
switch (vNode.type) {
|
|
9
10
|
case DOM_TYPES.TEXT: {
|
|
10
11
|
createTextNode(vNode, parentEl, index);
|
|
@@ -23,6 +24,8 @@ export function mountDOM(vNode, parentEl, index = undefined, hostComponent = nul
|
|
|
23
24
|
|
|
24
25
|
case DOM_TYPES.COMPONENT: {
|
|
25
26
|
createComponentNode(vNode, parentEl, index, hostComponent);
|
|
27
|
+
enqueueJob(() => vNode.component.onMounted());
|
|
28
|
+
break;
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
default: {
|
package/src/scheduler.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
let isScheduled = false;
|
|
2
|
+
const jobs = [];
|
|
3
|
+
|
|
4
|
+
export function enqueueJob(job) {
|
|
5
|
+
jobs.push(job);
|
|
6
|
+
scheduleUpdate();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function scheduleUpdate() {
|
|
10
|
+
if (isScheduled) return;
|
|
11
|
+
|
|
12
|
+
isScheduled = true;
|
|
13
|
+
queueMicrotask(processJobs);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function processJobs() {
|
|
17
|
+
while (jobs.length > 0) {
|
|
18
|
+
const job = jobs.shift();
|
|
19
|
+
try {
|
|
20
|
+
Promise.resolve(job()).catch((error) => {
|
|
21
|
+
console.error(`[scheduler]: ${error}`);
|
|
22
|
+
});
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error(`[scheduler]: ${error}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
isScheduled = false;
|
|
28
|
+
}
|