@viewfly/core 0.0.1-alpha.6 → 0.0.1-alpha.7

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.
@@ -18,7 +18,7 @@ export declare class Renderer {
18
18
  private diff;
19
19
  private cleanView;
20
20
  private reuseAndUpdate;
21
- private createViewByAtom;
21
+ private temporarilyRemove;
22
22
  private buildView;
23
23
  private componentRender;
24
24
  private createChainByComponentFactory;
@@ -47,20 +47,20 @@ const jsxErrorFn = makeError('JSX');
47
47
  const Fragment = function Fragment() {
48
48
  throw jsxErrorFn('Fragment does not support calling.');
49
49
  };
50
- function jsx(setup, config) {
50
+ function jsx(setup, config, key) {
51
51
  if (typeof setup === 'string') {
52
- return new JSXElement(setup, config);
52
+ return new JSXElement(setup, config, key);
53
53
  }
54
54
  return new JSXComponent(function (context) {
55
- return new Component(context, setup, config);
55
+ return new Component(context, setup, config, key);
56
56
  });
57
57
  }
58
- function jsxs(setup, config) {
58
+ function jsxs(setup, config, key) {
59
59
  if (typeof setup === 'string') {
60
- return new JSXElement(setup, config);
60
+ return new JSXElement(setup, config, key);
61
61
  }
62
62
  return new JSXComponent(function (context) {
63
- return new Component(context, setup, config);
63
+ return new Component(context, setup, config, key);
64
64
  });
65
65
  }
66
66
  class JSXText {
@@ -171,9 +171,10 @@ class Props {
171
171
  }
172
172
  }
173
173
  class JSXElement {
174
- constructor(name, config) {
174
+ constructor(name, config, key) {
175
175
  this.name = name;
176
176
  this.config = config;
177
+ this.key = key;
177
178
  this.props = new Props(config);
178
179
  }
179
180
  }
@@ -212,10 +213,11 @@ class Component extends ReflectiveInjector {
212
213
  get changed() {
213
214
  return this._changed;
214
215
  }
215
- constructor(context, setup, config) {
216
+ constructor(context, setup, config, key) {
216
217
  super(context, []);
217
218
  this.setup = setup;
218
219
  this.config = config;
220
+ this.key = key;
219
221
  this.destroyCallbacks = [];
220
222
  this.mountCallbacks = [];
221
223
  this.propsChangedCallbacks = [];
@@ -785,10 +787,10 @@ let Renderer = class Renderer {
785
787
  }
786
788
  render() {
787
789
  const { component, host } = this.rootComponentRef;
788
- const chain = new Atom(component, null);
789
- const children = this.buildView(chain);
790
- children.forEach(child => {
791
- this.nativeRenderer.appendChild(host, child);
790
+ const atom = new Atom(component, null);
791
+ this.buildView(atom, {
792
+ isParent: true,
793
+ host
792
794
  });
793
795
  }
794
796
  refresh() {
@@ -871,12 +873,17 @@ let Renderer = class Renderer {
871
873
  }
872
874
  diff(start, diffAtom, context) {
873
875
  const oldChildren = [];
876
+ let index = 0;
874
877
  while (diffAtom) {
875
- oldChildren.push(diffAtom);
878
+ oldChildren.push({
879
+ index,
880
+ atom: diffAtom
881
+ });
876
882
  diffAtom = diffAtom.sibling;
883
+ index++;
877
884
  }
878
885
  const commits = [];
879
- const addReuseCommit = (start, reusedAtom) => {
886
+ const addUpdateCommit = (start, reusedAtom) => {
880
887
  commits.push(() => {
881
888
  const isComponent = start.jsxNode instanceof Component;
882
889
  if (!isComponent) {
@@ -890,6 +897,10 @@ let Renderer = class Renderer {
890
897
  context.host = start.nativeNode;
891
898
  context.isParent = false;
892
899
  }
900
+ let applyRefs = null;
901
+ if (start.jsxNode instanceof JSXElement) {
902
+ applyRefs = this.updateNativeNodeProperties(start.jsxNode, reusedAtom.jsxNode, start.nativeNode);
903
+ }
893
904
  if (start.child) {
894
905
  const childContext = start.jsxNode instanceof JSXElement ? {
895
906
  host: start.nativeNode,
@@ -904,6 +915,9 @@ let Renderer = class Renderer {
904
915
  atom = atom.sibling;
905
916
  }
906
917
  }
918
+ if (applyRefs) {
919
+ applyRefs();
920
+ }
907
921
  if (isComponent) {
908
922
  start.jsxNode.rendered();
909
923
  }
@@ -911,31 +925,23 @@ let Renderer = class Renderer {
911
925
  };
912
926
  const addCreateCommit = (start) => {
913
927
  commits.push(() => {
914
- const children = this.createViewByAtom(start);
915
- children.forEach(child => {
916
- if (context.isParent) {
917
- this.nativeRenderer.prependChild(context.host, child);
918
- }
919
- else {
920
- this.nativeRenderer.insertAfter(child, context.host);
921
- }
922
- context.host = child;
923
- context.isParent = false;
924
- });
928
+ this.buildView(start, context);
925
929
  });
926
930
  };
931
+ let i = 0;
927
932
  while (start && !start.nativeNode) {
928
- const reusedAtom = this.reuseAndUpdate(start, oldChildren);
933
+ const reusedAtom = this.reuseAndUpdate(start, i, oldChildren);
929
934
  if (reusedAtom) {
930
- addReuseCommit(start, reusedAtom);
935
+ addUpdateCommit(start, reusedAtom);
931
936
  }
932
937
  else {
933
938
  addCreateCommit(start);
934
939
  }
940
+ i++;
935
941
  start = start.sibling;
936
942
  }
937
- for (const atom of oldChildren) {
938
- this.cleanView(atom, false);
943
+ for (const item of oldChildren) {
944
+ this.cleanView(item.atom, false);
939
945
  }
940
946
  for (const commit of commits) {
941
947
  commit();
@@ -961,14 +967,25 @@ let Renderer = class Renderer {
961
967
  atom.jsxNode.destroy();
962
968
  }
963
969
  }
964
- reuseAndUpdate(start, oldChildren) {
970
+ reuseAndUpdate(start, lastIndex, oldChildren) {
971
+ let isReuse = false;
965
972
  for (let i = 0; i < oldChildren.length; i++) {
966
- const diffAtom = oldChildren[i];
973
+ const { atom: diffAtom, index: diffIndex } = oldChildren[i];
974
+ const key = start.jsxNode.key;
975
+ const diffKey = diffAtom.jsxNode.key;
976
+ if (key !== undefined && diffKey !== undefined) {
977
+ if (diffKey !== key) {
978
+ continue;
979
+ }
980
+ isReuse = lastIndex > diffIndex;
981
+ }
967
982
  if (start.jsxNode instanceof JSXElement) {
968
983
  if (diffAtom.jsxNode instanceof JSXElement && start.jsxNode.name === diffAtom.jsxNode.name) {
969
984
  const nativeNode = diffAtom.nativeNode;
985
+ if (isReuse) {
986
+ this.nativeRenderer.remove(nativeNode);
987
+ }
970
988
  start.nativeNode = nativeNode;
971
- this.updateNativeNodeProperties(start.jsxNode, diffAtom.jsxNode, nativeNode);
972
989
  oldChildren.splice(i, 1);
973
990
  return diffAtom;
974
991
  }
@@ -986,6 +1003,9 @@ let Renderer = class Renderer {
986
1003
  }
987
1004
  else if (diffAtom.jsxNode instanceof Component) {
988
1005
  if (start.jsxNode.setup === diffAtom.jsxNode.setup) {
1006
+ if (isReuse) {
1007
+ this.temporarilyRemove(diffAtom);
1008
+ }
989
1009
  const { isChanged } = getNodeChanges(start.jsxNode, diffAtom.jsxNode);
990
1010
  if (isChanged) {
991
1011
  diffAtom.jsxNode.invokePropsChangedHooks(start.jsxNode.config);
@@ -1009,100 +1029,74 @@ let Renderer = class Renderer {
1009
1029
  }
1010
1030
  return null;
1011
1031
  }
1012
- createViewByAtom(atom) {
1013
- if (atom.jsxNode instanceof JSXElement) {
1014
- const nativeNode = this.createElement(atom.jsxNode);
1015
- atom.nativeNode = nativeNode;
1016
- if (atom.child) {
1017
- const children = this.buildView(atom.child);
1018
- for (const child of children) {
1019
- this.nativeRenderer.appendChild(nativeNode, child);
1020
- }
1032
+ temporarilyRemove(atom) {
1033
+ let next = atom.child;
1034
+ while (next) {
1035
+ if (next.jsxNode instanceof Component) {
1036
+ this.temporarilyRemove(next);
1021
1037
  }
1022
- return [nativeNode];
1023
- }
1024
- else if (atom.jsxNode instanceof JSXText) {
1025
- const nativeNode = this.createTextNode(atom.jsxNode);
1026
- atom.nativeNode = nativeNode;
1027
- return [nativeNode];
1028
- }
1029
- const { template, render } = atom.jsxNode.init();
1030
- this.componentAtomCaches.set(atom.jsxNode, {
1031
- atom,
1032
- render
1033
- });
1034
- if (template) {
1035
- this.linkTemplate(template, atom.jsxNode, atom);
1036
- }
1037
- if (atom.child) {
1038
- return this.buildView(atom.child);
1038
+ else {
1039
+ this.nativeRenderer.remove(next.nativeNode);
1040
+ }
1041
+ next = next.sibling;
1039
1042
  }
1040
- return [];
1041
1043
  }
1042
- buildView(chain) {
1043
- const context = [];
1044
- const children = [];
1045
- function getContext() {
1046
- return context[context.length - 1];
1047
- }
1048
- let atom = chain;
1049
- const stopAtom = chain.parent;
1050
- wrap: while (atom) {
1051
- if (atom.jsxNode instanceof Component) {
1052
- this.componentRender(atom.jsxNode, atom);
1053
- if (atom.child) {
1054
- atom = atom.child;
1055
- continue;
1056
- }
1057
- atom.jsxNode.rendered();
1044
+ buildView(atom, context) {
1045
+ if (atom.jsxNode instanceof Component) {
1046
+ this.componentRender(atom.jsxNode, atom);
1047
+ let child = atom.child;
1048
+ while (child) {
1049
+ this.buildView(child, context);
1050
+ child = child.sibling;
1051
+ }
1052
+ atom.jsxNode.rendered();
1053
+ }
1054
+ else {
1055
+ let nativeNode;
1056
+ let applyRefs = null;
1057
+ if (atom.jsxNode instanceof JSXElement) {
1058
+ const { nativeNode: n, applyRefs: a } = this.createElement(atom.jsxNode);
1059
+ nativeNode = n;
1060
+ applyRefs = a;
1058
1061
  }
1059
1062
  else {
1060
- const host = getContext();
1061
- const nativeNode = atom.jsxNode instanceof JSXElement ? this.createElement(atom.jsxNode) : this.createTextNode(atom.jsxNode);
1062
- atom.nativeNode = nativeNode;
1063
- if (host) {
1064
- this.nativeRenderer.appendChild(host, nativeNode);
1065
- }
1066
- else {
1067
- children.push(nativeNode);
1068
- }
1069
- if (atom.child) {
1070
- context.push(nativeNode);
1071
- atom = atom.child;
1072
- continue;
1073
- }
1063
+ nativeNode = this.createTextNode(atom.jsxNode);
1074
1064
  }
1075
- while (atom) {
1076
- if (atom.sibling) {
1077
- atom = atom.sibling;
1078
- break;
1079
- }
1080
- atom = atom.parent;
1081
- const isComponent = (atom === null || atom === void 0 ? void 0 : atom.jsxNode) instanceof Component;
1082
- if (isComponent) {
1083
- atom.jsxNode.rendered();
1084
- }
1085
- if (atom === stopAtom) {
1086
- break wrap;
1087
- }
1088
- if (isComponent) {
1089
- continue;
1065
+ atom.nativeNode = nativeNode;
1066
+ if (context.isParent) {
1067
+ this.nativeRenderer.prependChild(context.host, nativeNode);
1068
+ }
1069
+ else {
1070
+ this.nativeRenderer.insertAfter(nativeNode, context.host);
1071
+ }
1072
+ if (atom.jsxNode instanceof JSXElement) {
1073
+ const childContext = {
1074
+ isParent: true,
1075
+ host: nativeNode
1076
+ };
1077
+ let child = atom.child;
1078
+ while (child) {
1079
+ this.buildView(child, childContext);
1080
+ child = child.sibling;
1090
1081
  }
1091
- context.pop();
1082
+ }
1083
+ context.host = nativeNode;
1084
+ context.isParent = false;
1085
+ if (applyRefs) {
1086
+ applyRefs();
1092
1087
  }
1093
1088
  }
1094
- return children;
1095
1089
  }
1096
- componentRender(component, parent) {
1090
+ componentRender(component, from) {
1097
1091
  const { template, render } = component.init();
1098
1092
  if (template) {
1099
- this.linkTemplate(template, component, parent);
1093
+ this.linkTemplate(template, component, from);
1100
1094
  }
1101
1095
  this.componentAtomCaches.set(component, {
1102
1096
  render,
1103
- atom: parent
1097
+ atom: from
1104
1098
  });
1105
- return parent;
1099
+ return from;
1106
1100
  }
1107
1101
  createChainByComponentFactory(context, factory, parent) {
1108
1102
  const component = factory.createInstance(context);
@@ -1158,25 +1152,27 @@ let Renderer = class Renderer {
1158
1152
  createElement(vNode) {
1159
1153
  const nativeNode = this.nativeRenderer.createElement(vNode.name);
1160
1154
  const props = vNode.props;
1161
- if (props) {
1162
- let bindingRefs;
1163
- props.attrs.forEach((value, key) => {
1164
- if (key === refKey) {
1165
- bindingRefs = value;
1166
- return;
1167
- }
1168
- this.nativeRenderer.setProperty(nativeNode, key, value);
1169
- });
1170
- props.styles.forEach((value, key) => {
1171
- this.nativeRenderer.setStyle(nativeNode, key, value);
1172
- });
1173
- props.classes.forEach(k => this.nativeRenderer.addClass(nativeNode, k));
1174
- Object.keys(props.listeners).forEach(type => {
1175
- this.nativeRenderer.listen(nativeNode, type, props.listeners[type]);
1176
- });
1177
- this.applyRefs(bindingRefs, nativeNode, true);
1178
- }
1179
- return nativeNode;
1155
+ let bindingRefs;
1156
+ props.attrs.forEach((value, key) => {
1157
+ if (key === refKey) {
1158
+ bindingRefs = value;
1159
+ return;
1160
+ }
1161
+ this.nativeRenderer.setProperty(nativeNode, key, value);
1162
+ });
1163
+ props.styles.forEach((value, key) => {
1164
+ this.nativeRenderer.setStyle(nativeNode, key, value);
1165
+ });
1166
+ props.classes.forEach(k => this.nativeRenderer.addClass(nativeNode, k));
1167
+ Object.keys(props.listeners).forEach(type => {
1168
+ this.nativeRenderer.listen(nativeNode, type, props.listeners[type]);
1169
+ });
1170
+ return {
1171
+ nativeNode,
1172
+ applyRefs: () => {
1173
+ this.applyRefs(bindingRefs, nativeNode, true);
1174
+ }
1175
+ };
1180
1176
  }
1181
1177
  createTextNode(child) {
1182
1178
  return this.nativeRenderer.createTextNode(child.text);
@@ -1184,7 +1180,7 @@ let Renderer = class Renderer {
1184
1180
  updateNativeNodeProperties(newVNode, oldVNode, nativeNode) {
1185
1181
  const { styleChanges, attrChanges, classesChanges, listenerChanges, isChanged } = getNodeChanges(newVNode, oldVNode);
1186
1182
  if (!isChanged) {
1187
- return;
1183
+ return null;
1188
1184
  }
1189
1185
  styleChanges.remove.forEach(i => this.nativeRenderer.removeStyle(nativeNode, i[0]));
1190
1186
  styleChanges.set.forEach(i => this.nativeRenderer.setStyle(nativeNode, i[0], i[1]));
@@ -1212,8 +1208,10 @@ let Renderer = class Renderer {
1212
1208
  listenerChanges.add.forEach(i => {
1213
1209
  this.nativeRenderer.listen(nativeNode, i[0], i[1]);
1214
1210
  });
1215
- this.applyRefs(unBindRefs, nativeNode, false);
1216
- this.applyRefs(bindRefs, nativeNode, true);
1211
+ return () => {
1212
+ this.applyRefs(unBindRefs, nativeNode, false);
1213
+ this.applyRefs(bindRefs, nativeNode, true);
1214
+ };
1217
1215
  }
1218
1216
  applyRefs(refs, nativeNode, binding) {
1219
1217
  refs = Array.isArray(refs) ? refs : [refs];
package/bundles/index.js CHANGED
@@ -48,20 +48,20 @@ const jsxErrorFn = makeError('JSX');
48
48
  const Fragment = function Fragment() {
49
49
  throw jsxErrorFn('Fragment does not support calling.');
50
50
  };
51
- function jsx(setup, config) {
51
+ function jsx(setup, config, key) {
52
52
  if (typeof setup === 'string') {
53
- return new JSXElement(setup, config);
53
+ return new JSXElement(setup, config, key);
54
54
  }
55
55
  return new JSXComponent(function (context) {
56
- return new Component(context, setup, config);
56
+ return new Component(context, setup, config, key);
57
57
  });
58
58
  }
59
- function jsxs(setup, config) {
59
+ function jsxs(setup, config, key) {
60
60
  if (typeof setup === 'string') {
61
- return new JSXElement(setup, config);
61
+ return new JSXElement(setup, config, key);
62
62
  }
63
63
  return new JSXComponent(function (context) {
64
- return new Component(context, setup, config);
64
+ return new Component(context, setup, config, key);
65
65
  });
66
66
  }
67
67
  class JSXText {
@@ -172,9 +172,10 @@ class Props {
172
172
  }
173
173
  }
174
174
  class JSXElement {
175
- constructor(name, config) {
175
+ constructor(name, config, key) {
176
176
  this.name = name;
177
177
  this.config = config;
178
+ this.key = key;
178
179
  this.props = new Props(config);
179
180
  }
180
181
  }
@@ -213,10 +214,11 @@ class Component extends di.ReflectiveInjector {
213
214
  get changed() {
214
215
  return this._changed;
215
216
  }
216
- constructor(context, setup, config) {
217
+ constructor(context, setup, config, key) {
217
218
  super(context, []);
218
219
  this.setup = setup;
219
220
  this.config = config;
221
+ this.key = key;
220
222
  this.destroyCallbacks = [];
221
223
  this.mountCallbacks = [];
222
224
  this.propsChangedCallbacks = [];
@@ -786,10 +788,10 @@ exports.Renderer = class Renderer {
786
788
  }
787
789
  render() {
788
790
  const { component, host } = this.rootComponentRef;
789
- const chain = new Atom(component, null);
790
- const children = this.buildView(chain);
791
- children.forEach(child => {
792
- this.nativeRenderer.appendChild(host, child);
791
+ const atom = new Atom(component, null);
792
+ this.buildView(atom, {
793
+ isParent: true,
794
+ host
793
795
  });
794
796
  }
795
797
  refresh() {
@@ -872,12 +874,17 @@ exports.Renderer = class Renderer {
872
874
  }
873
875
  diff(start, diffAtom, context) {
874
876
  const oldChildren = [];
877
+ let index = 0;
875
878
  while (diffAtom) {
876
- oldChildren.push(diffAtom);
879
+ oldChildren.push({
880
+ index,
881
+ atom: diffAtom
882
+ });
877
883
  diffAtom = diffAtom.sibling;
884
+ index++;
878
885
  }
879
886
  const commits = [];
880
- const addReuseCommit = (start, reusedAtom) => {
887
+ const addUpdateCommit = (start, reusedAtom) => {
881
888
  commits.push(() => {
882
889
  const isComponent = start.jsxNode instanceof Component;
883
890
  if (!isComponent) {
@@ -891,6 +898,10 @@ exports.Renderer = class Renderer {
891
898
  context.host = start.nativeNode;
892
899
  context.isParent = false;
893
900
  }
901
+ let applyRefs = null;
902
+ if (start.jsxNode instanceof JSXElement) {
903
+ applyRefs = this.updateNativeNodeProperties(start.jsxNode, reusedAtom.jsxNode, start.nativeNode);
904
+ }
894
905
  if (start.child) {
895
906
  const childContext = start.jsxNode instanceof JSXElement ? {
896
907
  host: start.nativeNode,
@@ -905,6 +916,9 @@ exports.Renderer = class Renderer {
905
916
  atom = atom.sibling;
906
917
  }
907
918
  }
919
+ if (applyRefs) {
920
+ applyRefs();
921
+ }
908
922
  if (isComponent) {
909
923
  start.jsxNode.rendered();
910
924
  }
@@ -912,31 +926,23 @@ exports.Renderer = class Renderer {
912
926
  };
913
927
  const addCreateCommit = (start) => {
914
928
  commits.push(() => {
915
- const children = this.createViewByAtom(start);
916
- children.forEach(child => {
917
- if (context.isParent) {
918
- this.nativeRenderer.prependChild(context.host, child);
919
- }
920
- else {
921
- this.nativeRenderer.insertAfter(child, context.host);
922
- }
923
- context.host = child;
924
- context.isParent = false;
925
- });
929
+ this.buildView(start, context);
926
930
  });
927
931
  };
932
+ let i = 0;
928
933
  while (start && !start.nativeNode) {
929
- const reusedAtom = this.reuseAndUpdate(start, oldChildren);
934
+ const reusedAtom = this.reuseAndUpdate(start, i, oldChildren);
930
935
  if (reusedAtom) {
931
- addReuseCommit(start, reusedAtom);
936
+ addUpdateCommit(start, reusedAtom);
932
937
  }
933
938
  else {
934
939
  addCreateCommit(start);
935
940
  }
941
+ i++;
936
942
  start = start.sibling;
937
943
  }
938
- for (const atom of oldChildren) {
939
- this.cleanView(atom, false);
944
+ for (const item of oldChildren) {
945
+ this.cleanView(item.atom, false);
940
946
  }
941
947
  for (const commit of commits) {
942
948
  commit();
@@ -962,14 +968,25 @@ exports.Renderer = class Renderer {
962
968
  atom.jsxNode.destroy();
963
969
  }
964
970
  }
965
- reuseAndUpdate(start, oldChildren) {
971
+ reuseAndUpdate(start, lastIndex, oldChildren) {
972
+ let isReuse = false;
966
973
  for (let i = 0; i < oldChildren.length; i++) {
967
- const diffAtom = oldChildren[i];
974
+ const { atom: diffAtom, index: diffIndex } = oldChildren[i];
975
+ const key = start.jsxNode.key;
976
+ const diffKey = diffAtom.jsxNode.key;
977
+ if (key !== undefined && diffKey !== undefined) {
978
+ if (diffKey !== key) {
979
+ continue;
980
+ }
981
+ isReuse = lastIndex > diffIndex;
982
+ }
968
983
  if (start.jsxNode instanceof JSXElement) {
969
984
  if (diffAtom.jsxNode instanceof JSXElement && start.jsxNode.name === diffAtom.jsxNode.name) {
970
985
  const nativeNode = diffAtom.nativeNode;
986
+ if (isReuse) {
987
+ this.nativeRenderer.remove(nativeNode);
988
+ }
971
989
  start.nativeNode = nativeNode;
972
- this.updateNativeNodeProperties(start.jsxNode, diffAtom.jsxNode, nativeNode);
973
990
  oldChildren.splice(i, 1);
974
991
  return diffAtom;
975
992
  }
@@ -987,6 +1004,9 @@ exports.Renderer = class Renderer {
987
1004
  }
988
1005
  else if (diffAtom.jsxNode instanceof Component) {
989
1006
  if (start.jsxNode.setup === diffAtom.jsxNode.setup) {
1007
+ if (isReuse) {
1008
+ this.temporarilyRemove(diffAtom);
1009
+ }
990
1010
  const { isChanged } = getNodeChanges(start.jsxNode, diffAtom.jsxNode);
991
1011
  if (isChanged) {
992
1012
  diffAtom.jsxNode.invokePropsChangedHooks(start.jsxNode.config);
@@ -1010,100 +1030,74 @@ exports.Renderer = class Renderer {
1010
1030
  }
1011
1031
  return null;
1012
1032
  }
1013
- createViewByAtom(atom) {
1014
- if (atom.jsxNode instanceof JSXElement) {
1015
- const nativeNode = this.createElement(atom.jsxNode);
1016
- atom.nativeNode = nativeNode;
1017
- if (atom.child) {
1018
- const children = this.buildView(atom.child);
1019
- for (const child of children) {
1020
- this.nativeRenderer.appendChild(nativeNode, child);
1021
- }
1033
+ temporarilyRemove(atom) {
1034
+ let next = atom.child;
1035
+ while (next) {
1036
+ if (next.jsxNode instanceof Component) {
1037
+ this.temporarilyRemove(next);
1022
1038
  }
1023
- return [nativeNode];
1024
- }
1025
- else if (atom.jsxNode instanceof JSXText) {
1026
- const nativeNode = this.createTextNode(atom.jsxNode);
1027
- atom.nativeNode = nativeNode;
1028
- return [nativeNode];
1029
- }
1030
- const { template, render } = atom.jsxNode.init();
1031
- this.componentAtomCaches.set(atom.jsxNode, {
1032
- atom,
1033
- render
1034
- });
1035
- if (template) {
1036
- this.linkTemplate(template, atom.jsxNode, atom);
1037
- }
1038
- if (atom.child) {
1039
- return this.buildView(atom.child);
1039
+ else {
1040
+ this.nativeRenderer.remove(next.nativeNode);
1041
+ }
1042
+ next = next.sibling;
1040
1043
  }
1041
- return [];
1042
1044
  }
1043
- buildView(chain) {
1044
- const context = [];
1045
- const children = [];
1046
- function getContext() {
1047
- return context[context.length - 1];
1048
- }
1049
- let atom = chain;
1050
- const stopAtom = chain.parent;
1051
- wrap: while (atom) {
1052
- if (atom.jsxNode instanceof Component) {
1053
- this.componentRender(atom.jsxNode, atom);
1054
- if (atom.child) {
1055
- atom = atom.child;
1056
- continue;
1057
- }
1058
- atom.jsxNode.rendered();
1045
+ buildView(atom, context) {
1046
+ if (atom.jsxNode instanceof Component) {
1047
+ this.componentRender(atom.jsxNode, atom);
1048
+ let child = atom.child;
1049
+ while (child) {
1050
+ this.buildView(child, context);
1051
+ child = child.sibling;
1052
+ }
1053
+ atom.jsxNode.rendered();
1054
+ }
1055
+ else {
1056
+ let nativeNode;
1057
+ let applyRefs = null;
1058
+ if (atom.jsxNode instanceof JSXElement) {
1059
+ const { nativeNode: n, applyRefs: a } = this.createElement(atom.jsxNode);
1060
+ nativeNode = n;
1061
+ applyRefs = a;
1059
1062
  }
1060
1063
  else {
1061
- const host = getContext();
1062
- const nativeNode = atom.jsxNode instanceof JSXElement ? this.createElement(atom.jsxNode) : this.createTextNode(atom.jsxNode);
1063
- atom.nativeNode = nativeNode;
1064
- if (host) {
1065
- this.nativeRenderer.appendChild(host, nativeNode);
1066
- }
1067
- else {
1068
- children.push(nativeNode);
1069
- }
1070
- if (atom.child) {
1071
- context.push(nativeNode);
1072
- atom = atom.child;
1073
- continue;
1074
- }
1064
+ nativeNode = this.createTextNode(atom.jsxNode);
1075
1065
  }
1076
- while (atom) {
1077
- if (atom.sibling) {
1078
- atom = atom.sibling;
1079
- break;
1080
- }
1081
- atom = atom.parent;
1082
- const isComponent = (atom === null || atom === void 0 ? void 0 : atom.jsxNode) instanceof Component;
1083
- if (isComponent) {
1084
- atom.jsxNode.rendered();
1085
- }
1086
- if (atom === stopAtom) {
1087
- break wrap;
1088
- }
1089
- if (isComponent) {
1090
- continue;
1066
+ atom.nativeNode = nativeNode;
1067
+ if (context.isParent) {
1068
+ this.nativeRenderer.prependChild(context.host, nativeNode);
1069
+ }
1070
+ else {
1071
+ this.nativeRenderer.insertAfter(nativeNode, context.host);
1072
+ }
1073
+ if (atom.jsxNode instanceof JSXElement) {
1074
+ const childContext = {
1075
+ isParent: true,
1076
+ host: nativeNode
1077
+ };
1078
+ let child = atom.child;
1079
+ while (child) {
1080
+ this.buildView(child, childContext);
1081
+ child = child.sibling;
1091
1082
  }
1092
- context.pop();
1083
+ }
1084
+ context.host = nativeNode;
1085
+ context.isParent = false;
1086
+ if (applyRefs) {
1087
+ applyRefs();
1093
1088
  }
1094
1089
  }
1095
- return children;
1096
1090
  }
1097
- componentRender(component, parent) {
1091
+ componentRender(component, from) {
1098
1092
  const { template, render } = component.init();
1099
1093
  if (template) {
1100
- this.linkTemplate(template, component, parent);
1094
+ this.linkTemplate(template, component, from);
1101
1095
  }
1102
1096
  this.componentAtomCaches.set(component, {
1103
1097
  render,
1104
- atom: parent
1098
+ atom: from
1105
1099
  });
1106
- return parent;
1100
+ return from;
1107
1101
  }
1108
1102
  createChainByComponentFactory(context, factory, parent) {
1109
1103
  const component = factory.createInstance(context);
@@ -1159,25 +1153,27 @@ exports.Renderer = class Renderer {
1159
1153
  createElement(vNode) {
1160
1154
  const nativeNode = this.nativeRenderer.createElement(vNode.name);
1161
1155
  const props = vNode.props;
1162
- if (props) {
1163
- let bindingRefs;
1164
- props.attrs.forEach((value, key) => {
1165
- if (key === refKey) {
1166
- bindingRefs = value;
1167
- return;
1168
- }
1169
- this.nativeRenderer.setProperty(nativeNode, key, value);
1170
- });
1171
- props.styles.forEach((value, key) => {
1172
- this.nativeRenderer.setStyle(nativeNode, key, value);
1173
- });
1174
- props.classes.forEach(k => this.nativeRenderer.addClass(nativeNode, k));
1175
- Object.keys(props.listeners).forEach(type => {
1176
- this.nativeRenderer.listen(nativeNode, type, props.listeners[type]);
1177
- });
1178
- this.applyRefs(bindingRefs, nativeNode, true);
1179
- }
1180
- return nativeNode;
1156
+ let bindingRefs;
1157
+ props.attrs.forEach((value, key) => {
1158
+ if (key === refKey) {
1159
+ bindingRefs = value;
1160
+ return;
1161
+ }
1162
+ this.nativeRenderer.setProperty(nativeNode, key, value);
1163
+ });
1164
+ props.styles.forEach((value, key) => {
1165
+ this.nativeRenderer.setStyle(nativeNode, key, value);
1166
+ });
1167
+ props.classes.forEach(k => this.nativeRenderer.addClass(nativeNode, k));
1168
+ Object.keys(props.listeners).forEach(type => {
1169
+ this.nativeRenderer.listen(nativeNode, type, props.listeners[type]);
1170
+ });
1171
+ return {
1172
+ nativeNode,
1173
+ applyRefs: () => {
1174
+ this.applyRefs(bindingRefs, nativeNode, true);
1175
+ }
1176
+ };
1181
1177
  }
1182
1178
  createTextNode(child) {
1183
1179
  return this.nativeRenderer.createTextNode(child.text);
@@ -1185,7 +1181,7 @@ exports.Renderer = class Renderer {
1185
1181
  updateNativeNodeProperties(newVNode, oldVNode, nativeNode) {
1186
1182
  const { styleChanges, attrChanges, classesChanges, listenerChanges, isChanged } = getNodeChanges(newVNode, oldVNode);
1187
1183
  if (!isChanged) {
1188
- return;
1184
+ return null;
1189
1185
  }
1190
1186
  styleChanges.remove.forEach(i => this.nativeRenderer.removeStyle(nativeNode, i[0]));
1191
1187
  styleChanges.set.forEach(i => this.nativeRenderer.setStyle(nativeNode, i[0], i[1]));
@@ -1213,8 +1209,10 @@ exports.Renderer = class Renderer {
1213
1209
  listenerChanges.add.forEach(i => {
1214
1210
  this.nativeRenderer.listen(nativeNode, i[0], i[1]);
1215
1211
  });
1216
- this.applyRefs(unBindRefs, nativeNode, false);
1217
- this.applyRefs(bindRefs, nativeNode, true);
1212
+ return () => {
1213
+ this.applyRefs(unBindRefs, nativeNode, false);
1214
+ this.applyRefs(bindRefs, nativeNode, true);
1215
+ };
1218
1216
  }
1219
1217
  applyRefs(refs, nativeNode, binding) {
1220
1218
  refs = Array.isArray(refs) ? refs : [refs];
@@ -1,5 +1,5 @@
1
1
  import { Provider, ReflectiveInjector, AbstractType, Type, InjectionToken, InjectFlags, Injector } from '@tanbo/di';
2
- import { JSXProps, JSXElement, Props } from './jsx-element';
2
+ import { JSXProps, JSXElement, Props, Key } from './jsx-element';
3
3
  export declare class JSXComponent {
4
4
  createInstance: (injector: Component) => Component;
5
5
  constructor(createInstance: (injector: Component) => Component);
@@ -14,6 +14,7 @@ export interface ComponentSetup<T extends JSXProps<any> = JSXProps<any>> {
14
14
  export declare class Component extends ReflectiveInjector {
15
15
  setup: ComponentSetup;
16
16
  config?: JSXProps<any> | null | undefined;
17
+ key?: Key | undefined;
17
18
  destroyCallbacks: LifeCycleCallback[];
18
19
  mountCallbacks: LifeCycleCallback[];
19
20
  propsChangedCallbacks: PropsChangedCallback<any>[];
@@ -27,7 +28,7 @@ export declare class Component extends ReflectiveInjector {
27
28
  private updatedDestroyCallbacks;
28
29
  private propsChangedDestroyCallbacks;
29
30
  private isFirstRending;
30
- constructor(context: Injector, setup: ComponentSetup, config?: JSXProps<any> | null | undefined);
31
+ constructor(context: Injector, setup: ComponentSetup, config?: JSXProps<any> | null | undefined, key?: Key | undefined);
31
32
  addProvide<T>(providers: Provider<T> | Provider<T>[]): void;
32
33
  init(): {
33
34
  template: JSXTemplate;
@@ -6,10 +6,11 @@ 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 type Key = number | string;
10
+ export declare function jsx<T extends JSXChildNode>(name: string, config?: JSXProps<T> | null, key?: Key): JSXElement;
11
+ export declare function jsx<T extends JSXChildNode>(setup: ComponentSetup, config?: JSXProps<T> | null, key?: Key): JSXComponent;
12
+ export declare function jsxs<T extends JSXChildNode[]>(name: string, config?: JSXProps<T> | null, key?: Key): JSXElement;
13
+ export declare function jsxs<T extends JSXChildNode[]>(setup: ComponentSetup, config?: JSXProps<T> | null, key?: Key): JSXComponent;
13
14
  export interface VElementListeners {
14
15
  [listenKey: string]: <T extends Event>(ev: T) => any;
15
16
  }
@@ -30,6 +31,7 @@ export declare class Props {
30
31
  export declare class JSXElement {
31
32
  name: string;
32
33
  config?: JSXProps<any> | null | undefined;
34
+ key?: Key | undefined;
33
35
  props: Props;
34
- constructor(name: string, config?: JSXProps<any> | null | undefined);
36
+ constructor(name: string, config?: JSXProps<any> | null | undefined, key?: Key | undefined);
35
37
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viewfly/core",
3
- "version": "0.0.1-alpha.6",
3
+ "version": "0.0.1-alpha.7",
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": "aedb326658afa6a712aebe3f22fe5209ae18a9f9"
40
+ "gitHead": "b4aa728ce10f6aaca2bb2e242c7b8b8f8befbfec"
41
41
  }