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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,6 +12,7 @@ export declare class Renderer {
12
12
  render(): void;
13
13
  refresh(): void;
14
14
  private reconcile;
15
+ private getPrevSibling;
15
16
  private reconcileElement;
16
17
  private applyChanges;
17
18
  private diff;
@@ -3,6 +3,15 @@ import { ReflectiveInjector, normalizeProvider, NullInjector, Injectable } from
3
3
  export * from '@tanbo/di';
4
4
  import { Subject, Subscription, microTask } from '@tanbo/stream';
5
5
 
6
+ function makeError(name) {
7
+ return function viewflyError(message) {
8
+ const error = new Error(message);
9
+ error.name = `[ViewflyError: ${name}]`;
10
+ error.stack = error.stack.replace(/\n.*?(?=\n)/, '');
11
+ return error;
12
+ };
13
+ }
14
+
6
15
  class NativeRenderer {
7
16
  }
8
17
 
@@ -34,15 +43,6 @@ function __metadata(metadataKey, metadataValue) {
34
43
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
35
44
  }
36
45
 
37
- function makeError(name) {
38
- return function viewflyError(message) {
39
- const error = new Error(message);
40
- error.name = `[ViewflyError: ${name}]`;
41
- error.stack = error.stack.replace(/\n.*?(?=\n)/, '');
42
- return error;
43
- };
44
- }
45
-
46
46
  const jsxErrorFn = makeError('JSX');
47
47
  const Fragment = function Fragment() {
48
48
  throw jsxErrorFn('Fragment does not support calling.');
@@ -180,10 +180,13 @@ class JSXElement {
180
180
 
181
181
  const componentSetupStack = [];
182
182
  const componentRendingStack = [];
183
+ const derivedStack = [];
183
184
  const componentErrorFn = makeError('component');
184
185
  function getSetupContext(need = true) {
185
186
  const current = componentSetupStack[componentSetupStack.length - 1];
186
187
  if (!current && need) {
188
+ // 防止因外部捕获异常引引起的缓存未清理的问题
189
+ componentRendingStack.pop();
187
190
  throw componentErrorFn('cannot be called outside the component!');
188
191
  }
189
192
  return current;
@@ -191,6 +194,9 @@ function getSetupContext(need = true) {
191
194
  function getRendingContext() {
192
195
  return componentRendingStack[componentRendingStack.length - 1];
193
196
  }
197
+ function getDerivedContext() {
198
+ return derivedStack[derivedStack.length - 1];
199
+ }
194
200
  class JSXComponent {
195
201
  constructor(createInstance) {
196
202
  this.createInstance = createInstance;
@@ -237,20 +243,33 @@ class Component extends ReflectiveInjector {
237
243
  }
238
244
  },
239
245
  set() {
246
+ // 防止因外部捕获异常引引起的缓存未清理的问题
247
+ if (isSetup) {
248
+ componentSetupStack.pop();
249
+ }
250
+ if (isRending) {
251
+ componentRendingStack.pop();
252
+ }
240
253
  throw componentErrorFn('component props is readonly!');
241
254
  }
242
255
  });
243
256
  componentSetupStack.push(this);
257
+ let isSetup = true;
244
258
  const render = this.setup(props);
259
+ isSetup = false;
245
260
  componentSetupStack.pop();
246
261
  componentRendingStack.push(this);
262
+ let isRending = true;
247
263
  const template = render();
264
+ isRending = false;
248
265
  componentRendingStack.pop();
249
266
  return {
250
267
  template,
251
268
  render: () => {
252
269
  componentRendingStack.push(this);
270
+ isRending = true;
253
271
  const template = render();
272
+ isRending = false;
254
273
  componentRendingStack.pop();
255
274
  return template;
256
275
  }
@@ -408,7 +427,7 @@ function onDestroy(callback) {
408
427
  class Ref {
409
428
  constructor(callback) {
410
429
  this.callback = callback;
411
- this.unBindMap = new WeakMap;
430
+ this.unBindMap = new WeakMap();
412
431
  this.targetCaches = new Set();
413
432
  }
414
433
  bind(value) {
@@ -418,15 +437,16 @@ class Ref {
418
437
  if (this.targetCaches.has(value)) {
419
438
  return;
420
439
  }
421
- this.targetCaches.add(value);
422
440
  const unBindFn = this.callback(value);
423
441
  if (typeof unBindFn === 'function') {
424
442
  this.unBindMap.set(value, unBindFn);
425
443
  }
444
+ this.targetCaches.add(value);
426
445
  }
427
446
  unBind(value) {
428
447
  this.targetCaches.delete(value);
429
448
  const unBindFn = this.unBindMap.get(value);
449
+ this.unBindMap.delete(value);
430
450
  if (typeof unBindFn === 'function') {
431
451
  unBindFn();
432
452
  }
@@ -511,10 +531,6 @@ function useSignal(state) {
511
531
  signal[depsKey] = new Set();
512
532
  return signal;
513
533
  }
514
- const derivedStack = [];
515
- function getDerivedContext() {
516
- return derivedStack[derivedStack.length - 1];
517
- }
518
534
  /**
519
535
  * 使用派生值,Viewfly 会收集回调函数内同步执行时访问的 Signal,
520
536
  * 并在你获取 useDerived 函数返回的 Signal 的值时,自动计算最新的值。
@@ -601,8 +617,8 @@ function inject(token, notFoundValue, flags) {
601
617
  * Viewfly 根组件,用于实现组件状态更新事件通知
602
618
  */
603
619
  class RootComponent extends Component {
604
- constructor(factory) {
605
- super(new NullInjector(), factory, null);
620
+ constructor(factory, parentInjector = new NullInjector()) {
621
+ super(parentInjector, factory, null);
606
622
  this.changeEmitter = new Subject();
607
623
  }
608
624
  markAsChanged() {
@@ -790,6 +806,37 @@ let Renderer = class Renderer {
790
806
  const atom = this.componentAtomCaches.get(component).atom.child;
791
807
  this.reconcileElement(atom, context);
792
808
  }
809
+ else {
810
+ const prevSibling = this.getPrevSibling(component);
811
+ if (prevSibling) {
812
+ context.isParent = false;
813
+ context.host = prevSibling;
814
+ }
815
+ }
816
+ }
817
+ getPrevSibling(component) {
818
+ let atom = this.componentAtomCaches.get(component).atom.child;
819
+ const childAtoms = [];
820
+ while (atom) {
821
+ childAtoms.push(atom);
822
+ atom = atom.sibling;
823
+ }
824
+ const components = [];
825
+ while (childAtoms.length) {
826
+ const last = childAtoms.pop();
827
+ if (last.jsxNode instanceof Component) {
828
+ components.push(last.jsxNode);
829
+ continue;
830
+ }
831
+ return last.nativeNode;
832
+ }
833
+ for (const component of components) {
834
+ const nativeNode = this.getPrevSibling(component);
835
+ if (nativeNode) {
836
+ return nativeNode;
837
+ }
838
+ }
839
+ return null;
793
840
  }
794
841
  reconcileElement(atom, context) {
795
842
  while (atom) {
@@ -851,7 +898,11 @@ let Renderer = class Renderer {
851
898
  this.diff(start.child, reusedAtom.child, childContext);
852
899
  }
853
900
  else if (reusedAtom.child) {
854
- this.cleanView(reusedAtom.child, false);
901
+ let atom = reusedAtom.child;
902
+ while (atom) {
903
+ this.cleanView(atom, false);
904
+ atom = atom.sibling;
905
+ }
855
906
  }
856
907
  if (isComponent) {
857
908
  start.jsxNode.rendered();
@@ -1212,7 +1263,7 @@ class Viewfly extends ReflectiveInjector {
1212
1263
  /**
1213
1264
  * 启动 Viewfly
1214
1265
  */
1215
- start() {
1266
+ run() {
1216
1267
  const renderer = this.get(Renderer);
1217
1268
  renderer.render();
1218
1269
  if (this.config.autoUpdate === false) {
@@ -1237,8 +1288,8 @@ class Viewfly extends ReflectiveInjector {
1237
1288
  return () => {
1238
1289
  return this.destroyed ? null : rootNode;
1239
1290
  };
1240
- });
1291
+ }, this.config.context);
1241
1292
  }
1242
1293
  }
1243
1294
 
1244
- export { Component, Fragment, JSXComponent, JSXElement, JSXText, NativeRenderer, Props, Ref, Renderer, RootComponent, RootComponentRef, Viewfly, inject, jsx, jsxs, onDestroy, onMount, onPropsChanged, onUpdated, provide, useDerived, useEffect, useRef, useSignal };
1295
+ export { Component, Fragment, JSXComponent, JSXElement, JSXText, NativeRenderer, Props, Ref, Renderer, RootComponent, RootComponentRef, Viewfly, inject, jsx, jsxs, makeError, onDestroy, onMount, onPropsChanged, onUpdated, provide, useDerived, useEffect, useRef, useSignal };
package/bundles/index.js CHANGED
@@ -4,6 +4,15 @@ require('reflect-metadata');
4
4
  var di = require('@tanbo/di');
5
5
  var stream = require('@tanbo/stream');
6
6
 
7
+ function makeError(name) {
8
+ return function viewflyError(message) {
9
+ const error = new Error(message);
10
+ error.name = `[ViewflyError: ${name}]`;
11
+ error.stack = error.stack.replace(/\n.*?(?=\n)/, '');
12
+ return error;
13
+ };
14
+ }
15
+
7
16
  class NativeRenderer {
8
17
  }
9
18
 
@@ -35,15 +44,6 @@ function __metadata(metadataKey, metadataValue) {
35
44
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
36
45
  }
37
46
 
38
- function makeError(name) {
39
- return function viewflyError(message) {
40
- const error = new Error(message);
41
- error.name = `[ViewflyError: ${name}]`;
42
- error.stack = error.stack.replace(/\n.*?(?=\n)/, '');
43
- return error;
44
- };
45
- }
46
-
47
47
  const jsxErrorFn = makeError('JSX');
48
48
  const Fragment = function Fragment() {
49
49
  throw jsxErrorFn('Fragment does not support calling.');
@@ -181,10 +181,13 @@ class JSXElement {
181
181
 
182
182
  const componentSetupStack = [];
183
183
  const componentRendingStack = [];
184
+ const derivedStack = [];
184
185
  const componentErrorFn = makeError('component');
185
186
  function getSetupContext(need = true) {
186
187
  const current = componentSetupStack[componentSetupStack.length - 1];
187
188
  if (!current && need) {
189
+ // 防止因外部捕获异常引引起的缓存未清理的问题
190
+ componentRendingStack.pop();
188
191
  throw componentErrorFn('cannot be called outside the component!');
189
192
  }
190
193
  return current;
@@ -192,6 +195,9 @@ function getSetupContext(need = true) {
192
195
  function getRendingContext() {
193
196
  return componentRendingStack[componentRendingStack.length - 1];
194
197
  }
198
+ function getDerivedContext() {
199
+ return derivedStack[derivedStack.length - 1];
200
+ }
195
201
  class JSXComponent {
196
202
  constructor(createInstance) {
197
203
  this.createInstance = createInstance;
@@ -238,20 +244,33 @@ class Component extends di.ReflectiveInjector {
238
244
  }
239
245
  },
240
246
  set() {
247
+ // 防止因外部捕获异常引引起的缓存未清理的问题
248
+ if (isSetup) {
249
+ componentSetupStack.pop();
250
+ }
251
+ if (isRending) {
252
+ componentRendingStack.pop();
253
+ }
241
254
  throw componentErrorFn('component props is readonly!');
242
255
  }
243
256
  });
244
257
  componentSetupStack.push(this);
258
+ let isSetup = true;
245
259
  const render = this.setup(props);
260
+ isSetup = false;
246
261
  componentSetupStack.pop();
247
262
  componentRendingStack.push(this);
263
+ let isRending = true;
248
264
  const template = render();
265
+ isRending = false;
249
266
  componentRendingStack.pop();
250
267
  return {
251
268
  template,
252
269
  render: () => {
253
270
  componentRendingStack.push(this);
271
+ isRending = true;
254
272
  const template = render();
273
+ isRending = false;
255
274
  componentRendingStack.pop();
256
275
  return template;
257
276
  }
@@ -409,7 +428,7 @@ function onDestroy(callback) {
409
428
  class Ref {
410
429
  constructor(callback) {
411
430
  this.callback = callback;
412
- this.unBindMap = new WeakMap;
431
+ this.unBindMap = new WeakMap();
413
432
  this.targetCaches = new Set();
414
433
  }
415
434
  bind(value) {
@@ -419,15 +438,16 @@ class Ref {
419
438
  if (this.targetCaches.has(value)) {
420
439
  return;
421
440
  }
422
- this.targetCaches.add(value);
423
441
  const unBindFn = this.callback(value);
424
442
  if (typeof unBindFn === 'function') {
425
443
  this.unBindMap.set(value, unBindFn);
426
444
  }
445
+ this.targetCaches.add(value);
427
446
  }
428
447
  unBind(value) {
429
448
  this.targetCaches.delete(value);
430
449
  const unBindFn = this.unBindMap.get(value);
450
+ this.unBindMap.delete(value);
431
451
  if (typeof unBindFn === 'function') {
432
452
  unBindFn();
433
453
  }
@@ -512,10 +532,6 @@ function useSignal(state) {
512
532
  signal[depsKey] = new Set();
513
533
  return signal;
514
534
  }
515
- const derivedStack = [];
516
- function getDerivedContext() {
517
- return derivedStack[derivedStack.length - 1];
518
- }
519
535
  /**
520
536
  * 使用派生值,Viewfly 会收集回调函数内同步执行时访问的 Signal,
521
537
  * 并在你获取 useDerived 函数返回的 Signal 的值时,自动计算最新的值。
@@ -602,8 +618,8 @@ function inject(token, notFoundValue, flags) {
602
618
  * Viewfly 根组件,用于实现组件状态更新事件通知
603
619
  */
604
620
  class RootComponent extends Component {
605
- constructor(factory) {
606
- super(new di.NullInjector(), factory, null);
621
+ constructor(factory, parentInjector = new di.NullInjector()) {
622
+ super(parentInjector, factory, null);
607
623
  this.changeEmitter = new stream.Subject();
608
624
  }
609
625
  markAsChanged() {
@@ -791,6 +807,37 @@ exports.Renderer = class Renderer {
791
807
  const atom = this.componentAtomCaches.get(component).atom.child;
792
808
  this.reconcileElement(atom, context);
793
809
  }
810
+ else {
811
+ const prevSibling = this.getPrevSibling(component);
812
+ if (prevSibling) {
813
+ context.isParent = false;
814
+ context.host = prevSibling;
815
+ }
816
+ }
817
+ }
818
+ getPrevSibling(component) {
819
+ let atom = this.componentAtomCaches.get(component).atom.child;
820
+ const childAtoms = [];
821
+ while (atom) {
822
+ childAtoms.push(atom);
823
+ atom = atom.sibling;
824
+ }
825
+ const components = [];
826
+ while (childAtoms.length) {
827
+ const last = childAtoms.pop();
828
+ if (last.jsxNode instanceof Component) {
829
+ components.push(last.jsxNode);
830
+ continue;
831
+ }
832
+ return last.nativeNode;
833
+ }
834
+ for (const component of components) {
835
+ const nativeNode = this.getPrevSibling(component);
836
+ if (nativeNode) {
837
+ return nativeNode;
838
+ }
839
+ }
840
+ return null;
794
841
  }
795
842
  reconcileElement(atom, context) {
796
843
  while (atom) {
@@ -852,7 +899,11 @@ exports.Renderer = class Renderer {
852
899
  this.diff(start.child, reusedAtom.child, childContext);
853
900
  }
854
901
  else if (reusedAtom.child) {
855
- this.cleanView(reusedAtom.child, false);
902
+ let atom = reusedAtom.child;
903
+ while (atom) {
904
+ this.cleanView(atom, false);
905
+ atom = atom.sibling;
906
+ }
856
907
  }
857
908
  if (isComponent) {
858
909
  start.jsxNode.rendered();
@@ -1213,7 +1264,7 @@ class Viewfly extends di.ReflectiveInjector {
1213
1264
  /**
1214
1265
  * 启动 Viewfly
1215
1266
  */
1216
- start() {
1267
+ run() {
1217
1268
  const renderer = this.get(exports.Renderer);
1218
1269
  renderer.render();
1219
1270
  if (this.config.autoUpdate === false) {
@@ -1238,7 +1289,7 @@ class Viewfly extends di.ReflectiveInjector {
1238
1289
  return () => {
1239
1290
  return this.destroyed ? null : rootNode;
1240
1291
  };
1241
- });
1292
+ }, this.config.context);
1242
1293
  }
1243
1294
  }
1244
1295
 
@@ -1256,6 +1307,7 @@ exports.Viewfly = Viewfly;
1256
1307
  exports.inject = inject;
1257
1308
  exports.jsx = jsx;
1258
1309
  exports.jsxs = jsxs;
1310
+ exports.makeError = makeError;
1259
1311
  exports.onDestroy = onDestroy;
1260
1312
  exports.onMount = onMount;
1261
1313
  exports.onPropsChanged = onPropsChanged;
@@ -5,15 +5,15 @@ export declare class JSXComponent {
5
5
  constructor(createInstance: (injector: Component) => Component);
6
6
  }
7
7
  export type JSXTemplate = JSXElement | JSXComponent | null | void;
8
- export interface ComponentSetup {
9
- (props?: JSXProps<any>): () => JSXTemplate;
8
+ export interface ComponentSetup<T extends JSXProps<any> = JSXProps<any>> {
9
+ (props?: T): () => JSXTemplate;
10
10
  }
11
11
  /**
12
12
  * Viewfly 组件管理类,用于管理组件的生命周期,上下文等
13
13
  */
14
14
  export declare class Component extends ReflectiveInjector {
15
15
  setup: ComponentSetup;
16
- config: JSXProps<any> | null;
16
+ config?: JSXProps<any> | null | undefined;
17
17
  destroyCallbacks: LifeCycleCallback[];
18
18
  mountCallbacks: LifeCycleCallback[];
19
19
  propsChangedCallbacks: PropsChangedCallback<any>[];
@@ -27,7 +27,7 @@ export declare class Component extends ReflectiveInjector {
27
27
  private updatedDestroyCallbacks;
28
28
  private propsChangedDestroyCallbacks;
29
29
  private isFirstRending;
30
- constructor(context: Injector, setup: ComponentSetup, config: JSXProps<any> | null);
30
+ constructor(context: Injector, setup: ComponentSetup, config?: JSXProps<any> | null | undefined);
31
31
  addProvide<T>(providers: Provider<T> | Provider<T>[]): void;
32
32
  init(): {
33
33
  template: JSXTemplate;
@@ -36,7 +36,7 @@ export declare class Component extends ReflectiveInjector {
36
36
  markAsDirtied(): void;
37
37
  markAsChanged(): void;
38
38
  rendered(): void;
39
- invokePropsChangedHooks(newProps: JSXProps<any> | null): void;
39
+ invokePropsChangedHooks(newProps?: JSXProps<any> | null): void;
40
40
  destroy(): void;
41
41
  private invokeMountHooks;
42
42
  private invokeUpdatedHooks;
@@ -6,10 +6,10 @@ export interface JSXProps<T = JSXChildNode | JSXChildNode[]> {
6
6
  [key: symbol]: any;
7
7
  }
8
8
  export declare const Fragment: () => never;
9
- export declare function jsx<T extends JSXChildNode>(name: string, config: JSXProps<T> | null): JSXElement;
10
- export declare function jsx<T extends JSXChildNode>(setup: ComponentSetup, config: JSXProps<T> | null): JSXComponent;
11
- export declare function jsxs<T extends JSXChildNode[]>(name: string, config: JSXProps<T> | null): JSXElement;
12
- export declare function jsxs<T extends JSXChildNode[]>(setup: ComponentSetup, config: JSXProps<T> | null): JSXComponent;
9
+ export declare function jsx<T extends JSXChildNode>(name: string, config?: JSXProps<T> | null): JSXElement;
10
+ export declare function jsx<T extends JSXChildNode>(setup: ComponentSetup, config?: JSXProps<T> | null): JSXComponent;
11
+ export declare function jsxs<T extends JSXChildNode[]>(name: string, config?: JSXProps<T> | null): JSXElement;
12
+ export declare function jsxs<T extends JSXChildNode[]>(setup: ComponentSetup, config?: JSXProps<T> | null): JSXComponent;
13
13
  export interface VElementListeners {
14
14
  [listenKey: string]: <T extends Event>(ev: T) => any;
15
15
  }
@@ -24,12 +24,12 @@ export declare class Props {
24
24
  classes: Set<string>;
25
25
  listeners: VElementListeners;
26
26
  children: VNode[];
27
- constructor(props: JSXProps<JSXChildNode> | JSXProps<JSXChildNode[]> | null);
27
+ constructor(props?: JSXProps<JSXChildNode> | JSXProps<JSXChildNode[]> | null);
28
28
  static classToArray(config: unknown): string[];
29
29
  }
30
30
  export declare class JSXElement {
31
31
  name: string;
32
- config: JSXProps<any> | null;
32
+ config?: JSXProps<any> | null | undefined;
33
33
  props: Props;
34
- constructor(name: string, config: JSXProps<any> | null);
34
+ constructor(name: string, config?: JSXProps<any> | null | undefined);
35
35
  }
@@ -1,10 +1,11 @@
1
1
  import { Subject } from '@tanbo/stream';
2
+ import { NullInjector } from '@tanbo/di';
2
3
  import { Component, ComponentSetup } from './component';
3
4
  /**
4
5
  * Viewfly 根组件,用于实现组件状态更新事件通知
5
6
  */
6
7
  export declare class RootComponent extends Component {
7
8
  changeEmitter: Subject<void>;
8
- constructor(factory: ComponentSetup);
9
+ constructor(factory: ComponentSetup, parentInjector?: NullInjector);
9
10
  markAsChanged(): void;
10
11
  }
@@ -1,5 +1,6 @@
1
1
  import 'reflect-metadata';
2
2
  export * from '@tanbo/di';
3
+ export * from './_utils/make-error';
3
4
  export * from './foundation/_api';
4
5
  export * from './model/_api';
5
6
  export * from './viewfly';
@@ -1,4 +1,4 @@
1
- import { Provider, ReflectiveInjector } from '@tanbo/di';
1
+ import { Injector, Provider, ReflectiveInjector } from '@tanbo/di';
2
2
  import { NativeNode } from './foundation/_api';
3
3
  import { JSXComponent, JSXElement } from './model/_api';
4
4
  export type RootNode = JSXElement | JSXComponent;
@@ -14,6 +14,8 @@ export interface Config {
14
14
  autoUpdate?: boolean;
15
15
  /** 根节点 */
16
16
  root: RootNode;
17
+ /** 根组件的上下文 */
18
+ context?: Injector;
17
19
  }
18
20
  /**
19
21
  * Viewfly 核心类,用于启动一个 Viewfly 应用
@@ -27,7 +29,7 @@ export declare class Viewfly extends ReflectiveInjector {
27
29
  /**
28
30
  * 启动 Viewfly
29
31
  */
30
- start(): void;
32
+ run(): void;
31
33
  /**
32
34
  * 销毁 Viewfly 实例
33
35
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viewfly/core",
3
- "version": "0.0.1-alpha.4",
3
+ "version": "0.0.1-alpha.6",
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": "68a7c531c0040fc0b1b7addb87a8df3c5981600e"
40
+ "gitHead": "aedb326658afa6a712aebe3f22fe5209ae18a9f9"
41
41
  }