@viewfly/core 0.0.3 → 0.0.4

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.
@@ -30,4 +30,5 @@ export declare class Renderer {
30
30
  private createTextNode;
31
31
  private updateNativeNodeProperties;
32
32
  private applyRefs;
33
+ private bindEvent;
33
34
  }
@@ -383,13 +383,25 @@ function useSignal(state) {
383
383
  return;
384
384
  }
385
385
  state = newState;
386
- for (const fn of signal[depsKey]) {
386
+ const depCallbacks = Array.from(signal[depsKey]);
387
+ for (const fn of depCallbacks) {
388
+ // 回调中可能会对依赖做出修改,故需先缓存起来
387
389
  fn();
388
390
  }
389
391
  };
390
392
  signal[depsKey] = new Set();
391
393
  return signal;
392
394
  }
395
+ function invokeDepFn(fn) {
396
+ const deps = [];
397
+ signalDepsStack.push(deps);
398
+ const data = fn();
399
+ signalDepsStack.pop();
400
+ return {
401
+ deps,
402
+ data
403
+ };
404
+ }
393
405
  /**
394
406
  * 使用派生值,Viewfly 会收集回调函数内同步执行时访问的 Signal,
395
407
  * 并在你获取 useDerived 函数返回的 Signal 的值时,自动计算最新的值。
@@ -398,18 +410,32 @@ function useSignal(state) {
398
410
  * @param isContinue 可选的停止函数,在每次值更新后调用,当返回值为 false 时,将不再监听依赖的变化
399
411
  */
400
412
  function useDerived(callback, isContinue) {
401
- const deps = [];
402
- signalDepsStack.push(deps);
403
- const data = callback();
404
- signalDepsStack.pop();
413
+ let { data, deps } = invokeDepFn(callback);
405
414
  const signal = useSignal(data);
406
- if (deps.length) {
407
- const unListen = useEffect(deps, () => {
408
- const data = callback();
409
- signal.set(data);
410
- if (typeof isContinue === 'function' && !isContinue(data)) {
411
- unListen();
415
+ const component = getSetupContext(false);
416
+ const unListenRef = {};
417
+ function listen(model, deps, callback, unListenRef, isContinue) {
418
+ const nextListen = () => {
419
+ unListenRef.unListen();
420
+ const { data: nextData, deps: nextDeps } = invokeDepFn(callback);
421
+ model.set(nextData);
422
+ if (typeof isContinue !== 'function' || isContinue(nextData) !== false) {
423
+ listen(model, nextDeps, callback, unListenRef, isContinue);
424
+ }
425
+ };
426
+ unListenRef.unListen = () => {
427
+ for (const s of deps) {
428
+ s[depsKey].delete(nextListen);
412
429
  }
430
+ };
431
+ for (const s of deps) {
432
+ s[depsKey].add(nextListen);
433
+ }
434
+ }
435
+ listen(signal, deps, callback, unListenRef, isContinue);
436
+ if (component) {
437
+ component.destroyCallbacks.push(() => {
438
+ unListenRef.unListen();
413
439
  });
414
440
  }
415
441
  return signal;
@@ -917,14 +943,6 @@ let Renderer = class Renderer {
917
943
  }
918
944
  createChainByComponentFactory(context, factory, parent) {
919
945
  const component = factory.createInstance(context);
920
- // if (component.setup === Fragment) {
921
- // const children = component.props.children
922
- // return this.createChainByChildren(
923
- // component,
924
- // Array.isArray(children) ? children : [children],
925
- // parent
926
- // )
927
- // }
928
946
  return new Atom(component, parent);
929
947
  }
930
948
  createChainByJSXElement(context, element, parent) {
@@ -986,7 +1004,10 @@ let Renderer = class Renderer {
986
1004
  continue;
987
1005
  }
988
1006
  if (key === 'class') {
989
- this.nativeRenderer.setClass(nativeNode, classToString(props[key]));
1007
+ const className = classToString(props[key]);
1008
+ if (className) {
1009
+ this.nativeRenderer.setClass(nativeNode, className);
1010
+ }
990
1011
  continue;
991
1012
  }
992
1013
  if (key === 'style') {
@@ -999,7 +1020,7 @@ let Renderer = class Renderer {
999
1020
  if (/^on[A-Z]/.test(key)) {
1000
1021
  const listener = props[key];
1001
1022
  if (typeof listener === 'function') {
1002
- this.nativeRenderer.listen(nativeNode, key.replace(/^on/, '').toLowerCase(), listener);
1023
+ this.bindEvent(vNode, key, nativeNode, listener);
1003
1024
  }
1004
1025
  continue;
1005
1026
  }
@@ -1039,7 +1060,10 @@ let Renderer = class Renderer {
1039
1060
  }
1040
1061
  if (/^on[A-Z]/.test(key)) {
1041
1062
  if (typeof value === 'function') {
1042
- this.nativeRenderer.unListen(nativeNode, key.replace(/^on/, '').toLowerCase(), value);
1063
+ const type = key.replace(/^on/, '').toLowerCase();
1064
+ const oldOn = oldVNode.on;
1065
+ this.nativeRenderer.unListen(nativeNode, type, oldOn[type].delegate);
1066
+ Reflect.deleteProperty(oldOn, type);
1043
1067
  }
1044
1068
  continue;
1045
1069
  }
@@ -1073,12 +1097,8 @@ let Renderer = class Renderer {
1073
1097
  }
1074
1098
  if (/^on[A-Z]/.test(key)) {
1075
1099
  const listenType = key.replace(/^on/, '').toLowerCase();
1076
- if (typeof oldValue === 'function') {
1077
- this.nativeRenderer.unListen(nativeNode, listenType, oldValue);
1078
- }
1079
- if (typeof newValue === 'function') {
1080
- this.nativeRenderer.listen(nativeNode, listenType, newValue);
1081
- }
1100
+ newVNode.on = oldVNode.on;
1101
+ newVNode.on[listenType].listenFn = newValue;
1082
1102
  continue;
1083
1103
  }
1084
1104
  if (key === refKey) {
@@ -1105,7 +1125,7 @@ let Renderer = class Renderer {
1105
1125
  }
1106
1126
  if (/^on[A-Z]/.test(key)) {
1107
1127
  if (typeof value === 'function') {
1108
- this.nativeRenderer.listen(nativeNode, key.replace(/^on/, '').toLowerCase(), value);
1128
+ this.bindEvent(newVNode, key, nativeNode, value);
1109
1129
  }
1110
1130
  continue;
1111
1131
  }
@@ -1128,6 +1148,22 @@ let Renderer = class Renderer {
1128
1148
  }
1129
1149
  }
1130
1150
  }
1151
+ bindEvent(vNode, key, nativeNode, listenFn) {
1152
+ let on = vNode.on;
1153
+ if (!on) {
1154
+ vNode.on = on = {};
1155
+ }
1156
+ const type = key.replace(/^on/, '').toLowerCase();
1157
+ const delegate = function (...args) {
1158
+ return delegateObj.listenFn.apply(this, args);
1159
+ };
1160
+ const delegateObj = {
1161
+ delegate,
1162
+ listenFn
1163
+ };
1164
+ on[type] = delegateObj;
1165
+ this.nativeRenderer.listen(nativeNode, type, delegate);
1166
+ }
1131
1167
  };
1132
1168
  Renderer = __decorate([
1133
1169
  Injectable(),
package/bundles/index.js CHANGED
@@ -384,13 +384,25 @@ function useSignal(state) {
384
384
  return;
385
385
  }
386
386
  state = newState;
387
- for (const fn of signal[depsKey]) {
387
+ const depCallbacks = Array.from(signal[depsKey]);
388
+ for (const fn of depCallbacks) {
389
+ // 回调中可能会对依赖做出修改,故需先缓存起来
388
390
  fn();
389
391
  }
390
392
  };
391
393
  signal[depsKey] = new Set();
392
394
  return signal;
393
395
  }
396
+ function invokeDepFn(fn) {
397
+ const deps = [];
398
+ signalDepsStack.push(deps);
399
+ const data = fn();
400
+ signalDepsStack.pop();
401
+ return {
402
+ deps,
403
+ data
404
+ };
405
+ }
394
406
  /**
395
407
  * 使用派生值,Viewfly 会收集回调函数内同步执行时访问的 Signal,
396
408
  * 并在你获取 useDerived 函数返回的 Signal 的值时,自动计算最新的值。
@@ -399,18 +411,32 @@ function useSignal(state) {
399
411
  * @param isContinue 可选的停止函数,在每次值更新后调用,当返回值为 false 时,将不再监听依赖的变化
400
412
  */
401
413
  function useDerived(callback, isContinue) {
402
- const deps = [];
403
- signalDepsStack.push(deps);
404
- const data = callback();
405
- signalDepsStack.pop();
414
+ let { data, deps } = invokeDepFn(callback);
406
415
  const signal = useSignal(data);
407
- if (deps.length) {
408
- const unListen = useEffect(deps, () => {
409
- const data = callback();
410
- signal.set(data);
411
- if (typeof isContinue === 'function' && !isContinue(data)) {
412
- unListen();
416
+ const component = getSetupContext(false);
417
+ const unListenRef = {};
418
+ function listen(model, deps, callback, unListenRef, isContinue) {
419
+ const nextListen = () => {
420
+ unListenRef.unListen();
421
+ const { data: nextData, deps: nextDeps } = invokeDepFn(callback);
422
+ model.set(nextData);
423
+ if (typeof isContinue !== 'function' || isContinue(nextData) !== false) {
424
+ listen(model, nextDeps, callback, unListenRef, isContinue);
425
+ }
426
+ };
427
+ unListenRef.unListen = () => {
428
+ for (const s of deps) {
429
+ s[depsKey].delete(nextListen);
413
430
  }
431
+ };
432
+ for (const s of deps) {
433
+ s[depsKey].add(nextListen);
434
+ }
435
+ }
436
+ listen(signal, deps, callback, unListenRef, isContinue);
437
+ if (component) {
438
+ component.destroyCallbacks.push(() => {
439
+ unListenRef.unListen();
414
440
  });
415
441
  }
416
442
  return signal;
@@ -918,14 +944,6 @@ exports.Renderer = class Renderer {
918
944
  }
919
945
  createChainByComponentFactory(context, factory, parent) {
920
946
  const component = factory.createInstance(context);
921
- // if (component.setup === Fragment) {
922
- // const children = component.props.children
923
- // return this.createChainByChildren(
924
- // component,
925
- // Array.isArray(children) ? children : [children],
926
- // parent
927
- // )
928
- // }
929
947
  return new Atom(component, parent);
930
948
  }
931
949
  createChainByJSXElement(context, element, parent) {
@@ -987,7 +1005,10 @@ exports.Renderer = class Renderer {
987
1005
  continue;
988
1006
  }
989
1007
  if (key === 'class') {
990
- this.nativeRenderer.setClass(nativeNode, classToString(props[key]));
1008
+ const className = classToString(props[key]);
1009
+ if (className) {
1010
+ this.nativeRenderer.setClass(nativeNode, className);
1011
+ }
991
1012
  continue;
992
1013
  }
993
1014
  if (key === 'style') {
@@ -1000,7 +1021,7 @@ exports.Renderer = class Renderer {
1000
1021
  if (/^on[A-Z]/.test(key)) {
1001
1022
  const listener = props[key];
1002
1023
  if (typeof listener === 'function') {
1003
- this.nativeRenderer.listen(nativeNode, key.replace(/^on/, '').toLowerCase(), listener);
1024
+ this.bindEvent(vNode, key, nativeNode, listener);
1004
1025
  }
1005
1026
  continue;
1006
1027
  }
@@ -1040,7 +1061,10 @@ exports.Renderer = class Renderer {
1040
1061
  }
1041
1062
  if (/^on[A-Z]/.test(key)) {
1042
1063
  if (typeof value === 'function') {
1043
- this.nativeRenderer.unListen(nativeNode, key.replace(/^on/, '').toLowerCase(), value);
1064
+ const type = key.replace(/^on/, '').toLowerCase();
1065
+ const oldOn = oldVNode.on;
1066
+ this.nativeRenderer.unListen(nativeNode, type, oldOn[type].delegate);
1067
+ Reflect.deleteProperty(oldOn, type);
1044
1068
  }
1045
1069
  continue;
1046
1070
  }
@@ -1074,12 +1098,8 @@ exports.Renderer = class Renderer {
1074
1098
  }
1075
1099
  if (/^on[A-Z]/.test(key)) {
1076
1100
  const listenType = key.replace(/^on/, '').toLowerCase();
1077
- if (typeof oldValue === 'function') {
1078
- this.nativeRenderer.unListen(nativeNode, listenType, oldValue);
1079
- }
1080
- if (typeof newValue === 'function') {
1081
- this.nativeRenderer.listen(nativeNode, listenType, newValue);
1082
- }
1101
+ newVNode.on = oldVNode.on;
1102
+ newVNode.on[listenType].listenFn = newValue;
1083
1103
  continue;
1084
1104
  }
1085
1105
  if (key === refKey) {
@@ -1106,7 +1126,7 @@ exports.Renderer = class Renderer {
1106
1126
  }
1107
1127
  if (/^on[A-Z]/.test(key)) {
1108
1128
  if (typeof value === 'function') {
1109
- this.nativeRenderer.listen(nativeNode, key.replace(/^on/, '').toLowerCase(), value);
1129
+ this.bindEvent(newVNode, key, nativeNode, value);
1110
1130
  }
1111
1131
  continue;
1112
1132
  }
@@ -1129,6 +1149,22 @@ exports.Renderer = class Renderer {
1129
1149
  }
1130
1150
  }
1131
1151
  }
1152
+ bindEvent(vNode, key, nativeNode, listenFn) {
1153
+ let on = vNode.on;
1154
+ if (!on) {
1155
+ vNode.on = on = {};
1156
+ }
1157
+ const type = key.replace(/^on/, '').toLowerCase();
1158
+ const delegate = function (...args) {
1159
+ return delegateObj.listenFn.apply(this, args);
1160
+ };
1161
+ const delegateObj = {
1162
+ delegate,
1163
+ listenFn
1164
+ };
1165
+ on[type] = delegateObj;
1166
+ this.nativeRenderer.listen(nativeNode, type, delegate);
1167
+ }
1132
1168
  };
1133
1169
  exports.Renderer = __decorate([
1134
1170
  di.Injectable(),
@@ -21,11 +21,16 @@ export declare class JSXText implements JSXTypeof {
21
21
  constructor(text: string);
22
22
  is(target: JSXTypeof): boolean;
23
23
  }
24
+ export interface ListenDelegate {
25
+ delegate: () => any;
26
+ listenFn: ((...args: any[]) => any) | void;
27
+ }
24
28
  export declare class JSXElement implements JSXTypeof {
25
29
  type: string;
26
30
  props: Props<any>;
27
31
  key?: Key | undefined;
28
32
  $$typeOf: string;
33
+ on?: Record<string, ListenDelegate>;
29
34
  constructor(type: string, props: Props<any>, key?: Key | undefined);
30
35
  is(target: JSXTypeof): boolean;
31
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viewfly/core",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
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",
@@ -34,5 +34,5 @@
34
34
  "bugs": {
35
35
  "url": "https://github.com/viewfly/viewfly.git/issues"
36
36
  },
37
- "gitHead": "55152a4c7db778d22e4ed1d8cd648f9800a01992"
37
+ "gitHead": "fed5b3e328a9f70873bb1c33ea3789c099ad3ebe"
38
38
  }