@viewfly/core 1.0.1 → 1.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.
@@ -195,6 +195,10 @@ interface Props {
195
195
  children?: JSXNode | JSXNode[];
196
196
  }
197
197
  declare function Fragment(props: Props): () => JSXNode | JSXNode[];
198
+ interface ContextProps extends Props {
199
+ providers: Provider[];
200
+ }
201
+ declare function Context(props: ContextProps): () => JSXNode | JSXNode[];
198
202
  type Key = number | string;
199
203
  declare function jsx(type: string | ComponentSetup, props: Props & Record<string, any>, key?: Key): ViewFlyNode;
200
204
  declare const jsxs: typeof jsx;
@@ -242,7 +246,11 @@ declare namespace JSX {
242
246
  }
243
247
  interface ElementClass<P = any> extends ComponentInstance<P> {
244
248
  }
249
+ interface ElementAttributesProperty {
250
+ props: {};
251
+ }
245
252
  interface ElementChildrenAttribute {
253
+ children: {};
246
254
  }
247
255
  interface IntrinsicElements {
248
256
  [name: string]: any;
@@ -276,7 +284,6 @@ declare class Component extends ReflectiveInjector {
276
284
  props: Props;
277
285
  readonly key?: Key | undefined;
278
286
  instance: ComponentInstance<Props>;
279
- template: JSXNode;
280
287
  changedSubComponents: Set<Component>;
281
288
  get dirty(): boolean;
282
289
  get changed(): boolean;
@@ -294,14 +301,11 @@ declare class Component extends ReflectiveInjector {
294
301
  constructor(parentComponent: Injector | null, type: ComponentSetup, props: Props, key?: Key | undefined);
295
302
  markAsDirtied(): void;
296
303
  markAsChanged(changedComponent?: Component): void;
297
- render(): {
298
- template: JSXNode;
299
- portalHost: NativeNode | undefined;
300
- };
301
- update(newProps: Record<string, any>): JSXNode;
304
+ render(update: (template: JSXNode, portalHost?: NativeNode) => void): void;
305
+ update(newProps: Record<string, any>, updateChildren: (jsxNode: JSXNode) => void, reuseChildren: (skipSubComponentDiff: boolean) => void): void;
302
306
  provide<T>(providers: Provider<T> | Provider<T>[]): void;
303
- rendered(): void;
304
307
  destroy(): void;
308
+ rendered(): void;
305
309
  private invokePropsChangedHooks;
306
310
  private invokeMountHooks;
307
311
  private invokeUpdatedHooks;
@@ -559,7 +563,7 @@ interface ComponentAtom {
559
563
  }
560
564
  type Atom = TextAtom | ElementAtom | ComponentAtom;
561
565
  interface ComponentView {
562
- atom: Atom;
566
+ atom: ComponentAtom;
563
567
  host: NativeNode;
564
568
  isParent: boolean;
565
569
  rootHost: NativeNode;
@@ -592,4 +596,4 @@ interface Module {
592
596
  }
593
597
  declare function viewfly<T extends NativeNode>(config: Config): Application<T>;
594
598
 
595
- export { type AbstractInstanceType, type AbstractProvider, type AbstractType, type Application, type Atom, type ClassNames, type ClassProvider, Component, type ComponentAnnotation, type ComponentInstance, type ComponentSetup, type ComponentView, type Config, type ConstructorProvider, DynamicRef, type ExistingProvider, type ExtractInstanceType, type ExtractValueType, type FactoryProvider, ForwardRef, Fragment, Inject, type InjectDecorator, InjectFlags, Injectable, type InjectableDecorator, type InjectableOptions, InjectionToken, Injector, JSX, type JSXNode, JSXNodeFactory, type Key, type LifeCycleCallback, type Module, type NativeNode, NativeRenderer, type NormalizedProvider, NullInjector, Optional, type OptionalDecorator, Prop, type PropDecorator, type Props, type PropsChangedCallback, type ProvideScope, type Provider, type RefListener, type ReflectiveDependency, ReflectiveInjector, RootComponent, Scope, Self, type SelfDecorator, type Signal, SkipSelf, type SkipSelfDecorator, type StaticProvider, StaticRef, THROW_IF_NOT_FOUND, Type, type TypeProvider, type ValueProvider, type ViewFlyNode, type WatchCallback, createDerived, createDynamicRef, createRef, createRenderer, createSignal, forwardRef, getCurrentInstance, inject, jsx, jsxs, makeError, normalizeProvider, onMounted, onPropsChanged, onUnmounted, onUpdated, viewfly, watch, withAnnotation, withMemo };
599
+ export { type AbstractInstanceType, type AbstractProvider, type AbstractType, type Application, type Atom, type ClassNames, type ClassProvider, Component, type ComponentAnnotation, type ComponentInstance, type ComponentSetup, type ComponentView, type Config, type ConstructorProvider, Context, type ContextProps, DynamicRef, type ExistingProvider, type ExtractInstanceType, type ExtractValueType, type FactoryProvider, ForwardRef, Fragment, Inject, type InjectDecorator, InjectFlags, Injectable, type InjectableDecorator, type InjectableOptions, InjectionToken, Injector, JSX, type JSXNode, JSXNodeFactory, type Key, type LifeCycleCallback, type Module, type NativeNode, NativeRenderer, type NormalizedProvider, NullInjector, Optional, type OptionalDecorator, Prop, type PropDecorator, type Props, type PropsChangedCallback, type ProvideScope, type Provider, type RefListener, type ReflectiveDependency, ReflectiveInjector, RootComponent, Scope, Self, type SelfDecorator, type Signal, SkipSelf, type SkipSelfDecorator, type StaticProvider, StaticRef, THROW_IF_NOT_FOUND, Type, type TypeProvider, type ValueProvider, type ViewFlyNode, type WatchCallback, createDerived, createDynamicRef, createRef, createRenderer, createSignal, forwardRef, getCurrentInstance, inject, jsx, jsxs, makeError, normalizeProvider, onMounted, onPropsChanged, onUnmounted, onUpdated, viewfly, watch, withAnnotation, withMemo };
@@ -692,7 +692,7 @@ class Component extends ReflectiveInjector {
692
692
  this.parentComponent.markAsChanged(this);
693
693
  }
694
694
  }
695
- render() {
695
+ render(update) {
696
696
  const self = this;
697
697
  const proxiesProps = new Proxy(this.props, {
698
698
  get(_, key) {
@@ -734,19 +734,22 @@ class Component extends ReflectiveInjector {
734
734
  this.unWatch = watch(Array.from(new Set(deps)), () => {
735
735
  this.markAsDirtied();
736
736
  });
737
- this.template = template;
738
- return {
739
- template: template,
740
- portalHost: this.instance.$portalHost
741
- };
737
+ update(template, this.instance.$portalHost);
738
+ this.rendered();
742
739
  }
743
- update(newProps) {
740
+ update(newProps, updateChildren, reuseChildren) {
744
741
  const oldProps = this.props;
745
742
  if (newProps !== oldProps) {
746
743
  const { add, remove, replace } = getObjectChanges(newProps, oldProps);
747
744
  if (add.length || remove.length || replace.length) {
748
745
  this.invokePropsChangedHooks(newProps);
749
746
  }
747
+ else if (!this.dirty) {
748
+ this.props = newProps;
749
+ reuseChildren(false);
750
+ this.rendered();
751
+ return;
752
+ }
750
753
  const newRefs = toRefs(newProps.ref);
751
754
  if (this.refs) {
752
755
  for (const oldRef of this.refs) {
@@ -764,39 +767,25 @@ class Component extends ReflectiveInjector {
764
767
  }
765
768
  if (typeof this.instance.$useMemo === 'function') {
766
769
  if (this.instance.$useMemo(newProps, oldProps)) {
767
- return this.template;
770
+ reuseChildren(true);
771
+ this.rendered();
772
+ return;
768
773
  }
769
774
  }
770
775
  this.unWatch();
771
776
  signalDepsStack.push([]);
772
- this.template = this.instance.$render();
777
+ const template = this.instance.$render();
773
778
  const deps = signalDepsStack.pop();
774
779
  this.unWatch = watch(Array.from(new Set(deps)), () => {
775
780
  this.markAsDirtied();
776
781
  });
777
- return this.template;
782
+ updateChildren(template);
783
+ this.rendered();
778
784
  }
779
785
  provide(providers) {
780
786
  providers = Array.isArray(providers) ? providers : [providers];
781
787
  this.normalizedProviders.unshift(...providers.map(i => normalizeProvider(i)));
782
788
  }
783
- rendered() {
784
- this.changedSubComponents.clear();
785
- const is = this.isFirstRendering;
786
- this.isFirstRendering = false;
787
- this._dirty = this._changed = false;
788
- this.invokeUpdatedHooks();
789
- if (is) {
790
- this.invokeMountHooks();
791
- }
792
- if (this.changed) {
793
- Promise.resolve().then(() => {
794
- if (this.parentComponent instanceof Component) {
795
- this.parentComponent.markAsChanged(this);
796
- }
797
- });
798
- }
799
- }
800
789
  destroy() {
801
790
  var _a, _b, _c;
802
791
  this.unWatch();
@@ -816,6 +805,23 @@ class Component extends ReflectiveInjector {
816
805
  this.propsChangedCallbacks =
817
806
  this.unmountedCallbacks = null;
818
807
  }
808
+ rendered() {
809
+ this.changedSubComponents.clear();
810
+ const is = this.isFirstRendering;
811
+ this.isFirstRendering = false;
812
+ this._dirty = this._changed = false;
813
+ this.invokeUpdatedHooks();
814
+ if (is) {
815
+ this.invokeMountHooks();
816
+ }
817
+ if (this.changed) {
818
+ Promise.resolve().then(() => {
819
+ if (this.parentComponent instanceof Component) {
820
+ this.parentComponent.markAsChanged(this);
821
+ }
822
+ });
823
+ }
824
+ }
819
825
  invokePropsChangedHooks(newProps) {
820
826
  const oldProps = this.props;
821
827
  this.props = newProps;
@@ -1259,6 +1265,13 @@ function Fragment(props) {
1259
1265
  return props.children;
1260
1266
  };
1261
1267
  }
1268
+ function Context(props) {
1269
+ const instance = getCurrentInstance();
1270
+ instance.provide(props.providers);
1271
+ return () => {
1272
+ return props.children;
1273
+ };
1274
+ }
1262
1275
  function jsx(type, props, key) {
1263
1276
  return JSXNodeFactory.createNode(type, props, key);
1264
1277
  }
@@ -1304,7 +1317,7 @@ function createRenderer(component, nativeRenderer) {
1304
1317
  });
1305
1318
  }
1306
1319
  else {
1307
- updateView(nativeRenderer, component);
1320
+ updateView(nativeRenderer, component, false);
1308
1321
  }
1309
1322
  };
1310
1323
  }
@@ -1323,46 +1336,43 @@ function buildView(nativeRenderer, parentComponent, atom, context) {
1323
1336
  }
1324
1337
  }
1325
1338
  function buildElementChildren(atom, nativeRenderer, parentComponent, context) {
1326
- const childContext = {
1327
- isParent: true,
1328
- host: atom.nativeNode,
1329
- rootHost: context.rootHost
1330
- };
1331
1339
  let child = atom.child;
1332
1340
  while (child) {
1333
- buildView(nativeRenderer, parentComponent, child, childContext);
1341
+ buildView(nativeRenderer, parentComponent, child, context);
1334
1342
  child = child.sibling;
1335
1343
  }
1336
1344
  }
1337
- function updateView(nativeRenderer, component) {
1345
+ function updateView(nativeRenderer, component, needMove) {
1338
1346
  if (component.dirty) {
1339
- applyChanges(nativeRenderer, component);
1340
- component.rendered();
1347
+ const { atom, host, isParent, rootHost } = componentViewCache.get(component);
1348
+ applyChanges(nativeRenderer, component, atom, {
1349
+ host,
1350
+ isParent,
1351
+ rootHost
1352
+ }, needMove);
1341
1353
  }
1342
1354
  else if (component.changed) {
1343
1355
  component.changedSubComponents.forEach(child => {
1344
- updateView(nativeRenderer, child);
1356
+ updateView(nativeRenderer, child, needMove);
1345
1357
  });
1346
1358
  component.rendered();
1347
1359
  }
1348
1360
  }
1349
- function applyChanges(nativeRenderer, component) {
1350
- const { atom, host, isParent, rootHost } = componentViewCache.get(component);
1361
+ function applyChanges(nativeRenderer, component, atom, context, needMove) {
1351
1362
  const diffAtom = atom.child;
1352
- const template = component.update(component.props);
1353
- atom.child = createChildChain(template, atom.isSvg);
1354
- const context = {
1355
- host,
1356
- isParent,
1357
- rootHost
1358
- };
1359
- diff(nativeRenderer, component, atom.child, diffAtom, context, false);
1360
- const next = atom.sibling;
1361
- if (next && next.jsxNode instanceof Component) {
1362
- const view = componentViewCache.get(next.jsxNode);
1363
- view.host = context.host;
1364
- view.isParent = context.isParent;
1365
- }
1363
+ component.update(component.props, newTemplate => {
1364
+ atom.child = createChildChain(newTemplate, atom.isSvg);
1365
+ diff(nativeRenderer, component, atom.child, diffAtom, context, needMove);
1366
+ const next = atom.sibling;
1367
+ if (next && next.jsxNode instanceof Component) {
1368
+ const view = componentViewCache.get(next.jsxNode);
1369
+ view.host = context.host;
1370
+ view.isParent = context.isParent;
1371
+ }
1372
+ }, () => {
1373
+ // console.log(skipSubComponentDiff, '----')
1374
+ //
1375
+ });
1366
1376
  }
1367
1377
  function diff(nativeRenderer, parentComponent, newAtom, oldAtom, context, needMove) {
1368
1378
  const commits = [];
@@ -1447,54 +1457,60 @@ function updateElement(newAtom, oldAtom, nativeRenderer, context, parentComponen
1447
1457
  }
1448
1458
  context.host = newAtom.nativeNode;
1449
1459
  context.isParent = false;
1450
- updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComponent, context);
1460
+ updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComponent, {
1461
+ host: newAtom.nativeNode,
1462
+ isParent: true,
1463
+ rootHost: context.rootHost
1464
+ });
1451
1465
  };
1452
1466
  }
1453
1467
  function updateComponent(newAtom, reusedAtom, nativeRenderer, context) {
1454
1468
  return function (offset, needMove) {
1455
1469
  const component = reusedAtom.jsxNode;
1456
1470
  const newProps = newAtom.jsxNode.props;
1457
- const oldTemplate = component.template;
1458
- const newTemplate = component.update(newProps);
1459
1471
  const portalHost = component.instance.$portalHost;
1460
1472
  context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1461
1473
  componentViewCache.set(component, Object.assign({ atom: newAtom }, context));
1462
1474
  newAtom.jsxNode = component;
1463
- if (newTemplate === oldTemplate) {
1464
- newAtom.child = reusedAtom.child;
1465
- reuseComponentView(nativeRenderer, newAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index);
1466
- component.rendered();
1467
- return;
1468
- }
1469
- if (newTemplate) {
1470
- newAtom.child = createChildChain(newTemplate, newAtom.isSvg);
1471
- }
1472
- if (newAtom.child) {
1473
- diff(nativeRenderer, component, newAtom.child, reusedAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index);
1474
- }
1475
- else if (reusedAtom.child) {
1476
- let atom = reusedAtom.child;
1477
- while (atom) {
1478
- cleanView(nativeRenderer, atom, true);
1479
- atom = atom.sibling;
1475
+ component.update(newProps, newTemplate => {
1476
+ if (newTemplate) {
1477
+ newAtom.child = createChildChain(newTemplate, newAtom.isSvg);
1480
1478
  }
1481
- }
1482
- component.rendered();
1479
+ if (newAtom.child) {
1480
+ diff(nativeRenderer, component, newAtom.child, reusedAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index);
1481
+ }
1482
+ else if (reusedAtom.child) {
1483
+ let atom = reusedAtom.child;
1484
+ while (atom) {
1485
+ cleanView(nativeRenderer, atom, true);
1486
+ atom = atom.sibling;
1487
+ }
1488
+ }
1489
+ }, (skipSubComponentDiff) => {
1490
+ newAtom.child = reusedAtom.child;
1491
+ reuseComponentView(nativeRenderer, newAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index, skipSubComponentDiff);
1492
+ });
1483
1493
  };
1484
1494
  }
1485
- function reuseComponentView(nativeRenderer, child, context, moveView) {
1495
+ function reuseComponentView(nativeRenderer, child, context, moveView, skipSubComponentDiff) {
1486
1496
  const updateContext = (atom) => {
1487
1497
  if (atom.jsxNode instanceof Component) {
1488
- let child = atom.child;
1489
- while (child) {
1490
- updateContext(child);
1491
- child = child.sibling;
1498
+ if (skipSubComponentDiff || !moveView) {
1499
+ let child = atom.child;
1500
+ while (child) {
1501
+ updateContext(child);
1502
+ child = child.sibling;
1503
+ }
1504
+ }
1505
+ else {
1506
+ applyChanges(nativeRenderer, atom.jsxNode, atom, context, true);
1492
1507
  }
1493
1508
  }
1494
1509
  else {
1495
1510
  if (moveView) {
1496
1511
  insertNode(nativeRenderer, atom, context);
1497
1512
  }
1513
+ reuseElementChildrenView(nativeRenderer, atom);
1498
1514
  context.isParent = false;
1499
1515
  context.host = atom.nativeNode;
1500
1516
  }
@@ -1504,6 +1520,18 @@ function reuseComponentView(nativeRenderer, child, context, moveView) {
1504
1520
  child = child.sibling;
1505
1521
  }
1506
1522
  }
1523
+ function reuseElementChildrenView(nativeRenderer, atom, context, skipSubComponentDiff) {
1524
+ let child = atom.child;
1525
+ while (child) {
1526
+ if (child.jsxNode instanceof Component) {
1527
+ updateView(nativeRenderer, child.jsxNode, false);
1528
+ }
1529
+ else {
1530
+ reuseElementChildrenView(nativeRenderer, child);
1531
+ }
1532
+ child = child.sibling;
1533
+ }
1534
+ }
1507
1535
  function cleanElementChildren(atom, nativeRenderer) {
1508
1536
  let child = atom.child;
1509
1537
  nativeRenderer.cleanChildren(atom.nativeNode, atom.isSvg);
@@ -1536,16 +1564,16 @@ function cleanView(nativeRenderer, atom, needClean) {
1536
1564
  }
1537
1565
  }
1538
1566
  function componentRender(nativeRenderer, component, from, context) {
1539
- const { template, portalHost } = component.render();
1540
- from.child = createChildChain(template, from.isSvg);
1541
- context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1542
- componentViewCache.set(component, Object.assign({ atom: from }, context));
1543
- let child = from.child;
1544
- while (child) {
1545
- buildView(nativeRenderer, component, child, context);
1546
- child = child.sibling;
1547
- }
1548
- component.rendered();
1567
+ component.render((template, portalHost) => {
1568
+ from.child = createChildChain(template, from.isSvg);
1569
+ context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1570
+ componentViewCache.set(component, Object.assign({ atom: from }, context));
1571
+ let child = from.child;
1572
+ while (child) {
1573
+ buildView(nativeRenderer, component, child, context);
1574
+ child = child.sibling;
1575
+ }
1576
+ });
1549
1577
  }
1550
1578
  function createChainByJSXNode(type, jsxNode, nodeType, prevAtom, isSvg, key) {
1551
1579
  const atom = {
@@ -1648,7 +1676,11 @@ function createElement(nativeRenderer, atom, parentComponent, context) {
1648
1676
  }
1649
1677
  atom.nativeNode = nativeNode;
1650
1678
  insertNode(nativeRenderer, atom, context);
1651
- buildElementChildren(atom, nativeRenderer, parentComponent, context);
1679
+ buildElementChildren(atom, nativeRenderer, parentComponent, {
1680
+ isParent: true,
1681
+ host: nativeNode,
1682
+ rootHost: context.rootHost
1683
+ });
1652
1684
  context.host = nativeNode;
1653
1685
  context.isParent = false;
1654
1686
  applyRefs(bindingRefs, nativeNode, true);
@@ -1666,14 +1698,18 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1666
1698
  const nativeNode = newAtom.nativeNode;
1667
1699
  const oldVNode = oldAtom.jsxNode;
1668
1700
  if (newVNode === oldVNode) {
1669
- updateElementChildren(newAtom, oldAtom, nativeRenderer, parentComponent, context, isSvg);
1701
+ newAtom.child = oldAtom.child;
1702
+ reuseElementChildrenView(nativeRenderer, newAtom);
1670
1703
  return;
1671
1704
  }
1672
1705
  const changes = getObjectChanges(newVNode.props, oldVNode.props);
1673
1706
  let unBindRefs;
1674
1707
  let bindRefs;
1708
+ let updatedChildren = false;
1675
1709
  for (const [key, value] of changes.remove) {
1676
1710
  if (key === 'children') {
1711
+ updatedChildren = true;
1712
+ cleanElementChildren(oldAtom, nativeRenderer);
1677
1713
  continue;
1678
1714
  }
1679
1715
  if (key === 'class') {
@@ -1700,6 +1736,14 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1700
1736
  }
1701
1737
  for (const [key, newValue, oldValue] of changes.replace) {
1702
1738
  if (key === 'children') {
1739
+ updatedChildren = true;
1740
+ newAtom.child = createChildChain(newValue, isSvg);
1741
+ if (!newAtom.child) {
1742
+ cleanElementChildren(oldAtom, nativeRenderer);
1743
+ }
1744
+ else {
1745
+ diff(nativeRenderer, parentComponent, newAtom.child, oldAtom.child, context, false);
1746
+ }
1703
1747
  continue;
1704
1748
  }
1705
1749
  if (key === 'class') {
@@ -1734,6 +1778,9 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1734
1778
  }
1735
1779
  for (const [key, value] of changes.add) {
1736
1780
  if (key === 'children') {
1781
+ updatedChildren = true;
1782
+ newAtom.child = createChildChain(value, isSvg);
1783
+ buildElementChildren(newAtom, nativeRenderer, parentComponent, context);
1737
1784
  continue;
1738
1785
  }
1739
1786
  if (key === 'class') {
@@ -1759,40 +1806,13 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1759
1806
  }
1760
1807
  nativeRenderer.setProperty(nativeNode, key, value, isSvg);
1761
1808
  }
1762
- updateElementChildren(newAtom, oldAtom, nativeRenderer, parentComponent, context, isSvg);
1809
+ if (!updatedChildren) {
1810
+ newAtom.child = oldAtom.child;
1811
+ reuseElementChildrenView(nativeRenderer, newAtom);
1812
+ }
1763
1813
  applyRefs(unBindRefs, nativeNode, false);
1764
1814
  applyRefs(bindRefs, nativeNode, true);
1765
1815
  }
1766
- function updateElementChildren(newAtom, oldAtom, nativeRenderer, parentComponent, context, isSvg) {
1767
- /**
1768
- * 不能仅依赖 children 是否相等的判断来确定是否要继续向下 diff
1769
- * 如:
1770
- * ```tsx
1771
- * <Comp>
1772
- * <div>
1773
- * {props.children}
1774
- * </div>
1775
- * </Comp>
1776
- * ```
1777
- * 其中当 Comp 产生变化时,children 来自父组件,这时 children 是相等的,
1778
- * 但,children 内可能有子组件也发生了变化,如果不继续 diff,那么,子组件
1779
- * 的视图更新将不会发生
1780
- */
1781
- newAtom.child = createChildChain(newAtom.jsxNode.props.children, isSvg);
1782
- if (!newAtom.child) {
1783
- // 防止删除用户手动添加的元素
1784
- if (oldAtom.child) {
1785
- cleanElementChildren(oldAtom, nativeRenderer);
1786
- }
1787
- }
1788
- else {
1789
- diff(nativeRenderer, parentComponent, newAtom.child, oldAtom.child, {
1790
- host: newAtom.nativeNode,
1791
- isParent: true,
1792
- rootHost: context.rootHost
1793
- }, false);
1794
- }
1795
- }
1796
1816
  function applyRefs(refs, nativeNode, binding) {
1797
1817
  if (refs) {
1798
1818
  const refList = Array.isArray(refs) ? refs : [refs];
@@ -1908,4 +1928,4 @@ function viewfly(config) {
1908
1928
  return app;
1909
1929
  }
1910
1930
 
1911
- export { Component, DynamicRef, ForwardRef, Fragment, Inject, InjectFlags, Injectable, InjectionToken, Injector, JSXNodeFactory, NativeRenderer, NullInjector, Optional, Prop, ReflectiveInjector, RootComponent, Scope, Self, SkipSelf, StaticRef, THROW_IF_NOT_FOUND, Type, createDerived, createDynamicRef, createRef, createRenderer, createSignal, forwardRef, getCurrentInstance, inject, jsx, jsxs, makeError, normalizeProvider, onMounted, onPropsChanged, onUnmounted, onUpdated, viewfly, watch, withAnnotation, withMemo };
1931
+ export { Component, Context, DynamicRef, ForwardRef, Fragment, Inject, InjectFlags, Injectable, InjectionToken, Injector, JSXNodeFactory, NativeRenderer, NullInjector, Optional, Prop, ReflectiveInjector, RootComponent, Scope, Self, SkipSelf, StaticRef, THROW_IF_NOT_FOUND, Type, createDerived, createDynamicRef, createRef, createRenderer, createSignal, forwardRef, getCurrentInstance, inject, jsx, jsxs, makeError, normalizeProvider, onMounted, onPropsChanged, onUnmounted, onUpdated, viewfly, watch, withAnnotation, withMemo };
package/bundles/index.js CHANGED
@@ -694,7 +694,7 @@ class Component extends ReflectiveInjector {
694
694
  this.parentComponent.markAsChanged(this);
695
695
  }
696
696
  }
697
- render() {
697
+ render(update) {
698
698
  const self = this;
699
699
  const proxiesProps = new Proxy(this.props, {
700
700
  get(_, key) {
@@ -736,19 +736,22 @@ class Component extends ReflectiveInjector {
736
736
  this.unWatch = watch(Array.from(new Set(deps)), () => {
737
737
  this.markAsDirtied();
738
738
  });
739
- this.template = template;
740
- return {
741
- template: template,
742
- portalHost: this.instance.$portalHost
743
- };
739
+ update(template, this.instance.$portalHost);
740
+ this.rendered();
744
741
  }
745
- update(newProps) {
742
+ update(newProps, updateChildren, reuseChildren) {
746
743
  const oldProps = this.props;
747
744
  if (newProps !== oldProps) {
748
745
  const { add, remove, replace } = getObjectChanges(newProps, oldProps);
749
746
  if (add.length || remove.length || replace.length) {
750
747
  this.invokePropsChangedHooks(newProps);
751
748
  }
749
+ else if (!this.dirty) {
750
+ this.props = newProps;
751
+ reuseChildren(false);
752
+ this.rendered();
753
+ return;
754
+ }
752
755
  const newRefs = toRefs(newProps.ref);
753
756
  if (this.refs) {
754
757
  for (const oldRef of this.refs) {
@@ -766,39 +769,25 @@ class Component extends ReflectiveInjector {
766
769
  }
767
770
  if (typeof this.instance.$useMemo === 'function') {
768
771
  if (this.instance.$useMemo(newProps, oldProps)) {
769
- return this.template;
772
+ reuseChildren(true);
773
+ this.rendered();
774
+ return;
770
775
  }
771
776
  }
772
777
  this.unWatch();
773
778
  signalDepsStack.push([]);
774
- this.template = this.instance.$render();
779
+ const template = this.instance.$render();
775
780
  const deps = signalDepsStack.pop();
776
781
  this.unWatch = watch(Array.from(new Set(deps)), () => {
777
782
  this.markAsDirtied();
778
783
  });
779
- return this.template;
784
+ updateChildren(template);
785
+ this.rendered();
780
786
  }
781
787
  provide(providers) {
782
788
  providers = Array.isArray(providers) ? providers : [providers];
783
789
  this.normalizedProviders.unshift(...providers.map(i => normalizeProvider(i)));
784
790
  }
785
- rendered() {
786
- this.changedSubComponents.clear();
787
- const is = this.isFirstRendering;
788
- this.isFirstRendering = false;
789
- this._dirty = this._changed = false;
790
- this.invokeUpdatedHooks();
791
- if (is) {
792
- this.invokeMountHooks();
793
- }
794
- if (this.changed) {
795
- Promise.resolve().then(() => {
796
- if (this.parentComponent instanceof Component) {
797
- this.parentComponent.markAsChanged(this);
798
- }
799
- });
800
- }
801
- }
802
791
  destroy() {
803
792
  var _a, _b, _c;
804
793
  this.unWatch();
@@ -818,6 +807,23 @@ class Component extends ReflectiveInjector {
818
807
  this.propsChangedCallbacks =
819
808
  this.unmountedCallbacks = null;
820
809
  }
810
+ rendered() {
811
+ this.changedSubComponents.clear();
812
+ const is = this.isFirstRendering;
813
+ this.isFirstRendering = false;
814
+ this._dirty = this._changed = false;
815
+ this.invokeUpdatedHooks();
816
+ if (is) {
817
+ this.invokeMountHooks();
818
+ }
819
+ if (this.changed) {
820
+ Promise.resolve().then(() => {
821
+ if (this.parentComponent instanceof Component) {
822
+ this.parentComponent.markAsChanged(this);
823
+ }
824
+ });
825
+ }
826
+ }
821
827
  invokePropsChangedHooks(newProps) {
822
828
  const oldProps = this.props;
823
829
  this.props = newProps;
@@ -1261,6 +1267,13 @@ function Fragment(props) {
1261
1267
  return props.children;
1262
1268
  };
1263
1269
  }
1270
+ function Context(props) {
1271
+ const instance = getCurrentInstance();
1272
+ instance.provide(props.providers);
1273
+ return () => {
1274
+ return props.children;
1275
+ };
1276
+ }
1264
1277
  function jsx(type, props, key) {
1265
1278
  return JSXNodeFactory.createNode(type, props, key);
1266
1279
  }
@@ -1306,7 +1319,7 @@ function createRenderer(component, nativeRenderer) {
1306
1319
  });
1307
1320
  }
1308
1321
  else {
1309
- updateView(nativeRenderer, component);
1322
+ updateView(nativeRenderer, component, false);
1310
1323
  }
1311
1324
  };
1312
1325
  }
@@ -1325,46 +1338,43 @@ function buildView(nativeRenderer, parentComponent, atom, context) {
1325
1338
  }
1326
1339
  }
1327
1340
  function buildElementChildren(atom, nativeRenderer, parentComponent, context) {
1328
- const childContext = {
1329
- isParent: true,
1330
- host: atom.nativeNode,
1331
- rootHost: context.rootHost
1332
- };
1333
1341
  let child = atom.child;
1334
1342
  while (child) {
1335
- buildView(nativeRenderer, parentComponent, child, childContext);
1343
+ buildView(nativeRenderer, parentComponent, child, context);
1336
1344
  child = child.sibling;
1337
1345
  }
1338
1346
  }
1339
- function updateView(nativeRenderer, component) {
1347
+ function updateView(nativeRenderer, component, needMove) {
1340
1348
  if (component.dirty) {
1341
- applyChanges(nativeRenderer, component);
1342
- component.rendered();
1349
+ const { atom, host, isParent, rootHost } = componentViewCache.get(component);
1350
+ applyChanges(nativeRenderer, component, atom, {
1351
+ host,
1352
+ isParent,
1353
+ rootHost
1354
+ }, needMove);
1343
1355
  }
1344
1356
  else if (component.changed) {
1345
1357
  component.changedSubComponents.forEach(child => {
1346
- updateView(nativeRenderer, child);
1358
+ updateView(nativeRenderer, child, needMove);
1347
1359
  });
1348
1360
  component.rendered();
1349
1361
  }
1350
1362
  }
1351
- function applyChanges(nativeRenderer, component) {
1352
- const { atom, host, isParent, rootHost } = componentViewCache.get(component);
1363
+ function applyChanges(nativeRenderer, component, atom, context, needMove) {
1353
1364
  const diffAtom = atom.child;
1354
- const template = component.update(component.props);
1355
- atom.child = createChildChain(template, atom.isSvg);
1356
- const context = {
1357
- host,
1358
- isParent,
1359
- rootHost
1360
- };
1361
- diff(nativeRenderer, component, atom.child, diffAtom, context, false);
1362
- const next = atom.sibling;
1363
- if (next && next.jsxNode instanceof Component) {
1364
- const view = componentViewCache.get(next.jsxNode);
1365
- view.host = context.host;
1366
- view.isParent = context.isParent;
1367
- }
1365
+ component.update(component.props, newTemplate => {
1366
+ atom.child = createChildChain(newTemplate, atom.isSvg);
1367
+ diff(nativeRenderer, component, atom.child, diffAtom, context, needMove);
1368
+ const next = atom.sibling;
1369
+ if (next && next.jsxNode instanceof Component) {
1370
+ const view = componentViewCache.get(next.jsxNode);
1371
+ view.host = context.host;
1372
+ view.isParent = context.isParent;
1373
+ }
1374
+ }, () => {
1375
+ // console.log(skipSubComponentDiff, '----')
1376
+ //
1377
+ });
1368
1378
  }
1369
1379
  function diff(nativeRenderer, parentComponent, newAtom, oldAtom, context, needMove) {
1370
1380
  const commits = [];
@@ -1449,54 +1459,60 @@ function updateElement(newAtom, oldAtom, nativeRenderer, context, parentComponen
1449
1459
  }
1450
1460
  context.host = newAtom.nativeNode;
1451
1461
  context.isParent = false;
1452
- updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComponent, context);
1462
+ updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComponent, {
1463
+ host: newAtom.nativeNode,
1464
+ isParent: true,
1465
+ rootHost: context.rootHost
1466
+ });
1453
1467
  };
1454
1468
  }
1455
1469
  function updateComponent(newAtom, reusedAtom, nativeRenderer, context) {
1456
1470
  return function (offset, needMove) {
1457
1471
  const component = reusedAtom.jsxNode;
1458
1472
  const newProps = newAtom.jsxNode.props;
1459
- const oldTemplate = component.template;
1460
- const newTemplate = component.update(newProps);
1461
1473
  const portalHost = component.instance.$portalHost;
1462
1474
  context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1463
1475
  componentViewCache.set(component, Object.assign({ atom: newAtom }, context));
1464
1476
  newAtom.jsxNode = component;
1465
- if (newTemplate === oldTemplate) {
1466
- newAtom.child = reusedAtom.child;
1467
- reuseComponentView(nativeRenderer, newAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index);
1468
- component.rendered();
1469
- return;
1470
- }
1471
- if (newTemplate) {
1472
- newAtom.child = createChildChain(newTemplate, newAtom.isSvg);
1473
- }
1474
- if (newAtom.child) {
1475
- diff(nativeRenderer, component, newAtom.child, reusedAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index);
1476
- }
1477
- else if (reusedAtom.child) {
1478
- let atom = reusedAtom.child;
1479
- while (atom) {
1480
- cleanView(nativeRenderer, atom, true);
1481
- atom = atom.sibling;
1477
+ component.update(newProps, newTemplate => {
1478
+ if (newTemplate) {
1479
+ newAtom.child = createChildChain(newTemplate, newAtom.isSvg);
1482
1480
  }
1483
- }
1484
- component.rendered();
1481
+ if (newAtom.child) {
1482
+ diff(nativeRenderer, component, newAtom.child, reusedAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index);
1483
+ }
1484
+ else if (reusedAtom.child) {
1485
+ let atom = reusedAtom.child;
1486
+ while (atom) {
1487
+ cleanView(nativeRenderer, atom, true);
1488
+ atom = atom.sibling;
1489
+ }
1490
+ }
1491
+ }, (skipSubComponentDiff) => {
1492
+ newAtom.child = reusedAtom.child;
1493
+ reuseComponentView(nativeRenderer, newAtom.child, context, needMove || newAtom.index - offset !== reusedAtom.index, skipSubComponentDiff);
1494
+ });
1485
1495
  };
1486
1496
  }
1487
- function reuseComponentView(nativeRenderer, child, context, moveView) {
1497
+ function reuseComponentView(nativeRenderer, child, context, moveView, skipSubComponentDiff) {
1488
1498
  const updateContext = (atom) => {
1489
1499
  if (atom.jsxNode instanceof Component) {
1490
- let child = atom.child;
1491
- while (child) {
1492
- updateContext(child);
1493
- child = child.sibling;
1500
+ if (skipSubComponentDiff || !moveView) {
1501
+ let child = atom.child;
1502
+ while (child) {
1503
+ updateContext(child);
1504
+ child = child.sibling;
1505
+ }
1506
+ }
1507
+ else {
1508
+ applyChanges(nativeRenderer, atom.jsxNode, atom, context, true);
1494
1509
  }
1495
1510
  }
1496
1511
  else {
1497
1512
  if (moveView) {
1498
1513
  insertNode(nativeRenderer, atom, context);
1499
1514
  }
1515
+ reuseElementChildrenView(nativeRenderer, atom);
1500
1516
  context.isParent = false;
1501
1517
  context.host = atom.nativeNode;
1502
1518
  }
@@ -1506,6 +1522,18 @@ function reuseComponentView(nativeRenderer, child, context, moveView) {
1506
1522
  child = child.sibling;
1507
1523
  }
1508
1524
  }
1525
+ function reuseElementChildrenView(nativeRenderer, atom, context, skipSubComponentDiff) {
1526
+ let child = atom.child;
1527
+ while (child) {
1528
+ if (child.jsxNode instanceof Component) {
1529
+ updateView(nativeRenderer, child.jsxNode, false);
1530
+ }
1531
+ else {
1532
+ reuseElementChildrenView(nativeRenderer, child);
1533
+ }
1534
+ child = child.sibling;
1535
+ }
1536
+ }
1509
1537
  function cleanElementChildren(atom, nativeRenderer) {
1510
1538
  let child = atom.child;
1511
1539
  nativeRenderer.cleanChildren(atom.nativeNode, atom.isSvg);
@@ -1538,16 +1566,16 @@ function cleanView(nativeRenderer, atom, needClean) {
1538
1566
  }
1539
1567
  }
1540
1568
  function componentRender(nativeRenderer, component, from, context) {
1541
- const { template, portalHost } = component.render();
1542
- from.child = createChildChain(template, from.isSvg);
1543
- context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1544
- componentViewCache.set(component, Object.assign({ atom: from }, context));
1545
- let child = from.child;
1546
- while (child) {
1547
- buildView(nativeRenderer, component, child, context);
1548
- child = child.sibling;
1549
- }
1550
- component.rendered();
1569
+ component.render((template, portalHost) => {
1570
+ from.child = createChildChain(template, from.isSvg);
1571
+ context = portalHost ? { isParent: true, host: portalHost, rootHost: portalHost } : context;
1572
+ componentViewCache.set(component, Object.assign({ atom: from }, context));
1573
+ let child = from.child;
1574
+ while (child) {
1575
+ buildView(nativeRenderer, component, child, context);
1576
+ child = child.sibling;
1577
+ }
1578
+ });
1551
1579
  }
1552
1580
  function createChainByJSXNode(type, jsxNode, nodeType, prevAtom, isSvg, key) {
1553
1581
  const atom = {
@@ -1650,7 +1678,11 @@ function createElement(nativeRenderer, atom, parentComponent, context) {
1650
1678
  }
1651
1679
  atom.nativeNode = nativeNode;
1652
1680
  insertNode(nativeRenderer, atom, context);
1653
- buildElementChildren(atom, nativeRenderer, parentComponent, context);
1681
+ buildElementChildren(atom, nativeRenderer, parentComponent, {
1682
+ isParent: true,
1683
+ host: nativeNode,
1684
+ rootHost: context.rootHost
1685
+ });
1654
1686
  context.host = nativeNode;
1655
1687
  context.isParent = false;
1656
1688
  applyRefs(bindingRefs, nativeNode, true);
@@ -1668,14 +1700,18 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1668
1700
  const nativeNode = newAtom.nativeNode;
1669
1701
  const oldVNode = oldAtom.jsxNode;
1670
1702
  if (newVNode === oldVNode) {
1671
- updateElementChildren(newAtom, oldAtom, nativeRenderer, parentComponent, context, isSvg);
1703
+ newAtom.child = oldAtom.child;
1704
+ reuseElementChildrenView(nativeRenderer, newAtom);
1672
1705
  return;
1673
1706
  }
1674
1707
  const changes = getObjectChanges(newVNode.props, oldVNode.props);
1675
1708
  let unBindRefs;
1676
1709
  let bindRefs;
1710
+ let updatedChildren = false;
1677
1711
  for (const [key, value] of changes.remove) {
1678
1712
  if (key === 'children') {
1713
+ updatedChildren = true;
1714
+ cleanElementChildren(oldAtom, nativeRenderer);
1679
1715
  continue;
1680
1716
  }
1681
1717
  if (key === 'class') {
@@ -1702,6 +1738,14 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1702
1738
  }
1703
1739
  for (const [key, newValue, oldValue] of changes.replace) {
1704
1740
  if (key === 'children') {
1741
+ updatedChildren = true;
1742
+ newAtom.child = createChildChain(newValue, isSvg);
1743
+ if (!newAtom.child) {
1744
+ cleanElementChildren(oldAtom, nativeRenderer);
1745
+ }
1746
+ else {
1747
+ diff(nativeRenderer, parentComponent, newAtom.child, oldAtom.child, context, false);
1748
+ }
1705
1749
  continue;
1706
1750
  }
1707
1751
  if (key === 'class') {
@@ -1736,6 +1780,9 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1736
1780
  }
1737
1781
  for (const [key, value] of changes.add) {
1738
1782
  if (key === 'children') {
1783
+ updatedChildren = true;
1784
+ newAtom.child = createChildChain(value, isSvg);
1785
+ buildElementChildren(newAtom, nativeRenderer, parentComponent, context);
1739
1786
  continue;
1740
1787
  }
1741
1788
  if (key === 'class') {
@@ -1761,40 +1808,13 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1761
1808
  }
1762
1809
  nativeRenderer.setProperty(nativeNode, key, value, isSvg);
1763
1810
  }
1764
- updateElementChildren(newAtom, oldAtom, nativeRenderer, parentComponent, context, isSvg);
1811
+ if (!updatedChildren) {
1812
+ newAtom.child = oldAtom.child;
1813
+ reuseElementChildrenView(nativeRenderer, newAtom);
1814
+ }
1765
1815
  applyRefs(unBindRefs, nativeNode, false);
1766
1816
  applyRefs(bindRefs, nativeNode, true);
1767
1817
  }
1768
- function updateElementChildren(newAtom, oldAtom, nativeRenderer, parentComponent, context, isSvg) {
1769
- /**
1770
- * 不能仅依赖 children 是否相等的判断来确定是否要继续向下 diff
1771
- * 如:
1772
- * ```tsx
1773
- * <Comp>
1774
- * <div>
1775
- * {props.children}
1776
- * </div>
1777
- * </Comp>
1778
- * ```
1779
- * 其中当 Comp 产生变化时,children 来自父组件,这时 children 是相等的,
1780
- * 但,children 内可能有子组件也发生了变化,如果不继续 diff,那么,子组件
1781
- * 的视图更新将不会发生
1782
- */
1783
- newAtom.child = createChildChain(newAtom.jsxNode.props.children, isSvg);
1784
- if (!newAtom.child) {
1785
- // 防止删除用户手动添加的元素
1786
- if (oldAtom.child) {
1787
- cleanElementChildren(oldAtom, nativeRenderer);
1788
- }
1789
- }
1790
- else {
1791
- diff(nativeRenderer, parentComponent, newAtom.child, oldAtom.child, {
1792
- host: newAtom.nativeNode,
1793
- isParent: true,
1794
- rootHost: context.rootHost
1795
- }, false);
1796
- }
1797
- }
1798
1818
  function applyRefs(refs, nativeNode, binding) {
1799
1819
  if (refs) {
1800
1820
  const refList = Array.isArray(refs) ? refs : [refs];
@@ -1911,6 +1931,7 @@ function viewfly(config) {
1911
1931
  }
1912
1932
 
1913
1933
  exports.Component = Component;
1934
+ exports.Context = Context;
1914
1935
  exports.DynamicRef = DynamicRef;
1915
1936
  exports.ForwardRef = ForwardRef;
1916
1937
  exports.Fragment = Fragment;
@@ -18,6 +18,8 @@ export declare namespace JSX {
18
18
  }
19
19
  interface ElementChildrenAttribute extends ViewflyJSX.ElementChildrenAttribute {
20
20
  }
21
+ interface ElementAttributesProperty extends ViewflyJSX.ElementAttributesProperty {
22
+ }
21
23
  interface IntrinsicClassAttributes<T> extends ViewflyJSX.IntrinsicClassAttributes<T> {
22
24
  }
23
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viewfly/core",
3
- "version": "1.0.1",
3
+ "version": "1.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",
@@ -50,7 +50,7 @@
50
50
  "bugs": {
51
51
  "url": "https://github.com/viewfly/viewfly.git/issues"
52
52
  },
53
- "gitHead": "cd1ecadfe947e44eeff2966f13b03471ab6c8790",
53
+ "gitHead": "272ca07c3c97c4f468369380303c41133b345228",
54
54
  "dependencies": {
55
55
  "reflect-metadata": "^0.2.2"
56
56
  }