@yiin/reactive-proxy-state 1.0.15 → 1.0.17

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.
@@ -1,13 +1,16 @@
1
+ import { WatchEffectStopHandle } from './watch-effect';
1
2
  import { Ref, isRefSymbol } from './ref';
2
3
  declare const isComputedSymbol: unique symbol;
3
4
  export interface ComputedRef<T = any> extends Omit<Ref<T>, 'value'> {
4
5
  readonly value: T;
5
6
  readonly [isComputedSymbol]: true;
6
7
  readonly [isRefSymbol]: true;
8
+ readonly effect: WatchEffectStopHandle<T>;
7
9
  }
8
10
  export interface WritableComputedRef<T> extends Ref<T> {
9
11
  readonly [isComputedSymbol]: true;
10
12
  readonly [isRefSymbol]: true;
13
+ readonly effect: WatchEffectStopHandle<T>;
11
14
  }
12
15
  type ComputedGetter<T> = () => T;
13
16
  type ComputedSetter<T> = (v: T) => void;
package/dist/index.js CHANGED
@@ -58,6 +58,26 @@ function deepEqual(a, b, seen = globalSeen) {
58
58
  let result;
59
59
  if (Array.isArray(a)) {
60
60
  result = a.length === b.length && a.every((val, idx) => deepEqual(val, b[idx], seen));
61
+ } else if (a instanceof Map && b instanceof Map) {
62
+ result = a.size === b.size;
63
+ if (result) {
64
+ for (const [key, value] of a) {
65
+ if (!b.has(key) || !deepEqual(value, b.get(key), seen)) {
66
+ result = false;
67
+ break;
68
+ }
69
+ }
70
+ }
71
+ } else if (a instanceof Set && b instanceof Set) {
72
+ result = a.size === b.size;
73
+ if (result) {
74
+ for (const value of a) {
75
+ if (!b.has(value)) {
76
+ result = false;
77
+ break;
78
+ }
79
+ }
80
+ }
61
81
  } else {
62
82
  const keysA = Object.keys(a);
63
83
  const keysB = Object.keys(b);
@@ -120,7 +140,8 @@ function traverse(value, seen = new Set) {
120
140
  traverse(value[i], seen);
121
141
  }
122
142
  } else if (value instanceof Set || value instanceof Map) {
123
- for (const v of value) {
143
+ const rawValue = value.__v_raw || value;
144
+ for (const v of rawValue) {
124
145
  if (Array.isArray(v)) {
125
146
  traverse(v[0], seen);
126
147
  traverse(v[1], seen);
@@ -465,12 +486,17 @@ function flushEffects() {
465
486
  }
466
487
  }
467
488
  for (const effect of effectsToRun) {
468
- if (effect.active) {
469
- if (effect.options?.scheduler) {
470
- effect.options.scheduler(effect.run);
471
- } else {
472
- effect.run();
473
- }
489
+ if (!effect.active)
490
+ continue;
491
+ if (effect.options?.scheduler) {
492
+ effect.options.scheduler(effect.run);
493
+ }
494
+ }
495
+ for (const effect of effectsToRun) {
496
+ if (!effect.active)
497
+ continue;
498
+ if (!effect.options?.scheduler) {
499
+ effect.run();
474
500
  }
475
501
  }
476
502
  } finally {
@@ -513,12 +539,7 @@ function trigger(target, key) {
513
539
  function watchEffect(effectCallback, options = {}) {
514
540
  const run = () => {
515
541
  if (!effectFn.active) {
516
- try {
517
- return effectCallback();
518
- } catch (e) {
519
- console.error("error in stopped watchEffect callback:", e);
520
- return;
521
- }
542
+ throw new Error("Trying to run a stopped effect");
522
543
  }
523
544
  const previousEffect = activeEffect;
524
545
  try {
@@ -719,6 +740,9 @@ function wrapSet(set, emit, path = []) {
719
740
  track(target, "size");
720
741
  return target.size;
721
742
  }
743
+ if (prop === "constructor") {
744
+ return Set;
745
+ }
722
746
  const value = Reflect.get(target, prop, receiver);
723
747
  if (typeof value === "function") {
724
748
  return value.bind(target);
@@ -957,6 +981,9 @@ function wrapMap(map, emit, path = []) {
957
981
  track(target, "size");
958
982
  return target.size;
959
983
  }
984
+ if (prop === "constructor") {
985
+ return Map;
986
+ }
960
987
  const value = Reflect.get(target, prop, receiver);
961
988
  if (typeof value === "function") {
962
989
  return value.bind(target);
@@ -1325,35 +1352,6 @@ function reactive(obj, emit, path = []) {
1325
1352
  globalSeen.set(obj, proxy);
1326
1353
  return proxy;
1327
1354
  }
1328
- // src/watch.ts
1329
- function watch(sourceInput, callback, options = {}) {
1330
- const { immediate = false, deep = true } = options;
1331
- const source = typeof sourceInput === "function" ? sourceInput : () => sourceInput;
1332
- let oldValue;
1333
- let initialized = false;
1334
- const stopEffect = watchEffect(() => {
1335
- const currentValue = source();
1336
- if (deep) {
1337
- traverse(currentValue);
1338
- }
1339
- if (initialized) {
1340
- let hasChanged = false;
1341
- hasChanged = deep || currentValue !== oldValue;
1342
- if (hasChanged) {
1343
- const prevOldValue = oldValue;
1344
- oldValue = deep ? deepClone(currentValue) : currentValue;
1345
- callback(currentValue, prevOldValue);
1346
- }
1347
- } else {
1348
- oldValue = deep ? deepClone(currentValue) : currentValue;
1349
- initialized = true;
1350
- if (immediate) {
1351
- callback(currentValue, undefined);
1352
- }
1353
- }
1354
- }, { lazy: false });
1355
- return stopEffect;
1356
- }
1357
1355
  // src/ref.ts
1358
1356
  var isRefSymbol = Symbol("isRef");
1359
1357
  function ref(value) {
@@ -1407,6 +1405,7 @@ function toRef(object, key) {
1407
1405
  function triggerRef(ref2) {
1408
1406
  trigger(ref2, "value");
1409
1407
  }
1408
+
1410
1409
  // src/computed.ts
1411
1410
  var isComputedSymbol = Symbol("isComputed");
1412
1411
  function computed(getterOrOptions) {
@@ -1449,13 +1448,82 @@ function computed(getterOrOptions) {
1449
1448
  } else {
1450
1449
  console.warn("computed value is read-only");
1451
1450
  }
1452
- }
1451
+ },
1452
+ effect: stopHandle
1453
1453
  };
1454
1454
  return computedRef;
1455
1455
  }
1456
1456
  function isComputed(c) {
1457
1457
  return !!(c && c[isComputedSymbol]);
1458
1458
  }
1459
+
1460
+ // src/watch.ts
1461
+ function watch(source, callback, options = {}) {
1462
+ const { immediate = false, deep = true } = options;
1463
+ const isMultiSource = Array.isArray(source);
1464
+ const getter = () => {
1465
+ if (isMultiSource) {
1466
+ return source.map((s) => {
1467
+ if (isRef(s))
1468
+ return s.value;
1469
+ if (isComputed(s))
1470
+ return s.value;
1471
+ if (typeof s === "function")
1472
+ return s();
1473
+ return s;
1474
+ });
1475
+ }
1476
+ if (isRef(source))
1477
+ return source.value;
1478
+ if (isComputed(source))
1479
+ return source.value;
1480
+ if (typeof source === "function")
1481
+ return source();
1482
+ return source;
1483
+ };
1484
+ let oldValue;
1485
+ let initialized = false;
1486
+ const stopEffect = watchEffect(() => {
1487
+ let currentValue = getter();
1488
+ if (deep) {
1489
+ traverse(currentValue);
1490
+ }
1491
+ const job = () => {
1492
+ if (initialized) {
1493
+ let hasChanged = false;
1494
+ if (isMultiSource) {
1495
+ if (!Array.isArray(oldValue) || currentValue.length !== oldValue.length) {
1496
+ hasChanged = true;
1497
+ } else {
1498
+ hasChanged = currentValue.some((val, i) => {
1499
+ return deep ? !deepEqual(val, oldValue[i]) : val !== oldValue[i];
1500
+ });
1501
+ }
1502
+ } else {
1503
+ hasChanged = deep ? !deepEqual(currentValue, oldValue) : currentValue !== oldValue;
1504
+ }
1505
+ if (hasChanged) {
1506
+ const prevOldValue = oldValue;
1507
+ if (isMultiSource) {
1508
+ currentValue = getter();
1509
+ }
1510
+ const valueToClone = currentValue && typeof currentValue === "object" && currentValue.__v_raw ? currentValue.__v_raw : currentValue;
1511
+ oldValue = deep ? deepClone(valueToClone) : currentValue;
1512
+ callback(currentValue, prevOldValue);
1513
+ }
1514
+ } else {
1515
+ const valueToClone = currentValue && typeof currentValue === "object" && currentValue.__v_raw ? currentValue.__v_raw : currentValue;
1516
+ oldValue = deep ? deepClone(valueToClone) : currentValue;
1517
+ initialized = true;
1518
+ if (immediate) {
1519
+ callback(currentValue, undefined);
1520
+ }
1521
+ }
1522
+ };
1523
+ job();
1524
+ });
1525
+ return stopEffect;
1526
+ }
1459
1527
  export {
1460
1528
  wrapperCache,
1461
1529
  wrapSet,
package/dist/types.d.ts CHANGED
@@ -12,3 +12,11 @@ export interface StateEvent {
12
12
  oldValues?: any[];
13
13
  }
14
14
  export type EmitFunction = (event: StateEvent) => void;
15
+ import { Ref } from './ref';
16
+ import { ComputedRef } from './computed';
17
+ export type BaseWatchSource<T = any> = Ref<T> | ComputedRef<T> | (() => T);
18
+ export type WatchSource<T = any> = BaseWatchSource<T> | T;
19
+ export type UnwrapWatchSource<T> = T extends BaseWatchSource<infer V> ? V : T extends object ? T : T;
20
+ export type UnwrapWatchSources<T> = {
21
+ -readonly [K in keyof T]: UnwrapWatchSource<T[K]>;
22
+ };
@@ -1,4 +1,4 @@
1
- type EffectCallback<T = any> = (onCleanup?: (cleanupFn: () => void) => void) => T;
1
+ type EffectCallback<T = any> = (onCleanup: (cleanupFn: () => void) => void) => T;
2
2
  type Scheduler = (job: () => void) => void;
3
3
  export interface WatchEffectStopHandle<T = any> {
4
4
  (): void;
package/dist/watch.d.ts CHANGED
@@ -1,14 +1,11 @@
1
- type WatchCallback<T = any> = (newValue: T, oldValue: T | undefined) => void;
2
- type WatchSource<T = any> = () => T;
3
- type WatchSourceInput<T = any> = WatchSource<T> | T;
1
+ import { WatchSource, UnwrapWatchSource, UnwrapWatchSources } from './types';
2
+ type WatchCallback<T, O> = (newValue: T, oldValue: O) => void;
4
3
  type WatchStopHandle = () => void;
5
4
  export interface WatchOptions {
6
5
  immediate?: boolean;
7
6
  deep?: boolean;
8
7
  }
9
- /**
10
- * watches a reactive source (getter function or reactive object/ref)
11
- * and runs a callback when the source's value changes.
12
- */
13
- export declare function watch<T = any>(sourceInput: WatchSourceInput<T>, callback: WatchCallback<T>, options?: WatchOptions): WatchStopHandle;
8
+ export declare function watch<T extends readonly WatchSource<unknown>[], Immediate extends Readonly<boolean> = false>(sources: [...T], callback: WatchCallback<UnwrapWatchSources<T>, Immediate extends true ? (UnwrapWatchSources<T> | undefined) : UnwrapWatchSources<T>>, options?: WatchOptions): WatchStopHandle;
9
+ export declare function watch<T, Immediate extends Readonly<boolean> = false>(source: () => T, callback: WatchCallback<T, Immediate extends true ? T | undefined : T>, options?: WatchOptions): WatchStopHandle;
10
+ export declare function watch<T, Immediate extends Readonly<boolean> = false>(source: WatchSource<T>, callback: WatchCallback<UnwrapWatchSource<T>, Immediate extends true ? (UnwrapWatchSource<T> | undefined) : UnwrapWatchSource<T>>, options?: WatchOptions): WatchStopHandle;
14
11
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yiin/reactive-proxy-state",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "author": "Yiin <stanislovas@yiin.lt>",
5
5
  "repository": {
6
6
  "type": "git",