@viewfly/core 0.0.2 → 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
  }
@@ -58,8 +58,12 @@ function getSignalDepsContext() {
58
58
  return signalDepsStack[signalDepsStack.length - 1];
59
59
  }
60
60
  class JSXComponent {
61
- constructor(createInstance) {
62
- this.createInstance = createInstance;
61
+ constructor(props, factory) {
62
+ this.props = props;
63
+ this.factory = factory;
64
+ }
65
+ createInstance(injector) {
66
+ return this.factory(injector, this.props);
63
67
  }
64
68
  }
65
69
  /**
@@ -379,13 +383,25 @@ function useSignal(state) {
379
383
  return;
380
384
  }
381
385
  state = newState;
382
- for (const fn of signal[depsKey]) {
386
+ const depCallbacks = Array.from(signal[depsKey]);
387
+ for (const fn of depCallbacks) {
388
+ // 回调中可能会对依赖做出修改,故需先缓存起来
383
389
  fn();
384
390
  }
385
391
  };
386
392
  signal[depsKey] = new Set();
387
393
  return signal;
388
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
+ }
389
405
  /**
390
406
  * 使用派生值,Viewfly 会收集回调函数内同步执行时访问的 Signal,
391
407
  * 并在你获取 useDerived 函数返回的 Signal 的值时,自动计算最新的值。
@@ -394,18 +410,32 @@ function useSignal(state) {
394
410
  * @param isContinue 可选的停止函数,在每次值更新后调用,当返回值为 false 时,将不再监听依赖的变化
395
411
  */
396
412
  function useDerived(callback, isContinue) {
397
- const deps = [];
398
- signalDepsStack.push(deps);
399
- const data = callback();
400
- signalDepsStack.pop();
413
+ let { data, deps } = invokeDepFn(callback);
401
414
  const signal = useSignal(data);
402
- if (deps.length) {
403
- const unListen = useEffect(deps, () => {
404
- const data = callback();
405
- signal.set(data);
406
- if (typeof isContinue === 'function' && !isContinue(data)) {
407
- 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);
408
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();
409
439
  });
410
440
  }
411
441
  return signal;
@@ -473,20 +503,20 @@ const Fragment = function Fragment(props) {
473
503
  return props.children;
474
504
  };
475
505
  };
476
- function jsx(setup, config, key) {
506
+ function jsx(setup, props, key) {
477
507
  if (typeof setup === 'string') {
478
- return new JSXElement(setup, config, key);
508
+ return new JSXElement(setup, props, key);
479
509
  }
480
- return new JSXComponent(function (context) {
481
- return new Component(context, setup, config, key);
510
+ return new JSXComponent(props, function (context, props) {
511
+ return new Component(context, setup, props, key);
482
512
  });
483
513
  }
484
- function jsxs(setup, config, key) {
514
+ function jsxs(setup, props, key) {
485
515
  if (typeof setup === 'string') {
486
- return new JSXElement(setup, config, key);
516
+ return new JSXElement(setup, props, key);
487
517
  }
488
- return new JSXComponent(function (context) {
489
- return new Component(context, setup, config, key);
518
+ return new JSXComponent(props, function (context, props) {
519
+ return new Component(context, setup, props, key);
490
520
  });
491
521
  }
492
522
  class JSXText {
@@ -913,14 +943,6 @@ let Renderer = class Renderer {
913
943
  }
914
944
  createChainByComponentFactory(context, factory, parent) {
915
945
  const component = factory.createInstance(context);
916
- // if (component.setup === Fragment) {
917
- // const children = component.props.children
918
- // return this.createChainByChildren(
919
- // component,
920
- // Array.isArray(children) ? children : [children],
921
- // parent
922
- // )
923
- // }
924
946
  return new Atom(component, parent);
925
947
  }
926
948
  createChainByJSXElement(context, element, parent) {
@@ -982,7 +1004,10 @@ let Renderer = class Renderer {
982
1004
  continue;
983
1005
  }
984
1006
  if (key === 'class') {
985
- this.nativeRenderer.setClass(nativeNode, classToString(props[key]));
1007
+ const className = classToString(props[key]);
1008
+ if (className) {
1009
+ this.nativeRenderer.setClass(nativeNode, className);
1010
+ }
986
1011
  continue;
987
1012
  }
988
1013
  if (key === 'style') {
@@ -995,7 +1020,7 @@ let Renderer = class Renderer {
995
1020
  if (/^on[A-Z]/.test(key)) {
996
1021
  const listener = props[key];
997
1022
  if (typeof listener === 'function') {
998
- this.nativeRenderer.listen(nativeNode, key.replace(/^on/, '').toLowerCase(), listener);
1023
+ this.bindEvent(vNode, key, nativeNode, listener);
999
1024
  }
1000
1025
  continue;
1001
1026
  }
@@ -1035,7 +1060,10 @@ let Renderer = class Renderer {
1035
1060
  }
1036
1061
  if (/^on[A-Z]/.test(key)) {
1037
1062
  if (typeof value === 'function') {
1038
- 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);
1039
1067
  }
1040
1068
  continue;
1041
1069
  }
@@ -1069,12 +1097,8 @@ let Renderer = class Renderer {
1069
1097
  }
1070
1098
  if (/^on[A-Z]/.test(key)) {
1071
1099
  const listenType = key.replace(/^on/, '').toLowerCase();
1072
- if (typeof oldValue === 'function') {
1073
- this.nativeRenderer.unListen(nativeNode, listenType, oldValue);
1074
- }
1075
- if (typeof newValue === 'function') {
1076
- this.nativeRenderer.listen(nativeNode, listenType, newValue);
1077
- }
1100
+ newVNode.on = oldVNode.on;
1101
+ newVNode.on[listenType].listenFn = newValue;
1078
1102
  continue;
1079
1103
  }
1080
1104
  if (key === refKey) {
@@ -1101,7 +1125,7 @@ let Renderer = class Renderer {
1101
1125
  }
1102
1126
  if (/^on[A-Z]/.test(key)) {
1103
1127
  if (typeof value === 'function') {
1104
- this.nativeRenderer.listen(nativeNode, key.replace(/^on/, '').toLowerCase(), value);
1128
+ this.bindEvent(newVNode, key, nativeNode, value);
1105
1129
  }
1106
1130
  continue;
1107
1131
  }
@@ -1124,6 +1148,22 @@ let Renderer = class Renderer {
1124
1148
  }
1125
1149
  }
1126
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
+ }
1127
1167
  };
1128
1168
  Renderer = __decorate([
1129
1169
  Injectable(),
package/bundles/index.js CHANGED
@@ -59,8 +59,12 @@ function getSignalDepsContext() {
59
59
  return signalDepsStack[signalDepsStack.length - 1];
60
60
  }
61
61
  class JSXComponent {
62
- constructor(createInstance) {
63
- this.createInstance = createInstance;
62
+ constructor(props, factory) {
63
+ this.props = props;
64
+ this.factory = factory;
65
+ }
66
+ createInstance(injector) {
67
+ return this.factory(injector, this.props);
64
68
  }
65
69
  }
66
70
  /**
@@ -380,13 +384,25 @@ function useSignal(state) {
380
384
  return;
381
385
  }
382
386
  state = newState;
383
- for (const fn of signal[depsKey]) {
387
+ const depCallbacks = Array.from(signal[depsKey]);
388
+ for (const fn of depCallbacks) {
389
+ // 回调中可能会对依赖做出修改,故需先缓存起来
384
390
  fn();
385
391
  }
386
392
  };
387
393
  signal[depsKey] = new Set();
388
394
  return signal;
389
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
+ }
390
406
  /**
391
407
  * 使用派生值,Viewfly 会收集回调函数内同步执行时访问的 Signal,
392
408
  * 并在你获取 useDerived 函数返回的 Signal 的值时,自动计算最新的值。
@@ -395,18 +411,32 @@ function useSignal(state) {
395
411
  * @param isContinue 可选的停止函数,在每次值更新后调用,当返回值为 false 时,将不再监听依赖的变化
396
412
  */
397
413
  function useDerived(callback, isContinue) {
398
- const deps = [];
399
- signalDepsStack.push(deps);
400
- const data = callback();
401
- signalDepsStack.pop();
414
+ let { data, deps } = invokeDepFn(callback);
402
415
  const signal = useSignal(data);
403
- if (deps.length) {
404
- const unListen = useEffect(deps, () => {
405
- const data = callback();
406
- signal.set(data);
407
- if (typeof isContinue === 'function' && !isContinue(data)) {
408
- 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);
409
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();
410
440
  });
411
441
  }
412
442
  return signal;
@@ -474,20 +504,20 @@ const Fragment = function Fragment(props) {
474
504
  return props.children;
475
505
  };
476
506
  };
477
- function jsx(setup, config, key) {
507
+ function jsx(setup, props, key) {
478
508
  if (typeof setup === 'string') {
479
- return new JSXElement(setup, config, key);
509
+ return new JSXElement(setup, props, key);
480
510
  }
481
- return new JSXComponent(function (context) {
482
- return new Component(context, setup, config, key);
511
+ return new JSXComponent(props, function (context, props) {
512
+ return new Component(context, setup, props, key);
483
513
  });
484
514
  }
485
- function jsxs(setup, config, key) {
515
+ function jsxs(setup, props, key) {
486
516
  if (typeof setup === 'string') {
487
- return new JSXElement(setup, config, key);
517
+ return new JSXElement(setup, props, key);
488
518
  }
489
- return new JSXComponent(function (context) {
490
- return new Component(context, setup, config, key);
519
+ return new JSXComponent(props, function (context, props) {
520
+ return new Component(context, setup, props, key);
491
521
  });
492
522
  }
493
523
  class JSXText {
@@ -914,14 +944,6 @@ exports.Renderer = class Renderer {
914
944
  }
915
945
  createChainByComponentFactory(context, factory, parent) {
916
946
  const component = factory.createInstance(context);
917
- // if (component.setup === Fragment) {
918
- // const children = component.props.children
919
- // return this.createChainByChildren(
920
- // component,
921
- // Array.isArray(children) ? children : [children],
922
- // parent
923
- // )
924
- // }
925
947
  return new Atom(component, parent);
926
948
  }
927
949
  createChainByJSXElement(context, element, parent) {
@@ -983,7 +1005,10 @@ exports.Renderer = class Renderer {
983
1005
  continue;
984
1006
  }
985
1007
  if (key === 'class') {
986
- this.nativeRenderer.setClass(nativeNode, classToString(props[key]));
1008
+ const className = classToString(props[key]);
1009
+ if (className) {
1010
+ this.nativeRenderer.setClass(nativeNode, className);
1011
+ }
987
1012
  continue;
988
1013
  }
989
1014
  if (key === 'style') {
@@ -996,7 +1021,7 @@ exports.Renderer = class Renderer {
996
1021
  if (/^on[A-Z]/.test(key)) {
997
1022
  const listener = props[key];
998
1023
  if (typeof listener === 'function') {
999
- this.nativeRenderer.listen(nativeNode, key.replace(/^on/, '').toLowerCase(), listener);
1024
+ this.bindEvent(vNode, key, nativeNode, listener);
1000
1025
  }
1001
1026
  continue;
1002
1027
  }
@@ -1036,7 +1061,10 @@ exports.Renderer = class Renderer {
1036
1061
  }
1037
1062
  if (/^on[A-Z]/.test(key)) {
1038
1063
  if (typeof value === 'function') {
1039
- 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);
1040
1068
  }
1041
1069
  continue;
1042
1070
  }
@@ -1070,12 +1098,8 @@ exports.Renderer = class Renderer {
1070
1098
  }
1071
1099
  if (/^on[A-Z]/.test(key)) {
1072
1100
  const listenType = key.replace(/^on/, '').toLowerCase();
1073
- if (typeof oldValue === 'function') {
1074
- this.nativeRenderer.unListen(nativeNode, listenType, oldValue);
1075
- }
1076
- if (typeof newValue === 'function') {
1077
- this.nativeRenderer.listen(nativeNode, listenType, newValue);
1078
- }
1101
+ newVNode.on = oldVNode.on;
1102
+ newVNode.on[listenType].listenFn = newValue;
1079
1103
  continue;
1080
1104
  }
1081
1105
  if (key === refKey) {
@@ -1102,7 +1126,7 @@ exports.Renderer = class Renderer {
1102
1126
  }
1103
1127
  if (/^on[A-Z]/.test(key)) {
1104
1128
  if (typeof value === 'function') {
1105
- this.nativeRenderer.listen(nativeNode, key.replace(/^on/, '').toLowerCase(), value);
1129
+ this.bindEvent(newVNode, key, nativeNode, value);
1106
1130
  }
1107
1131
  continue;
1108
1132
  }
@@ -1125,6 +1149,22 @@ exports.Renderer = class Renderer {
1125
1149
  }
1126
1150
  }
1127
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
+ }
1128
1168
  };
1129
1169
  exports.Renderer = __decorate([
1130
1170
  di.Injectable(),
package/bundles/jsx.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Key, Ref } from '@viewfly/core';
2
2
  export declare namespace JSX {
3
+ type ClassNames = string | Record<string, unknown> | Array<string | Record<string, unknown>>;
3
4
  interface Attributes<T extends object> {
4
5
  ref?: Ref<T> | Ref<T>[];
5
6
  key?: Key;
@@ -1,8 +1,10 @@
1
1
  import { Provider, ReflectiveInjector, AbstractType, Type, InjectionToken, InjectFlags, Injector } from '@tanbo/di';
2
2
  import { Props, Key, JSXTypeof, JSXChildNode } from './jsx-element';
3
3
  export declare class JSXComponent {
4
- createInstance: (injector: Component) => Component;
5
- constructor(createInstance: (injector: Component) => Component);
4
+ props: Props;
5
+ private factory;
6
+ constructor(props: Props, factory: (injector: Component, props: Props) => Component);
7
+ createInstance(injector: Component): Component;
6
8
  }
7
9
  export interface ComponentSetup<T extends Props<any> = Props<any>> {
8
10
  (props?: T): () => JSXChildNode;
@@ -7,10 +7,10 @@ export interface Props<T = JSXChildNode | JSXChildNode[]> {
7
7
  }
8
8
  export declare const Fragment: (props: Props) => () => JSXChildNode | JSXChildNode[];
9
9
  export type Key = number | string;
10
- export declare function jsx<T extends JSXChildNode>(name: string, config: Props<T>, key?: Key): JSXElement;
11
- export declare function jsx<T extends JSXChildNode>(setup: ComponentSetup, config: Props<T>, key?: Key): JSXComponent;
12
- export declare function jsxs<T extends JSXChildNode[]>(name: string, config: Props<T>, key?: Key): JSXElement;
13
- export declare function jsxs<T extends JSXChildNode[]>(setup: ComponentSetup, config: Props<T>, key?: Key): JSXComponent;
10
+ export declare function jsx<T extends JSXChildNode>(name: string, props: Props<T>, key?: Key): JSXElement;
11
+ export declare function jsx<T extends JSXChildNode>(setup: ComponentSetup, props: Props<T>, key?: Key): JSXComponent;
12
+ export declare function jsxs<T extends JSXChildNode[]>(name: string, props: Props<T>, key?: Key): JSXElement;
13
+ export declare function jsxs<T extends JSXChildNode[]>(setup: ComponentSetup, props: Props<T>, key?: Key): JSXComponent;
14
14
  export interface JSXTypeof {
15
15
  $$typeOf: string | ComponentSetup;
16
16
  is(target: JSXTypeof): boolean;
@@ -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.2",
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": "65bcb20399ed7e6e14102b649588135a7ebf4a72"
37
+ "gitHead": "fed5b3e328a9f70873bb1c33ea3789c099ad3ebe"
38
38
  }