@viewfly/core 1.0.2 → 1.0.5

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.
@@ -246,7 +246,11 @@ declare namespace JSX {
246
246
  }
247
247
  interface ElementClass<P = any> extends ComponentInstance<P> {
248
248
  }
249
+ interface ElementAttributesProperty {
250
+ props: {};
251
+ }
249
252
  interface ElementChildrenAttribute {
253
+ children: {};
250
254
  }
251
255
  interface IntrinsicElements {
252
256
  [name: string]: any;
@@ -256,6 +260,7 @@ declare namespace JSX {
256
260
  }
257
261
  }
258
262
 
263
+ declare function getSetupContext(need?: boolean): Component;
259
264
  type ClassNames = string | Record<string, unknown> | false | null | undefined | ClassNames[];
260
265
  interface ComponentInstance<P> {
261
266
  $portalHost?: NativeNode;
@@ -291,9 +296,9 @@ declare class Component extends ReflectiveInjector {
291
296
  private propsChangedDestroyCallbacks?;
292
297
  protected _dirty: boolean;
293
298
  protected _changed: boolean;
294
- private unWatch?;
295
299
  private isFirstRendering;
296
300
  private refs;
301
+ private listener;
297
302
  constructor(parentComponent: Injector | null, type: ComponentSetup, props: Props, key?: Key | undefined);
298
303
  markAsDirtied(): void;
299
304
  markAsChanged(changedComponent?: Component): void;
@@ -408,13 +413,52 @@ declare class StaticRef<T> extends DynamicRef<T> {
408
413
  constructor();
409
414
  }
410
415
  declare function createRef<T, U = ExtractInstanceType<T>>(): StaticRef<U>;
411
- declare const depsKey: unique symbol;
412
416
  /**
413
- * 组件状态实例,直接调用可以获取最新的状态,通过 set 方法可以更新状态
417
+ * 给组件添加注解
418
+ * @param annotation
419
+ * @param componentSetup
420
+ * @example
421
+ * ```ts
422
+ * export customScope = new Scope('scopeName')
423
+ * export const App = withAnnotation({
424
+ * scope: customScope,
425
+ * providers: [
426
+ * ExampleService
427
+ * ]
428
+ * }, function(props: Props) {
429
+ * return () => {
430
+ * return <div>...</div>
431
+ * }
432
+ * })
414
433
  * ```
415
434
  */
435
+ declare function withAnnotation<T extends ComponentSetup>(annotation: ComponentAnnotation, componentSetup: T): T;
436
+ /**
437
+ * 通过组件上下文获取 IoC 容器内数据的勾子方法
438
+ */
439
+ declare function inject<T extends Type<any> | AbstractType<any> | InjectionToken<any>, U = never>(token: T, notFoundValue?: U, flags?: InjectFlags): ExtractValueType<T> | U;
440
+ /**
441
+ * 获取当前组件实例
442
+ */
443
+ declare function getCurrentInstance(): Component;
444
+
445
+ declare function withMemo<T extends Props = Props>(canUseMemo: ComponentInstance<T>['$useMemo'], render: () => JSXNode): ComponentInstance<T>;
446
+
447
+ declare function createRenderer(component: Component, nativeRenderer: NativeRenderer): (host: NativeNode) => void;
448
+
449
+ /**
450
+ * Viewfly 根组件,用于实现组件状态更新事件通知
451
+ */
452
+ declare class RootComponent extends Component {
453
+ private refresh;
454
+ constructor(parentInjector: Injector | null, factory: ComponentSetup, refresh: () => void);
455
+ markAsChanged(changedComponent?: Component): void;
456
+ }
457
+
458
+ /**
459
+ * 组件状态实例,直接调用可以获取最新的状态,通过 set 方法可以更新状态
460
+ */
416
461
  interface Signal<T> {
417
- $isSignal: true;
418
462
  /**
419
463
  * 直接调用一个 Signal 实例,可以获取最新状态
420
464
  */
@@ -424,7 +468,6 @@ interface Signal<T> {
424
468
  * @param newState
425
469
  */
426
470
  set(newState: T): void;
427
- [depsKey]: Set<LifeCycleCallback>;
428
471
  }
429
472
  /**
430
473
  * 组件状态管理器
@@ -452,14 +495,15 @@ interface Signal<T> {
452
495
  declare function createSignal<T>(state: T): Signal<T>;
453
496
  /**
454
497
  * 使用派生值,Viewfly 会收集回调函数内同步执行时访问的 Signal,
455
- * 并在你获取 useDerived 函数返回的 Signal 的值时,自动计算最新的值。
498
+ * 并在你获取 createDerived 函数返回的 Signal 的值时,自动计算最新的值。
456
499
  *
457
- * @param callback
500
+ * @param fn
458
501
  * @param isContinue 可选的停止函数,在每次值更新后调用,当返回值为 false 时,将不再监听依赖的变化
459
502
  */
460
- declare function createDerived<T>(callback: () => T, isContinue?: (data: T) => unknown): Signal<T>;
461
- interface WatchCallback<T, U> {
462
- (newValue: T, oldValue: U): void | (() => void);
503
+ declare function computed<T>(fn: () => T, isContinue?: (data: T) => unknown): Signal<T>;
504
+ declare const createDerived: typeof computed;
505
+ interface WatchCallback<T> {
506
+ (newValue: T, oldValue: T): void | (() => void);
463
507
  }
464
508
  /**
465
509
  * 监听状态变化,当任意一个状态发生变更时,触发回调。
@@ -468,58 +512,17 @@ interface WatchCallback<T, U> {
468
512
  * @param deps 依赖的状态 Signal,可以是一个 Signal,只可以一个数包含 Signal 的数组,或者是一个求值函数
469
513
  * @param callback 状态变更后的回调函数
470
514
  */
471
- declare function watch<T>(deps: Signal<T>, callback: WatchCallback<T, T>): () => void;
472
- declare function watch<T>(deps: [Signal<T>], callback: WatchCallback<[T], [T]>): () => void;
473
- declare function watch<T, T1>(deps: [Signal<T>, Signal<T1>], callback: WatchCallback<[T, T1], [T, T1]>): () => void;
474
- declare function watch<T, T1, T2>(deps: [Signal<T>, Signal<T1>, Signal<T2>], callback: WatchCallback<[T, T1, T2], [T, T1, T2]>): () => void;
475
- declare function watch<T, T1, T2, T3>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>], callback: WatchCallback<[T, T1, T2, T3], [T, T1, T2, T3]>): () => void;
476
- declare function watch<T, T1, T2, T3, T4>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>, Signal<T4>], callback: WatchCallback<[T, T1, T2, T3, T4], [T, T1, T2, T3, T4]>): () => void;
477
- declare function watch<T, T1, T2, T3, T4, T5>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>, Signal<T4>, Signal<T5>], callback: WatchCallback<[T, T1, T2, T3, T4, T5], [T, T1, T2, T3, T4, T5]>): () => void;
478
- declare function watch<T, T1, T2, T3, T4, T5, T6>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>, Signal<T4>, Signal<T5>, Signal<T6>], callback: WatchCallback<[T, T1, T2, T3, T4, T5, T6], [T, T1, T2, T3, T4, T5, T6]>): () => void;
479
- declare function watch<T, T1, T2, T3, T4, T5, T6, T7>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>, Signal<T4>, Signal<T5>, Signal<T6>, Signal<T7>], callback: WatchCallback<[T, T1, T2, T3, T4, T5, T6, T7], [T, T1, T2, T3, T4, T5, T6, T7]>): () => void;
480
- declare function watch<T>(deps: () => T, callback: WatchCallback<T, T>): () => void;
481
- declare function watch<T = any>(deps: Signal<any>[], callback: WatchCallback<T[], T[]>): () => void;
482
- /**
483
- * 给组件添加注解
484
- * @param annotation
485
- * @param componentSetup
486
- * @example
487
- * ```ts
488
- * export customScope = new Scope('scopeName')
489
- * export const App = withAnnotation({
490
- * scope: customScope,
491
- * providers: [
492
- * ExampleService
493
- * ]
494
- * }, function(props: Props) {
495
- * return () => {
496
- * return <div>...</div>
497
- * }
498
- * })
499
- * ```
500
- */
501
- declare function withAnnotation<T extends ComponentSetup>(annotation: ComponentAnnotation, componentSetup: T): T;
502
- /**
503
- * 通过组件上下文获取 IoC 容器内数据的勾子方法
504
- */
505
- declare function inject<T extends Type<any> | AbstractType<any> | InjectionToken<any>, U = never>(token: T, notFoundValue?: U, flags?: InjectFlags): ExtractValueType<T> | U;
506
- /**
507
- * 获取当前组件实例
508
- */
509
- declare function getCurrentInstance(): Component;
510
-
511
- declare function withMemo<T extends Props = Props>(canUseMemo: ComponentInstance<T>['$useMemo'], render: () => JSXNode): ComponentInstance<T>;
512
-
513
- declare function createRenderer(component: Component, nativeRenderer: NativeRenderer): (host: NativeNode) => void;
514
-
515
- /**
516
- * Viewfly 根组件,用于实现组件状态更新事件通知
517
- */
518
- declare class RootComponent extends Component {
519
- private refresh;
520
- constructor(parentInjector: Injector | null, factory: ComponentSetup, refresh: () => void);
521
- markAsChanged(changedComponent?: Component): void;
522
- }
515
+ declare function watch<T>(deps: Signal<T>, callback: WatchCallback<T>): () => void;
516
+ declare function watch<T>(deps: [Signal<T>], callback: WatchCallback<[T]>): () => void;
517
+ declare function watch<T, T1>(deps: [Signal<T>, Signal<T1>], callback: WatchCallback<[T, T1]>): () => void;
518
+ declare function watch<T, T1, T2>(deps: [Signal<T>, Signal<T1>, Signal<T2>], callback: WatchCallback<[T, T1, T2]>): () => void;
519
+ declare function watch<T, T1, T2, T3>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>], callback: WatchCallback<[T, T1, T2, T3]>): () => void;
520
+ declare function watch<T, T1, T2, T3, T4>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>, Signal<T4>], callback: WatchCallback<[T, T1, T2, T3, T4]>): () => void;
521
+ declare function watch<T, T1, T2, T3, T4, T5>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>, Signal<T4>, Signal<T5>], callback: WatchCallback<[T, T1, T2, T3, T4, T5]>): () => void;
522
+ declare function watch<T, T1, T2, T3, T4, T5, T6>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>, Signal<T4>, Signal<T5>, Signal<T6>], callback: WatchCallback<[T, T1, T2, T3, T4, T5, T6]>): () => void;
523
+ declare function watch<T, T1, T2, T3, T4, T5, T6, T7>(deps: [Signal<T>, Signal<T1>, Signal<T2>, Signal<T3>, Signal<T4>, Signal<T5>, Signal<T6>, Signal<T7>], callback: WatchCallback<[T, T1, T2, T3, T4, T5, T6, T7]>): () => void;
524
+ declare function watch<T>(deps: () => T, callback: WatchCallback<T>): () => void;
525
+ declare function watch<T = any>(deps: Signal<any>[], callback: WatchCallback<T[]>): () => void;
523
526
 
524
527
  declare const TextAtomType: unique symbol;
525
528
  declare const ElementAtomType: unique symbol;
@@ -592,4 +595,4 @@ interface Module {
592
595
  }
593
596
  declare function viewfly<T extends NativeNode>(config: Config): Application<T>;
594
597
 
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, 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 };
598
+ 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, computed, createDerived, createDynamicRef, createRef, createRenderer, createSignal, forwardRef, getCurrentInstance, getSetupContext, inject, jsx, jsxs, makeError, normalizeProvider, onMounted, onPropsChanged, onUnmounted, onUpdated, viewfly, watch, withAnnotation, withMemo };
@@ -570,23 +570,6 @@ function getObjectChanges(newProps, oldProps) {
570
570
  }
571
571
  return changes;
572
572
  }
573
- function getArrayChanges(left, right) {
574
- const changes = {
575
- add: [],
576
- remove: []
577
- };
578
- for (const i of left) {
579
- if (!right.includes(i)) {
580
- changes.remove.push(i);
581
- }
582
- }
583
- for (const i of right) {
584
- if (!left.includes(i)) {
585
- changes.add.push(i);
586
- }
587
- }
588
- return changes;
589
- }
590
573
  function classToString(config) {
591
574
  if (typeof config === 'string') {
592
575
  return config;
@@ -635,8 +618,28 @@ const TextAtomType = Symbol('Text');
635
618
  const ElementAtomType = Symbol('Element');
636
619
  const ComponentAtomType = Symbol('Component');
637
620
 
621
+ class Listener {
622
+ constructor(effect) {
623
+ this.effect = effect;
624
+ this.destroyCallbacks = [];
625
+ }
626
+ destroy() {
627
+ this.destroyCallbacks.forEach(fn => fn());
628
+ this.destroyCallbacks = [];
629
+ }
630
+ }
631
+ const listeners = [];
632
+ function getCurrentListener() {
633
+ return listeners.at(-1);
634
+ }
635
+ function pushListener(listener) {
636
+ listeners.push(listener);
637
+ }
638
+ function popListener() {
639
+ listeners.pop();
640
+ }
641
+
638
642
  const componentSetupStack = [];
639
- const signalDepsStack = [];
640
643
  const componentErrorFn = makeError('component');
641
644
  function getSetupContext(need = true) {
642
645
  const current = componentSetupStack[componentSetupStack.length - 1];
@@ -646,9 +649,6 @@ function getSetupContext(need = true) {
646
649
  }
647
650
  return current;
648
651
  }
649
- function getSignalDepsContext() {
650
- return signalDepsStack[signalDepsStack.length - 1];
651
- }
652
652
  /**
653
653
  * Viewfly 组件管理类,用于管理组件的生命周期,上下文等
654
654
  */
@@ -675,6 +675,9 @@ class Component extends ReflectiveInjector {
675
675
  this._changed = true;
676
676
  this.isFirstRendering = true;
677
677
  this.refs = null;
678
+ this.listener = new Listener(() => {
679
+ this.markAsDirtied();
680
+ });
678
681
  }
679
682
  markAsDirtied() {
680
683
  this._dirty = true;
@@ -728,12 +731,9 @@ class Component extends ReflectiveInjector {
728
731
  }
729
732
  isSetup = false;
730
733
  componentSetupStack.pop();
731
- signalDepsStack.push([]);
734
+ pushListener(this.listener);
732
735
  const template = this.instance.$render();
733
- const deps = signalDepsStack.pop();
734
- this.unWatch = watch(Array.from(new Set(deps)), () => {
735
- this.markAsDirtied();
736
- });
736
+ popListener();
737
737
  update(template, this.instance.$portalHost);
738
738
  this.rendered();
739
739
  }
@@ -772,13 +772,10 @@ class Component extends ReflectiveInjector {
772
772
  return;
773
773
  }
774
774
  }
775
- this.unWatch();
776
- signalDepsStack.push([]);
775
+ this.listener.destroy();
776
+ pushListener(this.listener);
777
777
  const template = this.instance.$render();
778
- const deps = signalDepsStack.pop();
779
- this.unWatch = watch(Array.from(new Set(deps)), () => {
780
- this.markAsDirtied();
781
- });
778
+ popListener();
782
779
  updateChildren(template);
783
780
  this.rendered();
784
781
  }
@@ -788,7 +785,7 @@ class Component extends ReflectiveInjector {
788
785
  }
789
786
  destroy() {
790
787
  var _a, _b, _c;
791
- this.unWatch();
788
+ this.listener.destroy();
792
789
  (_a = this.updatedDestroyCallbacks) === null || _a === void 0 ? void 0 : _a.forEach(fn => {
793
790
  fn();
794
791
  });
@@ -1050,173 +1047,6 @@ class StaticRef extends DynamicRef {
1050
1047
  function createRef() {
1051
1048
  return new StaticRef();
1052
1049
  }
1053
- const depsKey = Symbol('deps');
1054
- /**
1055
- * 组件状态管理器
1056
- * @param state 初始状态
1057
- * @example
1058
- * ```tsx
1059
- * function App() {
1060
- * // 初始化状态
1061
- * const state = createSignal(1)
1062
- *
1063
- * return () => {
1064
- * <div>
1065
- * <div>当前值为:{state()}</div>
1066
- * <div>
1067
- * <button type="button" onClick={() => {
1068
- * // 当点击时更新状态
1069
- * state.set(state() + 1)
1070
- * }
1071
- * }>updateState</button>
1072
- * </div>
1073
- * </div>
1074
- * }
1075
- * }
1076
- */
1077
- function createSignal(state) {
1078
- function signal() {
1079
- const depsContext = getSignalDepsContext();
1080
- if (depsContext) {
1081
- depsContext.push(signal);
1082
- }
1083
- return state;
1084
- }
1085
- signal.$isSignal = true;
1086
- signal.set = function (newState) {
1087
- if (newState === state) {
1088
- return;
1089
- }
1090
- state = newState;
1091
- const depCallbacks = Array.from(signal[depsKey]);
1092
- for (const fn of depCallbacks) {
1093
- // 回调中可能会对依赖做出修改,故需先缓存起来
1094
- fn();
1095
- }
1096
- };
1097
- //
1098
- // signal.toString = function () {
1099
- // return String(state)
1100
- // }
1101
- //
1102
- // signal.valueOf = function () {
1103
- // return state
1104
- // }
1105
- signal[depsKey] = new Set();
1106
- return signal;
1107
- }
1108
- function invokeDepFn(fn) {
1109
- const deps = [];
1110
- signalDepsStack.push(deps);
1111
- const data = fn();
1112
- signalDepsStack.pop();
1113
- return {
1114
- deps: Array.from(new Set(deps)),
1115
- data
1116
- };
1117
- }
1118
- function listen(model, deps, callback, isContinue) {
1119
- let isStop = false;
1120
- const nextListen = () => {
1121
- if (isStop) {
1122
- return;
1123
- }
1124
- isStop = true;
1125
- const { data: nextData, deps: nextDeps } = invokeDepFn(callback);
1126
- model.set(nextData);
1127
- if (typeof isContinue === 'function' && isContinue(nextData) === false) {
1128
- unListen();
1129
- return;
1130
- }
1131
- const changes = getArrayChanges(deps, nextDeps);
1132
- deps = deps.filter(i => {
1133
- const has = changes.remove.includes(i);
1134
- if (has) {
1135
- i[depsKey].delete(nextListen);
1136
- return false;
1137
- }
1138
- return true;
1139
- });
1140
- for (const s of changes.add) {
1141
- s[depsKey].add(nextListen);
1142
- }
1143
- deps.push(...changes.add);
1144
- isStop = false;
1145
- };
1146
- const unListen = () => {
1147
- for (const s of deps) {
1148
- s[depsKey].delete(nextListen);
1149
- }
1150
- };
1151
- for (const s of deps) {
1152
- s[depsKey].add(nextListen);
1153
- }
1154
- return unListen;
1155
- }
1156
- /**
1157
- * 使用派生值,Viewfly 会收集回调函数内同步执行时访问的 Signal,
1158
- * 并在你获取 useDerived 函数返回的 Signal 的值时,自动计算最新的值。
1159
- *
1160
- * @param callback
1161
- * @param isContinue 可选的停止函数,在每次值更新后调用,当返回值为 false 时,将不再监听依赖的变化
1162
- */
1163
- function createDerived(callback, isContinue) {
1164
- const { data, deps } = invokeDepFn(callback);
1165
- const signal = createSignal(data);
1166
- const component = getSetupContext(false);
1167
- const unListen = listen(signal, deps, callback, isContinue);
1168
- if (component) {
1169
- if (!component.unmountedCallbacks) {
1170
- component.unmountedCallbacks = [];
1171
- }
1172
- component.unmountedCallbacks.push(() => {
1173
- unListen();
1174
- });
1175
- }
1176
- return signal;
1177
- }
1178
- /* eslint-enable max-len*/
1179
- function watch(deps, callback) {
1180
- if (typeof deps === 'function' && !deps.$isSignal) {
1181
- deps = createDerived(deps);
1182
- }
1183
- const signals = Array.isArray(deps) ? deps : [deps];
1184
- let oldValues = signals.map(s => s());
1185
- let prevCleanup;
1186
- function effectCallback() {
1187
- if (typeof prevCleanup === 'function') {
1188
- prevCleanup();
1189
- }
1190
- const newValues = signals.map(s => s());
1191
- prevCleanup = Array.isArray(deps) ? callback(newValues, oldValues) : callback(newValues[0], oldValues[0]);
1192
- oldValues = newValues;
1193
- }
1194
- for (const dep of signals) {
1195
- dep[depsKey].add(effectCallback);
1196
- }
1197
- const component = getSetupContext(false);
1198
- let isClean = false;
1199
- const destroyFn = () => {
1200
- if (isClean) {
1201
- return;
1202
- }
1203
- isClean = true;
1204
- if (component === null || component === void 0 ? void 0 : component.unmountedCallbacks) {
1205
- const index = component.unmountedCallbacks.indexOf(destroyFn);
1206
- component.unmountedCallbacks.splice(index, 1);
1207
- }
1208
- for (const dep of signals) {
1209
- dep[depsKey].delete(effectCallback);
1210
- }
1211
- };
1212
- if (component) {
1213
- if (!component.unmountedCallbacks) {
1214
- component.unmountedCallbacks = [];
1215
- }
1216
- component.unmountedCallbacks.push(destroyFn);
1217
- }
1218
- return destroyFn;
1219
- }
1220
1050
  /**
1221
1051
  * 给组件添加注解
1222
1052
  * @param annotation
@@ -1741,6 +1571,9 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1741
1571
  if (!newAtom.child) {
1742
1572
  cleanElementChildren(oldAtom, nativeRenderer);
1743
1573
  }
1574
+ else if (!oldAtom.child) {
1575
+ buildElementChildren(newAtom, nativeRenderer, parentComponent, context);
1576
+ }
1744
1577
  else {
1745
1578
  diff(nativeRenderer, parentComponent, newAtom.child, oldAtom.child, context, false);
1746
1579
  }
@@ -1841,6 +1674,133 @@ class RootComponent extends Component {
1841
1674
  }
1842
1675
  }
1843
1676
 
1677
+ /**
1678
+ * 组件状态管理器
1679
+ * @param state 初始状态
1680
+ * @example
1681
+ * ```tsx
1682
+ * function App() {
1683
+ * // 初始化状态
1684
+ * const state = createSignal(1)
1685
+ *
1686
+ * return () => {
1687
+ * <div>
1688
+ * <div>当前值为:{state()}</div>
1689
+ * <div>
1690
+ * <button type="button" onClick={() => {
1691
+ * // 当点击时更新状态
1692
+ * state.set(state() + 1)
1693
+ * }
1694
+ * }>updateState</button>
1695
+ * </div>
1696
+ * </div>
1697
+ * }
1698
+ * }
1699
+ */
1700
+ function createSignal(state) {
1701
+ const subscribers = new Set();
1702
+ function signal() {
1703
+ const listener = getCurrentListener();
1704
+ if (listener) {
1705
+ listener.destroyCallbacks.push(() => {
1706
+ subscribers.delete(listener);
1707
+ });
1708
+ subscribers.add(listener);
1709
+ }
1710
+ return state;
1711
+ }
1712
+ signal.set = function (newValue) {
1713
+ if (newValue === state) {
1714
+ return;
1715
+ }
1716
+ state = newValue;
1717
+ const listeners = Array.from(subscribers);
1718
+ listeners.forEach(listener => listener.effect());
1719
+ };
1720
+ return signal;
1721
+ }
1722
+ /**
1723
+ * 使用派生值,Viewfly 会收集回调函数内同步执行时访问的 Signal,
1724
+ * 并在你获取 createDerived 函数返回的 Signal 的值时,自动计算最新的值。
1725
+ *
1726
+ * @param fn
1727
+ * @param isContinue 可选的停止函数,在每次值更新后调用,当返回值为 false 时,将不再监听依赖的变化
1728
+ */
1729
+ function computed(fn, isContinue) {
1730
+ let isStop = false;
1731
+ function canListen(value) {
1732
+ if (isContinue) {
1733
+ const b = isContinue(value);
1734
+ if (b === false) {
1735
+ listener.destroy();
1736
+ return false;
1737
+ }
1738
+ }
1739
+ return true;
1740
+ }
1741
+ const listener = new Listener(() => {
1742
+ if (isStop) {
1743
+ return;
1744
+ }
1745
+ isStop = true;
1746
+ listener.destroy();
1747
+ pushListener(listener);
1748
+ const value = fn();
1749
+ popListener();
1750
+ signal.set(value);
1751
+ canListen(value);
1752
+ isStop = false;
1753
+ });
1754
+ pushListener(listener);
1755
+ const value = fn();
1756
+ const signal = createSignal(value);
1757
+ popListener();
1758
+ isStop = false;
1759
+ if (canListen(value)) {
1760
+ registryComponentDestroyCallback(() => listener.destroy());
1761
+ }
1762
+ return signal;
1763
+ }
1764
+ const createDerived = computed;
1765
+ /* eslint-enable max-len*/
1766
+ function watch(deps, callback) {
1767
+ let prevFn;
1768
+ const isArray = Array.isArray(deps);
1769
+ const effect = new Listener(function () {
1770
+ if (prevFn) {
1771
+ prevFn();
1772
+ }
1773
+ const newValue = isArray ? deps.map(fn => fn()) : deps();
1774
+ prevFn = callback(newValue, oldValue);
1775
+ oldValue = newValue;
1776
+ });
1777
+ pushListener(effect);
1778
+ let oldValue = isArray ? deps.map(fn => fn()) : deps();
1779
+ popListener();
1780
+ let isUnWatch = false;
1781
+ function unWatch() {
1782
+ if (isUnWatch) {
1783
+ return;
1784
+ }
1785
+ isUnWatch = true;
1786
+ if (prevFn) {
1787
+ prevFn();
1788
+ }
1789
+ effect.destroy();
1790
+ }
1791
+ registryComponentDestroyCallback(unWatch);
1792
+ return unWatch;
1793
+ }
1794
+ function registryComponentDestroyCallback(fn) {
1795
+ const component = getSetupContext(false);
1796
+ if (component) {
1797
+ if (!component.unmountedCallbacks) {
1798
+ component.unmountedCallbacks = [];
1799
+ }
1800
+ component.unmountedCallbacks.push(fn);
1801
+ }
1802
+ }
1803
+
1844
1804
  const viewflyErrorFn = makeError('Viewfly');
1845
1805
  function viewfly(config) {
1846
1806
  const { context, nativeRenderer, autoUpdate, root } = Object.assign({ autoUpdate: true }, config);
@@ -1928,4 +1888,4 @@ function viewfly(config) {
1928
1888
  return app;
1929
1889
  }
1930
1890
 
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 };
1891
+ 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, computed, createDerived, createDynamicRef, createRef, createRenderer, createSignal, forwardRef, getCurrentInstance, getSetupContext, inject, jsx, jsxs, makeError, normalizeProvider, onMounted, onPropsChanged, onUnmounted, onUpdated, viewfly, watch, withAnnotation, withMemo };
package/bundles/index.js CHANGED
@@ -572,23 +572,6 @@ function getObjectChanges(newProps, oldProps) {
572
572
  }
573
573
  return changes;
574
574
  }
575
- function getArrayChanges(left, right) {
576
- const changes = {
577
- add: [],
578
- remove: []
579
- };
580
- for (const i of left) {
581
- if (!right.includes(i)) {
582
- changes.remove.push(i);
583
- }
584
- }
585
- for (const i of right) {
586
- if (!left.includes(i)) {
587
- changes.add.push(i);
588
- }
589
- }
590
- return changes;
591
- }
592
575
  function classToString(config) {
593
576
  if (typeof config === 'string') {
594
577
  return config;
@@ -637,8 +620,28 @@ const TextAtomType = Symbol('Text');
637
620
  const ElementAtomType = Symbol('Element');
638
621
  const ComponentAtomType = Symbol('Component');
639
622
 
623
+ class Listener {
624
+ constructor(effect) {
625
+ this.effect = effect;
626
+ this.destroyCallbacks = [];
627
+ }
628
+ destroy() {
629
+ this.destroyCallbacks.forEach(fn => fn());
630
+ this.destroyCallbacks = [];
631
+ }
632
+ }
633
+ const listeners = [];
634
+ function getCurrentListener() {
635
+ return listeners.at(-1);
636
+ }
637
+ function pushListener(listener) {
638
+ listeners.push(listener);
639
+ }
640
+ function popListener() {
641
+ listeners.pop();
642
+ }
643
+
640
644
  const componentSetupStack = [];
641
- const signalDepsStack = [];
642
645
  const componentErrorFn = makeError('component');
643
646
  function getSetupContext(need = true) {
644
647
  const current = componentSetupStack[componentSetupStack.length - 1];
@@ -648,9 +651,6 @@ function getSetupContext(need = true) {
648
651
  }
649
652
  return current;
650
653
  }
651
- function getSignalDepsContext() {
652
- return signalDepsStack[signalDepsStack.length - 1];
653
- }
654
654
  /**
655
655
  * Viewfly 组件管理类,用于管理组件的生命周期,上下文等
656
656
  */
@@ -677,6 +677,9 @@ class Component extends ReflectiveInjector {
677
677
  this._changed = true;
678
678
  this.isFirstRendering = true;
679
679
  this.refs = null;
680
+ this.listener = new Listener(() => {
681
+ this.markAsDirtied();
682
+ });
680
683
  }
681
684
  markAsDirtied() {
682
685
  this._dirty = true;
@@ -730,12 +733,9 @@ class Component extends ReflectiveInjector {
730
733
  }
731
734
  isSetup = false;
732
735
  componentSetupStack.pop();
733
- signalDepsStack.push([]);
736
+ pushListener(this.listener);
734
737
  const template = this.instance.$render();
735
- const deps = signalDepsStack.pop();
736
- this.unWatch = watch(Array.from(new Set(deps)), () => {
737
- this.markAsDirtied();
738
- });
738
+ popListener();
739
739
  update(template, this.instance.$portalHost);
740
740
  this.rendered();
741
741
  }
@@ -774,13 +774,10 @@ class Component extends ReflectiveInjector {
774
774
  return;
775
775
  }
776
776
  }
777
- this.unWatch();
778
- signalDepsStack.push([]);
777
+ this.listener.destroy();
778
+ pushListener(this.listener);
779
779
  const template = this.instance.$render();
780
- const deps = signalDepsStack.pop();
781
- this.unWatch = watch(Array.from(new Set(deps)), () => {
782
- this.markAsDirtied();
783
- });
780
+ popListener();
784
781
  updateChildren(template);
785
782
  this.rendered();
786
783
  }
@@ -790,7 +787,7 @@ class Component extends ReflectiveInjector {
790
787
  }
791
788
  destroy() {
792
789
  var _a, _b, _c;
793
- this.unWatch();
790
+ this.listener.destroy();
794
791
  (_a = this.updatedDestroyCallbacks) === null || _a === void 0 ? void 0 : _a.forEach(fn => {
795
792
  fn();
796
793
  });
@@ -1052,173 +1049,6 @@ class StaticRef extends DynamicRef {
1052
1049
  function createRef() {
1053
1050
  return new StaticRef();
1054
1051
  }
1055
- const depsKey = Symbol('deps');
1056
- /**
1057
- * 组件状态管理器
1058
- * @param state 初始状态
1059
- * @example
1060
- * ```tsx
1061
- * function App() {
1062
- * // 初始化状态
1063
- * const state = createSignal(1)
1064
- *
1065
- * return () => {
1066
- * <div>
1067
- * <div>当前值为:{state()}</div>
1068
- * <div>
1069
- * <button type="button" onClick={() => {
1070
- * // 当点击时更新状态
1071
- * state.set(state() + 1)
1072
- * }
1073
- * }>updateState</button>
1074
- * </div>
1075
- * </div>
1076
- * }
1077
- * }
1078
- */
1079
- function createSignal(state) {
1080
- function signal() {
1081
- const depsContext = getSignalDepsContext();
1082
- if (depsContext) {
1083
- depsContext.push(signal);
1084
- }
1085
- return state;
1086
- }
1087
- signal.$isSignal = true;
1088
- signal.set = function (newState) {
1089
- if (newState === state) {
1090
- return;
1091
- }
1092
- state = newState;
1093
- const depCallbacks = Array.from(signal[depsKey]);
1094
- for (const fn of depCallbacks) {
1095
- // 回调中可能会对依赖做出修改,故需先缓存起来
1096
- fn();
1097
- }
1098
- };
1099
- //
1100
- // signal.toString = function () {
1101
- // return String(state)
1102
- // }
1103
- //
1104
- // signal.valueOf = function () {
1105
- // return state
1106
- // }
1107
- signal[depsKey] = new Set();
1108
- return signal;
1109
- }
1110
- function invokeDepFn(fn) {
1111
- const deps = [];
1112
- signalDepsStack.push(deps);
1113
- const data = fn();
1114
- signalDepsStack.pop();
1115
- return {
1116
- deps: Array.from(new Set(deps)),
1117
- data
1118
- };
1119
- }
1120
- function listen(model, deps, callback, isContinue) {
1121
- let isStop = false;
1122
- const nextListen = () => {
1123
- if (isStop) {
1124
- return;
1125
- }
1126
- isStop = true;
1127
- const { data: nextData, deps: nextDeps } = invokeDepFn(callback);
1128
- model.set(nextData);
1129
- if (typeof isContinue === 'function' && isContinue(nextData) === false) {
1130
- unListen();
1131
- return;
1132
- }
1133
- const changes = getArrayChanges(deps, nextDeps);
1134
- deps = deps.filter(i => {
1135
- const has = changes.remove.includes(i);
1136
- if (has) {
1137
- i[depsKey].delete(nextListen);
1138
- return false;
1139
- }
1140
- return true;
1141
- });
1142
- for (const s of changes.add) {
1143
- s[depsKey].add(nextListen);
1144
- }
1145
- deps.push(...changes.add);
1146
- isStop = false;
1147
- };
1148
- const unListen = () => {
1149
- for (const s of deps) {
1150
- s[depsKey].delete(nextListen);
1151
- }
1152
- };
1153
- for (const s of deps) {
1154
- s[depsKey].add(nextListen);
1155
- }
1156
- return unListen;
1157
- }
1158
- /**
1159
- * 使用派生值,Viewfly 会收集回调函数内同步执行时访问的 Signal,
1160
- * 并在你获取 useDerived 函数返回的 Signal 的值时,自动计算最新的值。
1161
- *
1162
- * @param callback
1163
- * @param isContinue 可选的停止函数,在每次值更新后调用,当返回值为 false 时,将不再监听依赖的变化
1164
- */
1165
- function createDerived(callback, isContinue) {
1166
- const { data, deps } = invokeDepFn(callback);
1167
- const signal = createSignal(data);
1168
- const component = getSetupContext(false);
1169
- const unListen = listen(signal, deps, callback, isContinue);
1170
- if (component) {
1171
- if (!component.unmountedCallbacks) {
1172
- component.unmountedCallbacks = [];
1173
- }
1174
- component.unmountedCallbacks.push(() => {
1175
- unListen();
1176
- });
1177
- }
1178
- return signal;
1179
- }
1180
- /* eslint-enable max-len*/
1181
- function watch(deps, callback) {
1182
- if (typeof deps === 'function' && !deps.$isSignal) {
1183
- deps = createDerived(deps);
1184
- }
1185
- const signals = Array.isArray(deps) ? deps : [deps];
1186
- let oldValues = signals.map(s => s());
1187
- let prevCleanup;
1188
- function effectCallback() {
1189
- if (typeof prevCleanup === 'function') {
1190
- prevCleanup();
1191
- }
1192
- const newValues = signals.map(s => s());
1193
- prevCleanup = Array.isArray(deps) ? callback(newValues, oldValues) : callback(newValues[0], oldValues[0]);
1194
- oldValues = newValues;
1195
- }
1196
- for (const dep of signals) {
1197
- dep[depsKey].add(effectCallback);
1198
- }
1199
- const component = getSetupContext(false);
1200
- let isClean = false;
1201
- const destroyFn = () => {
1202
- if (isClean) {
1203
- return;
1204
- }
1205
- isClean = true;
1206
- if (component === null || component === void 0 ? void 0 : component.unmountedCallbacks) {
1207
- const index = component.unmountedCallbacks.indexOf(destroyFn);
1208
- component.unmountedCallbacks.splice(index, 1);
1209
- }
1210
- for (const dep of signals) {
1211
- dep[depsKey].delete(effectCallback);
1212
- }
1213
- };
1214
- if (component) {
1215
- if (!component.unmountedCallbacks) {
1216
- component.unmountedCallbacks = [];
1217
- }
1218
- component.unmountedCallbacks.push(destroyFn);
1219
- }
1220
- return destroyFn;
1221
- }
1222
1052
  /**
1223
1053
  * 给组件添加注解
1224
1054
  * @param annotation
@@ -1743,6 +1573,9 @@ function updateNativeNodeProperties(nativeRenderer, newAtom, oldAtom, parentComp
1743
1573
  if (!newAtom.child) {
1744
1574
  cleanElementChildren(oldAtom, nativeRenderer);
1745
1575
  }
1576
+ else if (!oldAtom.child) {
1577
+ buildElementChildren(newAtom, nativeRenderer, parentComponent, context);
1578
+ }
1746
1579
  else {
1747
1580
  diff(nativeRenderer, parentComponent, newAtom.child, oldAtom.child, context, false);
1748
1581
  }
@@ -1843,6 +1676,133 @@ class RootComponent extends Component {
1843
1676
  }
1844
1677
  }
1845
1678
 
1679
+ /**
1680
+ * 组件状态管理器
1681
+ * @param state 初始状态
1682
+ * @example
1683
+ * ```tsx
1684
+ * function App() {
1685
+ * // 初始化状态
1686
+ * const state = createSignal(1)
1687
+ *
1688
+ * return () => {
1689
+ * <div>
1690
+ * <div>当前值为:{state()}</div>
1691
+ * <div>
1692
+ * <button type="button" onClick={() => {
1693
+ * // 当点击时更新状态
1694
+ * state.set(state() + 1)
1695
+ * }
1696
+ * }>updateState</button>
1697
+ * </div>
1698
+ * </div>
1699
+ * }
1700
+ * }
1701
+ */
1702
+ function createSignal(state) {
1703
+ const subscribers = new Set();
1704
+ function signal() {
1705
+ const listener = getCurrentListener();
1706
+ if (listener) {
1707
+ listener.destroyCallbacks.push(() => {
1708
+ subscribers.delete(listener);
1709
+ });
1710
+ subscribers.add(listener);
1711
+ }
1712
+ return state;
1713
+ }
1714
+ signal.set = function (newValue) {
1715
+ if (newValue === state) {
1716
+ return;
1717
+ }
1718
+ state = newValue;
1719
+ const listeners = Array.from(subscribers);
1720
+ listeners.forEach(listener => listener.effect());
1721
+ };
1722
+ return signal;
1723
+ }
1724
+ /**
1725
+ * 使用派生值,Viewfly 会收集回调函数内同步执行时访问的 Signal,
1726
+ * 并在你获取 createDerived 函数返回的 Signal 的值时,自动计算最新的值。
1727
+ *
1728
+ * @param fn
1729
+ * @param isContinue 可选的停止函数,在每次值更新后调用,当返回值为 false 时,将不再监听依赖的变化
1730
+ */
1731
+ function computed(fn, isContinue) {
1732
+ let isStop = false;
1733
+ function canListen(value) {
1734
+ if (isContinue) {
1735
+ const b = isContinue(value);
1736
+ if (b === false) {
1737
+ listener.destroy();
1738
+ return false;
1739
+ }
1740
+ }
1741
+ return true;
1742
+ }
1743
+ const listener = new Listener(() => {
1744
+ if (isStop) {
1745
+ return;
1746
+ }
1747
+ isStop = true;
1748
+ listener.destroy();
1749
+ pushListener(listener);
1750
+ const value = fn();
1751
+ popListener();
1752
+ signal.set(value);
1753
+ canListen(value);
1754
+ isStop = false;
1755
+ });
1756
+ pushListener(listener);
1757
+ const value = fn();
1758
+ const signal = createSignal(value);
1759
+ popListener();
1760
+ isStop = false;
1761
+ if (canListen(value)) {
1762
+ registryComponentDestroyCallback(() => listener.destroy());
1763
+ }
1764
+ return signal;
1765
+ }
1766
+ const createDerived = computed;
1767
+ /* eslint-enable max-len*/
1768
+ function watch(deps, callback) {
1769
+ let prevFn;
1770
+ const isArray = Array.isArray(deps);
1771
+ const effect = new Listener(function () {
1772
+ if (prevFn) {
1773
+ prevFn();
1774
+ }
1775
+ const newValue = isArray ? deps.map(fn => fn()) : deps();
1776
+ prevFn = callback(newValue, oldValue);
1777
+ oldValue = newValue;
1778
+ });
1779
+ pushListener(effect);
1780
+ let oldValue = isArray ? deps.map(fn => fn()) : deps();
1781
+ popListener();
1782
+ let isUnWatch = false;
1783
+ function unWatch() {
1784
+ if (isUnWatch) {
1785
+ return;
1786
+ }
1787
+ isUnWatch = true;
1788
+ if (prevFn) {
1789
+ prevFn();
1790
+ }
1791
+ effect.destroy();
1792
+ }
1793
+ registryComponentDestroyCallback(unWatch);
1794
+ return unWatch;
1795
+ }
1796
+ function registryComponentDestroyCallback(fn) {
1797
+ const component = getSetupContext(false);
1798
+ if (component) {
1799
+ if (!component.unmountedCallbacks) {
1800
+ component.unmountedCallbacks = [];
1801
+ }
1802
+ component.unmountedCallbacks.push(fn);
1803
+ }
1804
+ }
1805
+
1846
1806
  const viewflyErrorFn = makeError('Viewfly');
1847
1807
  function viewfly(config) {
1848
1808
  const { context, nativeRenderer, autoUpdate, root } = Object.assign({ autoUpdate: true }, config);
@@ -1952,6 +1912,7 @@ exports.SkipSelf = SkipSelf;
1952
1912
  exports.StaticRef = StaticRef;
1953
1913
  exports.THROW_IF_NOT_FOUND = THROW_IF_NOT_FOUND;
1954
1914
  exports.Type = Type;
1915
+ exports.computed = computed;
1955
1916
  exports.createDerived = createDerived;
1956
1917
  exports.createDynamicRef = createDynamicRef;
1957
1918
  exports.createRef = createRef;
@@ -1959,6 +1920,7 @@ exports.createRenderer = createRenderer;
1959
1920
  exports.createSignal = createSignal;
1960
1921
  exports.forwardRef = forwardRef;
1961
1922
  exports.getCurrentInstance = getCurrentInstance;
1923
+ exports.getSetupContext = getSetupContext;
1962
1924
  exports.inject = inject;
1963
1925
  exports.jsx = jsx;
1964
1926
  exports.jsxs = jsxs;
@@ -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.2",
3
+ "version": "1.0.5",
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",