@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.
@@ -12,6 +12,7 @@ export declare class Renderer {
12
12
  render(): void;
13
13
  refresh(): void;
14
14
  private reconcile;
15
+ private getPrevSibling;
15
16
  private reconcileElement;
16
17
  private applyChanges;
17
18
  private diff;
@@ -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 stateManager() {
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
- stateManager.set = function (newState) {
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 stateManager[depsKey]) {
527
+ for (const fn of signal[depsKey]) {
504
528
  fn();
505
529
  }
506
530
  };
507
- stateManager[depsKey] = new Set();
508
- return stateManager;
531
+ signal[depsKey] = new Set();
532
+ return signal;
509
533
  }
510
534
  /**
511
- * 监听状态变化,当任意一个状态发生变更时,触发回调。
512
- * useEffect 会返回一个取消监听的函数,调用此函数,可以取消监听。
513
- * 当在组件中调用时,组件销毁时会自动取消监听。
514
- * @param deps 依赖的状态 Signal,可以是一个 Signal,只可以一个数包含 Signal 的数组
515
- * @param effect 状态变更后的回调函数
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
- prevCleanup = effect();
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(new NullInjector(), factory, null);
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
- start() {
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 stateManager() {
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
- stateManager.set = function (newState) {
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 stateManager[depsKey]) {
528
+ for (const fn of signal[depsKey]) {
505
529
  fn();
506
530
  }
507
531
  };
508
- stateManager[depsKey] = new Set();
509
- return stateManager;
532
+ signal[depsKey] = new Set();
533
+ return signal;
510
534
  }
511
535
  /**
512
- * 监听状态变化,当任意一个状态发生变更时,触发回调。
513
- * useEffect 会返回一个取消监听的函数,调用此函数,可以取消监听。
514
- * 当在组件中调用时,组件销毁时会自动取消监听。
515
- * @param deps 依赖的状态 Signal,可以是一个 Signal,只可以一个数包含 Signal 的数组
516
- * @param effect 状态变更后的回调函数
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
- prevCleanup = effect();
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(new di.NullInjector(), factory, null);
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
- start() {
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?: JSXProps<any>): () => JSXTemplate;
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: JSXProps<any> | null;
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: JSXProps<any> | null);
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: JSXProps<any> | null): void;
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<any> | Signal<any>[], effect: LifeCycleCallback): () => void;
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: 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;
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: JSXProps<JSXChildNode> | JSXProps<JSXChildNode[]> | null);
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: JSXProps<any> | null;
32
+ config?: JSXProps<any> | null | undefined;
33
33
  props: Props;
34
- constructor(name: string, config: JSXProps<any> | null);
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
  }
@@ -1,5 +1,6 @@
1
1
  import 'reflect-metadata';
2
2
  export * from '@tanbo/di';
3
+ export * from './_utils/make-error';
3
4
  export * from './foundation/_api';
4
5
  export * from './model/_api';
5
6
  export * from './viewfly';
@@ -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
- start(): void;
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",
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": "e0795c315c3b3e1df2e3d2d9f823843b91838ff6"
40
+ "gitHead": "135aeda546b83c7947e888dfe40860858123b6fc"
41
41
  }