@viewfly/core 0.0.1-alpha.3 → 0.0.1-alpha.5
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/bundles/foundation/renderer.d.ts +1 -0
- package/bundles/index.esm.js +108 -27
- package/bundles/index.js +109 -26
- package/bundles/model/component.d.ts +28 -7
- package/bundles/model/jsx-element.d.ts +7 -7
- package/bundles/model/root.component.d.ts +2 -1
- package/bundles/public-api.d.ts +1 -0
- package/bundles/viewfly.d.ts +4 -2
- package/package.json +2 -2
package/bundles/index.esm.js
CHANGED
|
@@ -3,6 +3,15 @@ import { ReflectiveInjector, normalizeProvider, NullInjector, Injectable } from
|
|
|
3
3
|
export * from '@tanbo/di';
|
|
4
4
|
import { Subject, Subscription, microTask } from '@tanbo/stream';
|
|
5
5
|
|
|
6
|
+
function makeError(name) {
|
|
7
|
+
return function viewflyError(message) {
|
|
8
|
+
const error = new Error(message);
|
|
9
|
+
error.name = `[ViewflyError: ${name}]`;
|
|
10
|
+
error.stack = error.stack.replace(/\n.*?(?=\n)/, '');
|
|
11
|
+
return error;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
6
15
|
class NativeRenderer {
|
|
7
16
|
}
|
|
8
17
|
|
|
@@ -34,15 +43,6 @@ function __metadata(metadataKey, metadataValue) {
|
|
|
34
43
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
|
|
35
44
|
}
|
|
36
45
|
|
|
37
|
-
function makeError(name) {
|
|
38
|
-
return function viewflyError(message) {
|
|
39
|
-
const error = new Error(message);
|
|
40
|
-
error.name = `[ViewflyError: ${name}]`;
|
|
41
|
-
error.stack = error.stack.replace(/\n.*?(?=\n)/, '');
|
|
42
|
-
return error;
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
46
|
const jsxErrorFn = makeError('JSX');
|
|
47
47
|
const Fragment = function Fragment() {
|
|
48
48
|
throw jsxErrorFn('Fragment does not support calling.');
|
|
@@ -180,10 +180,13 @@ class JSXElement {
|
|
|
180
180
|
|
|
181
181
|
const componentSetupStack = [];
|
|
182
182
|
const componentRendingStack = [];
|
|
183
|
+
const derivedStack = [];
|
|
183
184
|
const componentErrorFn = makeError('component');
|
|
184
185
|
function getSetupContext(need = true) {
|
|
185
186
|
const current = componentSetupStack[componentSetupStack.length - 1];
|
|
186
187
|
if (!current && need) {
|
|
188
|
+
// 防止因外部捕获异常引引起的缓存未清理的问题
|
|
189
|
+
componentRendingStack.pop();
|
|
187
190
|
throw componentErrorFn('cannot be called outside the component!');
|
|
188
191
|
}
|
|
189
192
|
return current;
|
|
@@ -191,6 +194,9 @@ function getSetupContext(need = true) {
|
|
|
191
194
|
function getRendingContext() {
|
|
192
195
|
return componentRendingStack[componentRendingStack.length - 1];
|
|
193
196
|
}
|
|
197
|
+
function getDerivedContext() {
|
|
198
|
+
return derivedStack[derivedStack.length - 1];
|
|
199
|
+
}
|
|
194
200
|
class JSXComponent {
|
|
195
201
|
constructor(createInstance) {
|
|
196
202
|
this.createInstance = createInstance;
|
|
@@ -237,20 +243,33 @@ class Component extends ReflectiveInjector {
|
|
|
237
243
|
}
|
|
238
244
|
},
|
|
239
245
|
set() {
|
|
246
|
+
// 防止因外部捕获异常引引起的缓存未清理的问题
|
|
247
|
+
if (isSetup) {
|
|
248
|
+
componentSetupStack.pop();
|
|
249
|
+
}
|
|
250
|
+
if (isRending) {
|
|
251
|
+
componentRendingStack.pop();
|
|
252
|
+
}
|
|
240
253
|
throw componentErrorFn('component props is readonly!');
|
|
241
254
|
}
|
|
242
255
|
});
|
|
243
256
|
componentSetupStack.push(this);
|
|
257
|
+
let isSetup = true;
|
|
244
258
|
const render = this.setup(props);
|
|
259
|
+
isSetup = false;
|
|
245
260
|
componentSetupStack.pop();
|
|
246
261
|
componentRendingStack.push(this);
|
|
262
|
+
let isRending = true;
|
|
247
263
|
const template = render();
|
|
264
|
+
isRending = false;
|
|
248
265
|
componentRendingStack.pop();
|
|
249
266
|
return {
|
|
250
267
|
template,
|
|
251
268
|
render: () => {
|
|
252
269
|
componentRendingStack.push(this);
|
|
270
|
+
isRending = true;
|
|
253
271
|
const template = render();
|
|
272
|
+
isRending = false;
|
|
254
273
|
componentRendingStack.pop();
|
|
255
274
|
return template;
|
|
256
275
|
}
|
|
@@ -408,7 +427,7 @@ function onDestroy(callback) {
|
|
|
408
427
|
class Ref {
|
|
409
428
|
constructor(callback) {
|
|
410
429
|
this.callback = callback;
|
|
411
|
-
this.unBindMap = new WeakMap;
|
|
430
|
+
this.unBindMap = new WeakMap();
|
|
412
431
|
this.targetCaches = new Set();
|
|
413
432
|
}
|
|
414
433
|
bind(value) {
|
|
@@ -418,15 +437,16 @@ class Ref {
|
|
|
418
437
|
if (this.targetCaches.has(value)) {
|
|
419
438
|
return;
|
|
420
439
|
}
|
|
421
|
-
this.targetCaches.add(value);
|
|
422
440
|
const unBindFn = this.callback(value);
|
|
423
441
|
if (typeof unBindFn === 'function') {
|
|
424
442
|
this.unBindMap.set(value, unBindFn);
|
|
425
443
|
}
|
|
444
|
+
this.targetCaches.add(value);
|
|
426
445
|
}
|
|
427
446
|
unBind(value) {
|
|
428
447
|
this.targetCaches.delete(value);
|
|
429
448
|
const unBindFn = this.unBindMap.get(value);
|
|
449
|
+
this.unBindMap.delete(value);
|
|
430
450
|
if (typeof unBindFn === 'function') {
|
|
431
451
|
unBindFn();
|
|
432
452
|
}
|
|
@@ -482,8 +502,12 @@ const depsKey = Symbol('deps');
|
|
|
482
502
|
*/
|
|
483
503
|
function useSignal(state) {
|
|
484
504
|
const usedComponents = new Set();
|
|
485
|
-
function
|
|
505
|
+
function signal() {
|
|
486
506
|
const component = getRendingContext();
|
|
507
|
+
const derivedContext = getDerivedContext();
|
|
508
|
+
if (derivedContext) {
|
|
509
|
+
derivedContext.push(signal);
|
|
510
|
+
}
|
|
487
511
|
if (component && !usedComponents.has(component)) {
|
|
488
512
|
usedComponents.add(component);
|
|
489
513
|
component.destroyCallbacks.push(() => {
|
|
@@ -492,7 +516,7 @@ function useSignal(state) {
|
|
|
492
516
|
}
|
|
493
517
|
return state;
|
|
494
518
|
}
|
|
495
|
-
|
|
519
|
+
signal.set = function (newState) {
|
|
496
520
|
if (newState === state) {
|
|
497
521
|
return;
|
|
498
522
|
}
|
|
@@ -500,28 +524,54 @@ function useSignal(state) {
|
|
|
500
524
|
for (const component of usedComponents) {
|
|
501
525
|
component.markAsDirtied();
|
|
502
526
|
}
|
|
503
|
-
for (const fn of
|
|
527
|
+
for (const fn of signal[depsKey]) {
|
|
504
528
|
fn();
|
|
505
529
|
}
|
|
506
530
|
};
|
|
507
|
-
|
|
508
|
-
return
|
|
531
|
+
signal[depsKey] = new Set();
|
|
532
|
+
return signal;
|
|
509
533
|
}
|
|
510
534
|
/**
|
|
511
|
-
*
|
|
512
|
-
*
|
|
513
|
-
*
|
|
514
|
-
* @param
|
|
515
|
-
* @param
|
|
535
|
+
* 使用派生值,Viewfly 会收集回调函数内同步执行时访问的 Signal,
|
|
536
|
+
* 并在你获取 useDerived 函数返回的 Signal 的值时,自动计算最新的值。
|
|
537
|
+
*
|
|
538
|
+
* @param callback
|
|
539
|
+
* @param isContinue 可选的停止函数,在每次值更新后调用,当返回值为 false 时,将不再监听依赖的变化
|
|
516
540
|
*/
|
|
541
|
+
function useDerived(callback, isContinue) {
|
|
542
|
+
const deps = [];
|
|
543
|
+
derivedStack.push(deps);
|
|
544
|
+
const data = callback();
|
|
545
|
+
derivedStack.pop();
|
|
546
|
+
const signal = useSignal(data);
|
|
547
|
+
if (deps.length) {
|
|
548
|
+
const unListen = useEffect(deps, () => {
|
|
549
|
+
const data = callback();
|
|
550
|
+
signal.set(data);
|
|
551
|
+
if (typeof isContinue === 'function' && !isContinue(data)) {
|
|
552
|
+
unListen();
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
return signal;
|
|
557
|
+
}
|
|
558
|
+
/* eslint-enable max-len*/
|
|
517
559
|
function useEffect(deps, effect) {
|
|
560
|
+
if (typeof deps === 'function' &&
|
|
561
|
+
typeof deps.set === 'undefined' &&
|
|
562
|
+
typeof deps[depsKey] === 'undefined') {
|
|
563
|
+
deps = useDerived(deps);
|
|
564
|
+
}
|
|
518
565
|
const signals = Array.isArray(deps) ? deps : [deps];
|
|
566
|
+
let oldValues = signals.map(s => s());
|
|
519
567
|
let prevCleanup;
|
|
520
568
|
function effectCallback() {
|
|
521
569
|
if (typeof prevCleanup === 'function') {
|
|
522
570
|
prevCleanup();
|
|
523
571
|
}
|
|
524
|
-
|
|
572
|
+
const newValues = signals.map(s => s());
|
|
573
|
+
prevCleanup = Array.isArray(deps) ? effect(newValues, oldValues) : effect(newValues[0], oldValues[0]);
|
|
574
|
+
oldValues = newValues;
|
|
525
575
|
}
|
|
526
576
|
for (const dep of signals) {
|
|
527
577
|
dep[depsKey].add(effectCallback);
|
|
@@ -567,8 +617,8 @@ function inject(token, notFoundValue, flags) {
|
|
|
567
617
|
* Viewfly 根组件,用于实现组件状态更新事件通知
|
|
568
618
|
*/
|
|
569
619
|
class RootComponent extends Component {
|
|
570
|
-
constructor(factory) {
|
|
571
|
-
super(
|
|
620
|
+
constructor(factory, parentInjector = new NullInjector()) {
|
|
621
|
+
super(parentInjector, factory, null);
|
|
572
622
|
this.changeEmitter = new Subject();
|
|
573
623
|
}
|
|
574
624
|
markAsChanged() {
|
|
@@ -756,6 +806,37 @@ let Renderer = class Renderer {
|
|
|
756
806
|
const atom = this.componentAtomCaches.get(component).atom.child;
|
|
757
807
|
this.reconcileElement(atom, context);
|
|
758
808
|
}
|
|
809
|
+
else {
|
|
810
|
+
const prevSibling = this.getPrevSibling(component);
|
|
811
|
+
if (prevSibling) {
|
|
812
|
+
context.isParent = false;
|
|
813
|
+
context.host = prevSibling;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
getPrevSibling(component) {
|
|
818
|
+
let atom = this.componentAtomCaches.get(component).atom.child;
|
|
819
|
+
const childAtoms = [];
|
|
820
|
+
while (atom) {
|
|
821
|
+
childAtoms.push(atom);
|
|
822
|
+
atom = atom.sibling;
|
|
823
|
+
}
|
|
824
|
+
const components = [];
|
|
825
|
+
while (childAtoms.length) {
|
|
826
|
+
const last = childAtoms.pop();
|
|
827
|
+
if (last.jsxNode instanceof Component) {
|
|
828
|
+
components.push(last.jsxNode);
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
return last.nativeNode;
|
|
832
|
+
}
|
|
833
|
+
for (const component of components) {
|
|
834
|
+
const nativeNode = this.getPrevSibling(component);
|
|
835
|
+
if (nativeNode) {
|
|
836
|
+
return nativeNode;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
return null;
|
|
759
840
|
}
|
|
760
841
|
reconcileElement(atom, context) {
|
|
761
842
|
while (atom) {
|
|
@@ -1178,7 +1259,7 @@ class Viewfly extends ReflectiveInjector {
|
|
|
1178
1259
|
/**
|
|
1179
1260
|
* 启动 Viewfly
|
|
1180
1261
|
*/
|
|
1181
|
-
|
|
1262
|
+
run() {
|
|
1182
1263
|
const renderer = this.get(Renderer);
|
|
1183
1264
|
renderer.render();
|
|
1184
1265
|
if (this.config.autoUpdate === false) {
|
|
@@ -1203,8 +1284,8 @@ class Viewfly extends ReflectiveInjector {
|
|
|
1203
1284
|
return () => {
|
|
1204
1285
|
return this.destroyed ? null : rootNode;
|
|
1205
1286
|
};
|
|
1206
|
-
});
|
|
1287
|
+
}, this.config.context);
|
|
1207
1288
|
}
|
|
1208
1289
|
}
|
|
1209
1290
|
|
|
1210
|
-
export { Component, Fragment, JSXComponent, JSXElement, JSXText, NativeRenderer, Props, Ref, Renderer, RootComponent, RootComponentRef, Viewfly, inject, jsx, jsxs, onDestroy, onMount, onPropsChanged, onUpdated, provide, useEffect, useRef, useSignal };
|
|
1291
|
+
export { Component, Fragment, JSXComponent, JSXElement, JSXText, NativeRenderer, Props, Ref, Renderer, RootComponent, RootComponentRef, Viewfly, inject, jsx, jsxs, makeError, onDestroy, onMount, onPropsChanged, onUpdated, provide, useDerived, useEffect, useRef, useSignal };
|
package/bundles/index.js
CHANGED
|
@@ -4,6 +4,15 @@ require('reflect-metadata');
|
|
|
4
4
|
var di = require('@tanbo/di');
|
|
5
5
|
var stream = require('@tanbo/stream');
|
|
6
6
|
|
|
7
|
+
function makeError(name) {
|
|
8
|
+
return function viewflyError(message) {
|
|
9
|
+
const error = new Error(message);
|
|
10
|
+
error.name = `[ViewflyError: ${name}]`;
|
|
11
|
+
error.stack = error.stack.replace(/\n.*?(?=\n)/, '');
|
|
12
|
+
return error;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
7
16
|
class NativeRenderer {
|
|
8
17
|
}
|
|
9
18
|
|
|
@@ -35,15 +44,6 @@ function __metadata(metadataKey, metadataValue) {
|
|
|
35
44
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
|
|
36
45
|
}
|
|
37
46
|
|
|
38
|
-
function makeError(name) {
|
|
39
|
-
return function viewflyError(message) {
|
|
40
|
-
const error = new Error(message);
|
|
41
|
-
error.name = `[ViewflyError: ${name}]`;
|
|
42
|
-
error.stack = error.stack.replace(/\n.*?(?=\n)/, '');
|
|
43
|
-
return error;
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
47
|
const jsxErrorFn = makeError('JSX');
|
|
48
48
|
const Fragment = function Fragment() {
|
|
49
49
|
throw jsxErrorFn('Fragment does not support calling.');
|
|
@@ -181,10 +181,13 @@ class JSXElement {
|
|
|
181
181
|
|
|
182
182
|
const componentSetupStack = [];
|
|
183
183
|
const componentRendingStack = [];
|
|
184
|
+
const derivedStack = [];
|
|
184
185
|
const componentErrorFn = makeError('component');
|
|
185
186
|
function getSetupContext(need = true) {
|
|
186
187
|
const current = componentSetupStack[componentSetupStack.length - 1];
|
|
187
188
|
if (!current && need) {
|
|
189
|
+
// 防止因外部捕获异常引引起的缓存未清理的问题
|
|
190
|
+
componentRendingStack.pop();
|
|
188
191
|
throw componentErrorFn('cannot be called outside the component!');
|
|
189
192
|
}
|
|
190
193
|
return current;
|
|
@@ -192,6 +195,9 @@ function getSetupContext(need = true) {
|
|
|
192
195
|
function getRendingContext() {
|
|
193
196
|
return componentRendingStack[componentRendingStack.length - 1];
|
|
194
197
|
}
|
|
198
|
+
function getDerivedContext() {
|
|
199
|
+
return derivedStack[derivedStack.length - 1];
|
|
200
|
+
}
|
|
195
201
|
class JSXComponent {
|
|
196
202
|
constructor(createInstance) {
|
|
197
203
|
this.createInstance = createInstance;
|
|
@@ -238,20 +244,33 @@ class Component extends di.ReflectiveInjector {
|
|
|
238
244
|
}
|
|
239
245
|
},
|
|
240
246
|
set() {
|
|
247
|
+
// 防止因外部捕获异常引引起的缓存未清理的问题
|
|
248
|
+
if (isSetup) {
|
|
249
|
+
componentSetupStack.pop();
|
|
250
|
+
}
|
|
251
|
+
if (isRending) {
|
|
252
|
+
componentRendingStack.pop();
|
|
253
|
+
}
|
|
241
254
|
throw componentErrorFn('component props is readonly!');
|
|
242
255
|
}
|
|
243
256
|
});
|
|
244
257
|
componentSetupStack.push(this);
|
|
258
|
+
let isSetup = true;
|
|
245
259
|
const render = this.setup(props);
|
|
260
|
+
isSetup = false;
|
|
246
261
|
componentSetupStack.pop();
|
|
247
262
|
componentRendingStack.push(this);
|
|
263
|
+
let isRending = true;
|
|
248
264
|
const template = render();
|
|
265
|
+
isRending = false;
|
|
249
266
|
componentRendingStack.pop();
|
|
250
267
|
return {
|
|
251
268
|
template,
|
|
252
269
|
render: () => {
|
|
253
270
|
componentRendingStack.push(this);
|
|
271
|
+
isRending = true;
|
|
254
272
|
const template = render();
|
|
273
|
+
isRending = false;
|
|
255
274
|
componentRendingStack.pop();
|
|
256
275
|
return template;
|
|
257
276
|
}
|
|
@@ -409,7 +428,7 @@ function onDestroy(callback) {
|
|
|
409
428
|
class Ref {
|
|
410
429
|
constructor(callback) {
|
|
411
430
|
this.callback = callback;
|
|
412
|
-
this.unBindMap = new WeakMap;
|
|
431
|
+
this.unBindMap = new WeakMap();
|
|
413
432
|
this.targetCaches = new Set();
|
|
414
433
|
}
|
|
415
434
|
bind(value) {
|
|
@@ -419,15 +438,16 @@ class Ref {
|
|
|
419
438
|
if (this.targetCaches.has(value)) {
|
|
420
439
|
return;
|
|
421
440
|
}
|
|
422
|
-
this.targetCaches.add(value);
|
|
423
441
|
const unBindFn = this.callback(value);
|
|
424
442
|
if (typeof unBindFn === 'function') {
|
|
425
443
|
this.unBindMap.set(value, unBindFn);
|
|
426
444
|
}
|
|
445
|
+
this.targetCaches.add(value);
|
|
427
446
|
}
|
|
428
447
|
unBind(value) {
|
|
429
448
|
this.targetCaches.delete(value);
|
|
430
449
|
const unBindFn = this.unBindMap.get(value);
|
|
450
|
+
this.unBindMap.delete(value);
|
|
431
451
|
if (typeof unBindFn === 'function') {
|
|
432
452
|
unBindFn();
|
|
433
453
|
}
|
|
@@ -483,8 +503,12 @@ const depsKey = Symbol('deps');
|
|
|
483
503
|
*/
|
|
484
504
|
function useSignal(state) {
|
|
485
505
|
const usedComponents = new Set();
|
|
486
|
-
function
|
|
506
|
+
function signal() {
|
|
487
507
|
const component = getRendingContext();
|
|
508
|
+
const derivedContext = getDerivedContext();
|
|
509
|
+
if (derivedContext) {
|
|
510
|
+
derivedContext.push(signal);
|
|
511
|
+
}
|
|
488
512
|
if (component && !usedComponents.has(component)) {
|
|
489
513
|
usedComponents.add(component);
|
|
490
514
|
component.destroyCallbacks.push(() => {
|
|
@@ -493,7 +517,7 @@ function useSignal(state) {
|
|
|
493
517
|
}
|
|
494
518
|
return state;
|
|
495
519
|
}
|
|
496
|
-
|
|
520
|
+
signal.set = function (newState) {
|
|
497
521
|
if (newState === state) {
|
|
498
522
|
return;
|
|
499
523
|
}
|
|
@@ -501,28 +525,54 @@ function useSignal(state) {
|
|
|
501
525
|
for (const component of usedComponents) {
|
|
502
526
|
component.markAsDirtied();
|
|
503
527
|
}
|
|
504
|
-
for (const fn of
|
|
528
|
+
for (const fn of signal[depsKey]) {
|
|
505
529
|
fn();
|
|
506
530
|
}
|
|
507
531
|
};
|
|
508
|
-
|
|
509
|
-
return
|
|
532
|
+
signal[depsKey] = new Set();
|
|
533
|
+
return signal;
|
|
510
534
|
}
|
|
511
535
|
/**
|
|
512
|
-
*
|
|
513
|
-
*
|
|
514
|
-
*
|
|
515
|
-
* @param
|
|
516
|
-
* @param
|
|
536
|
+
* 使用派生值,Viewfly 会收集回调函数内同步执行时访问的 Signal,
|
|
537
|
+
* 并在你获取 useDerived 函数返回的 Signal 的值时,自动计算最新的值。
|
|
538
|
+
*
|
|
539
|
+
* @param callback
|
|
540
|
+
* @param isContinue 可选的停止函数,在每次值更新后调用,当返回值为 false 时,将不再监听依赖的变化
|
|
517
541
|
*/
|
|
542
|
+
function useDerived(callback, isContinue) {
|
|
543
|
+
const deps = [];
|
|
544
|
+
derivedStack.push(deps);
|
|
545
|
+
const data = callback();
|
|
546
|
+
derivedStack.pop();
|
|
547
|
+
const signal = useSignal(data);
|
|
548
|
+
if (deps.length) {
|
|
549
|
+
const unListen = useEffect(deps, () => {
|
|
550
|
+
const data = callback();
|
|
551
|
+
signal.set(data);
|
|
552
|
+
if (typeof isContinue === 'function' && !isContinue(data)) {
|
|
553
|
+
unListen();
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
return signal;
|
|
558
|
+
}
|
|
559
|
+
/* eslint-enable max-len*/
|
|
518
560
|
function useEffect(deps, effect) {
|
|
561
|
+
if (typeof deps === 'function' &&
|
|
562
|
+
typeof deps.set === 'undefined' &&
|
|
563
|
+
typeof deps[depsKey] === 'undefined') {
|
|
564
|
+
deps = useDerived(deps);
|
|
565
|
+
}
|
|
519
566
|
const signals = Array.isArray(deps) ? deps : [deps];
|
|
567
|
+
let oldValues = signals.map(s => s());
|
|
520
568
|
let prevCleanup;
|
|
521
569
|
function effectCallback() {
|
|
522
570
|
if (typeof prevCleanup === 'function') {
|
|
523
571
|
prevCleanup();
|
|
524
572
|
}
|
|
525
|
-
|
|
573
|
+
const newValues = signals.map(s => s());
|
|
574
|
+
prevCleanup = Array.isArray(deps) ? effect(newValues, oldValues) : effect(newValues[0], oldValues[0]);
|
|
575
|
+
oldValues = newValues;
|
|
526
576
|
}
|
|
527
577
|
for (const dep of signals) {
|
|
528
578
|
dep[depsKey].add(effectCallback);
|
|
@@ -568,8 +618,8 @@ function inject(token, notFoundValue, flags) {
|
|
|
568
618
|
* Viewfly 根组件,用于实现组件状态更新事件通知
|
|
569
619
|
*/
|
|
570
620
|
class RootComponent extends Component {
|
|
571
|
-
constructor(factory) {
|
|
572
|
-
super(
|
|
621
|
+
constructor(factory, parentInjector = new di.NullInjector()) {
|
|
622
|
+
super(parentInjector, factory, null);
|
|
573
623
|
this.changeEmitter = new stream.Subject();
|
|
574
624
|
}
|
|
575
625
|
markAsChanged() {
|
|
@@ -757,6 +807,37 @@ exports.Renderer = class Renderer {
|
|
|
757
807
|
const atom = this.componentAtomCaches.get(component).atom.child;
|
|
758
808
|
this.reconcileElement(atom, context);
|
|
759
809
|
}
|
|
810
|
+
else {
|
|
811
|
+
const prevSibling = this.getPrevSibling(component);
|
|
812
|
+
if (prevSibling) {
|
|
813
|
+
context.isParent = false;
|
|
814
|
+
context.host = prevSibling;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
getPrevSibling(component) {
|
|
819
|
+
let atom = this.componentAtomCaches.get(component).atom.child;
|
|
820
|
+
const childAtoms = [];
|
|
821
|
+
while (atom) {
|
|
822
|
+
childAtoms.push(atom);
|
|
823
|
+
atom = atom.sibling;
|
|
824
|
+
}
|
|
825
|
+
const components = [];
|
|
826
|
+
while (childAtoms.length) {
|
|
827
|
+
const last = childAtoms.pop();
|
|
828
|
+
if (last.jsxNode instanceof Component) {
|
|
829
|
+
components.push(last.jsxNode);
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
return last.nativeNode;
|
|
833
|
+
}
|
|
834
|
+
for (const component of components) {
|
|
835
|
+
const nativeNode = this.getPrevSibling(component);
|
|
836
|
+
if (nativeNode) {
|
|
837
|
+
return nativeNode;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
return null;
|
|
760
841
|
}
|
|
761
842
|
reconcileElement(atom, context) {
|
|
762
843
|
while (atom) {
|
|
@@ -1179,7 +1260,7 @@ class Viewfly extends di.ReflectiveInjector {
|
|
|
1179
1260
|
/**
|
|
1180
1261
|
* 启动 Viewfly
|
|
1181
1262
|
*/
|
|
1182
|
-
|
|
1263
|
+
run() {
|
|
1183
1264
|
const renderer = this.get(exports.Renderer);
|
|
1184
1265
|
renderer.render();
|
|
1185
1266
|
if (this.config.autoUpdate === false) {
|
|
@@ -1204,7 +1285,7 @@ class Viewfly extends di.ReflectiveInjector {
|
|
|
1204
1285
|
return () => {
|
|
1205
1286
|
return this.destroyed ? null : rootNode;
|
|
1206
1287
|
};
|
|
1207
|
-
});
|
|
1288
|
+
}, this.config.context);
|
|
1208
1289
|
}
|
|
1209
1290
|
}
|
|
1210
1291
|
|
|
@@ -1222,11 +1303,13 @@ exports.Viewfly = Viewfly;
|
|
|
1222
1303
|
exports.inject = inject;
|
|
1223
1304
|
exports.jsx = jsx;
|
|
1224
1305
|
exports.jsxs = jsxs;
|
|
1306
|
+
exports.makeError = makeError;
|
|
1225
1307
|
exports.onDestroy = onDestroy;
|
|
1226
1308
|
exports.onMount = onMount;
|
|
1227
1309
|
exports.onPropsChanged = onPropsChanged;
|
|
1228
1310
|
exports.onUpdated = onUpdated;
|
|
1229
1311
|
exports.provide = provide;
|
|
1312
|
+
exports.useDerived = useDerived;
|
|
1230
1313
|
exports.useEffect = useEffect;
|
|
1231
1314
|
exports.useRef = useRef;
|
|
1232
1315
|
exports.useSignal = useSignal;
|
|
@@ -5,15 +5,15 @@ export declare class JSXComponent {
|
|
|
5
5
|
constructor(createInstance: (injector: Component) => Component);
|
|
6
6
|
}
|
|
7
7
|
export type JSXTemplate = JSXElement | JSXComponent | null | void;
|
|
8
|
-
export interface ComponentSetup {
|
|
9
|
-
(props?:
|
|
8
|
+
export interface ComponentSetup<T extends JSXProps<any> = JSXProps<any>> {
|
|
9
|
+
(props?: T): () => JSXTemplate;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* Viewfly 组件管理类,用于管理组件的生命周期,上下文等
|
|
13
13
|
*/
|
|
14
14
|
export declare class Component extends ReflectiveInjector {
|
|
15
15
|
setup: ComponentSetup;
|
|
16
|
-
config
|
|
16
|
+
config?: JSXProps<any> | null | undefined;
|
|
17
17
|
destroyCallbacks: LifeCycleCallback[];
|
|
18
18
|
mountCallbacks: LifeCycleCallback[];
|
|
19
19
|
propsChangedCallbacks: PropsChangedCallback<any>[];
|
|
@@ -27,7 +27,7 @@ export declare class Component extends ReflectiveInjector {
|
|
|
27
27
|
private updatedDestroyCallbacks;
|
|
28
28
|
private propsChangedDestroyCallbacks;
|
|
29
29
|
private isFirstRending;
|
|
30
|
-
constructor(context: Injector, setup: ComponentSetup, config
|
|
30
|
+
constructor(context: Injector, setup: ComponentSetup, config?: JSXProps<any> | null | undefined);
|
|
31
31
|
addProvide<T>(providers: Provider<T> | Provider<T>[]): void;
|
|
32
32
|
init(): {
|
|
33
33
|
template: JSXTemplate;
|
|
@@ -36,7 +36,7 @@ export declare class Component extends ReflectiveInjector {
|
|
|
36
36
|
markAsDirtied(): void;
|
|
37
37
|
markAsChanged(): void;
|
|
38
38
|
rendered(): void;
|
|
39
|
-
invokePropsChangedHooks(newProps
|
|
39
|
+
invokePropsChangedHooks(newProps?: JSXProps<any> | null): void;
|
|
40
40
|
destroy(): void;
|
|
41
41
|
private invokeMountHooks;
|
|
42
42
|
private invokeUpdatedHooks;
|
|
@@ -175,14 +175,35 @@ export interface Signal<T> {
|
|
|
175
175
|
* }
|
|
176
176
|
*/
|
|
177
177
|
export declare function useSignal<T>(state: T): Signal<T>;
|
|
178
|
+
/**
|
|
179
|
+
* 使用派生值,Viewfly 会收集回调函数内同步执行时访问的 Signal,
|
|
180
|
+
* 并在你获取 useDerived 函数返回的 Signal 的值时,自动计算最新的值。
|
|
181
|
+
*
|
|
182
|
+
* @param callback
|
|
183
|
+
* @param isContinue 可选的停止函数,在每次值更新后调用,当返回值为 false 时,将不再监听依赖的变化
|
|
184
|
+
*/
|
|
185
|
+
export declare function useDerived<T>(callback: () => T, isContinue?: (data: T) => unknown): Signal<T>;
|
|
186
|
+
export interface EffectCallback<T, U> {
|
|
187
|
+
(newValue: T, oldValue: U): void | (() => void);
|
|
188
|
+
}
|
|
178
189
|
/**
|
|
179
190
|
* 监听状态变化,当任意一个状态发生变更时,触发回调。
|
|
180
191
|
* useEffect 会返回一个取消监听的函数,调用此函数,可以取消监听。
|
|
181
192
|
* 当在组件中调用时,组件销毁时会自动取消监听。
|
|
182
|
-
* @param deps 依赖的状态 Signal,可以是一个 Signal,只可以一个数包含 Signal
|
|
193
|
+
* @param deps 依赖的状态 Signal,可以是一个 Signal,只可以一个数包含 Signal 的数组,或者是一个求值函数
|
|
183
194
|
* @param effect 状态变更后的回调函数
|
|
184
195
|
*/
|
|
185
|
-
export declare function useEffect(deps: Signal<
|
|
196
|
+
export declare function useEffect<T>(deps: Signal<T>, effect: EffectCallback<T, T>): () => void;
|
|
197
|
+
export declare function useEffect<T>(deps: [Signal<T>], effect: EffectCallback<[T], [T]>): () => void;
|
|
198
|
+
export declare function useEffect<T, T1>(deps: [Signal<T>, Signal<T1>], effect: EffectCallback<[T, T1], [T, T1]>): () => void;
|
|
199
|
+
export declare function useEffect<T, T1, T2>(deps: [Signal<T>, Signal<T1>, Signal<T2>], effect: EffectCallback<[T, T1, T2], [T, T1, T2]>): () => void;
|
|
200
|
+
export declare function useEffect<T, T1, T2, T3>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>], effect: EffectCallback<[T, T1, T2, T3], [T, T1, T2, T3]>): () => void;
|
|
201
|
+
export declare function useEffect<T, T1, T2, T3, T4>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>, Signal<T4>], effect: EffectCallback<[T, T1, T2, T3, T4], [T, T1, T2, T3, T4]>): () => void;
|
|
202
|
+
export declare function useEffect<T, T1, T2, T3, T4, T5>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>, Signal<T4>, Signal<T5>], effect: EffectCallback<[T, T1, T2, T3, T4, T5], [T, T1, T2, T3, T4, T5]>): () => void;
|
|
203
|
+
export declare function useEffect<T, T1, T2, T3, T4, T5, T6>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>, Signal<T4>, Signal<T5>, Signal<T6>], effect: EffectCallback<[T, T1, T2, T3, T4, T5, T6], [T, T1, T2, T3, T4, T5, T6]>): () => void;
|
|
204
|
+
export declare function useEffect<T, T1, T2, T3, T4, T5, T6, T7>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>, Signal<T4>, Signal<T5>, Signal<T6>, Signal<T7>], effect: EffectCallback<[T, T1, T2, T3, T4, T5, T6, T7], [T, T1, T2, T3, T4, T5, T6, T7]>): () => void;
|
|
205
|
+
export declare function useEffect<T>(deps: () => T, effect: EffectCallback<T, T>): () => void;
|
|
206
|
+
export declare function useEffect<T = any>(deps: Signal<any>[], effect: EffectCallback<T[], T[]>): () => void;
|
|
186
207
|
/**
|
|
187
208
|
* 通过 IoC 容器当前组件提供上下文共享数据的方法
|
|
188
209
|
* @param provider
|
|
@@ -6,10 +6,10 @@ export interface JSXProps<T = JSXChildNode | JSXChildNode[]> {
|
|
|
6
6
|
[key: symbol]: any;
|
|
7
7
|
}
|
|
8
8
|
export declare const Fragment: () => never;
|
|
9
|
-
export declare function jsx<T extends JSXChildNode>(name: string, config
|
|
10
|
-
export declare function jsx<T extends JSXChildNode>(setup: ComponentSetup, config
|
|
11
|
-
export declare function jsxs<T extends JSXChildNode[]>(name: string, config
|
|
12
|
-
export declare function jsxs<T extends JSXChildNode[]>(setup: ComponentSetup, config
|
|
9
|
+
export declare function jsx<T extends JSXChildNode>(name: string, config?: JSXProps<T> | null): JSXElement;
|
|
10
|
+
export declare function jsx<T extends JSXChildNode>(setup: ComponentSetup, config?: JSXProps<T> | null): JSXComponent;
|
|
11
|
+
export declare function jsxs<T extends JSXChildNode[]>(name: string, config?: JSXProps<T> | null): JSXElement;
|
|
12
|
+
export declare function jsxs<T extends JSXChildNode[]>(setup: ComponentSetup, config?: JSXProps<T> | null): JSXComponent;
|
|
13
13
|
export interface VElementListeners {
|
|
14
14
|
[listenKey: string]: <T extends Event>(ev: T) => any;
|
|
15
15
|
}
|
|
@@ -24,12 +24,12 @@ export declare class Props {
|
|
|
24
24
|
classes: Set<string>;
|
|
25
25
|
listeners: VElementListeners;
|
|
26
26
|
children: VNode[];
|
|
27
|
-
constructor(props
|
|
27
|
+
constructor(props?: JSXProps<JSXChildNode> | JSXProps<JSXChildNode[]> | null);
|
|
28
28
|
static classToArray(config: unknown): string[];
|
|
29
29
|
}
|
|
30
30
|
export declare class JSXElement {
|
|
31
31
|
name: string;
|
|
32
|
-
config
|
|
32
|
+
config?: JSXProps<any> | null | undefined;
|
|
33
33
|
props: Props;
|
|
34
|
-
constructor(name: string, config
|
|
34
|
+
constructor(name: string, config?: JSXProps<any> | null | undefined);
|
|
35
35
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Subject } from '@tanbo/stream';
|
|
2
|
+
import { NullInjector } from '@tanbo/di';
|
|
2
3
|
import { Component, ComponentSetup } from './component';
|
|
3
4
|
/**
|
|
4
5
|
* Viewfly 根组件,用于实现组件状态更新事件通知
|
|
5
6
|
*/
|
|
6
7
|
export declare class RootComponent extends Component {
|
|
7
8
|
changeEmitter: Subject<void>;
|
|
8
|
-
constructor(factory: ComponentSetup);
|
|
9
|
+
constructor(factory: ComponentSetup, parentInjector?: NullInjector);
|
|
9
10
|
markAsChanged(): void;
|
|
10
11
|
}
|
package/bundles/public-api.d.ts
CHANGED
package/bundles/viewfly.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Provider, ReflectiveInjector } from '@tanbo/di';
|
|
1
|
+
import { Injector, Provider, ReflectiveInjector } from '@tanbo/di';
|
|
2
2
|
import { NativeNode } from './foundation/_api';
|
|
3
3
|
import { JSXComponent, JSXElement } from './model/_api';
|
|
4
4
|
export type RootNode = JSXElement | JSXComponent;
|
|
@@ -14,6 +14,8 @@ export interface Config {
|
|
|
14
14
|
autoUpdate?: boolean;
|
|
15
15
|
/** 根节点 */
|
|
16
16
|
root: RootNode;
|
|
17
|
+
/** 根组件的上下文 */
|
|
18
|
+
context?: Injector;
|
|
17
19
|
}
|
|
18
20
|
/**
|
|
19
21
|
* Viewfly 核心类,用于启动一个 Viewfly 应用
|
|
@@ -27,7 +29,7 @@ export declare class Viewfly extends ReflectiveInjector {
|
|
|
27
29
|
/**
|
|
28
30
|
* 启动 Viewfly
|
|
29
31
|
*/
|
|
30
|
-
|
|
32
|
+
run(): void;
|
|
31
33
|
/**
|
|
32
34
|
* 销毁 Viewfly 实例
|
|
33
35
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viewfly/core",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.5",
|
|
4
4
|
"description": "Viewfly is a simple and easy-to-use JavaScript framework with an intuitive development experience.",
|
|
5
5
|
"main": "./bundles/index.js",
|
|
6
6
|
"module": "./bundles/index.esm.js",
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"bugs": {
|
|
38
38
|
"url": "https://github.com/viewfly/viewfly.git/issues"
|
|
39
39
|
},
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "135aeda546b83c7947e888dfe40860858123b6fc"
|
|
41
41
|
}
|