react-obsidian 0.0.46 → 1.0.0

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.
Files changed (63) hide show
  1. package/.vscode/settings.json +5 -0
  2. package/babel.config.js +1 -1
  3. package/dist/src/index.d.ts +3 -1
  4. package/dist/src/index.d.ts.map +1 -1
  5. package/dist/src/index.js +6 -2
  6. package/dist/src/index.js.map +1 -1
  7. package/dist/src/model/Model.d.ts +4 -0
  8. package/dist/src/model/Model.d.ts.map +1 -0
  9. package/dist/src/model/Model.js +19 -0
  10. package/dist/src/model/Model.js.map +1 -0
  11. package/dist/src/observable/Observable.d.ts +1 -1
  12. package/dist/src/observable/Observable.d.ts.map +1 -1
  13. package/dist/src/observable/Observable.js +2 -1
  14. package/dist/src/observable/Observable.js.map +1 -1
  15. package/dist/src/observable/cold/ColdMediatorObservable.d.ts +18 -0
  16. package/dist/src/observable/cold/ColdMediatorObservable.d.ts.map +1 -0
  17. package/dist/src/observable/cold/ColdMediatorObservable.js +46 -0
  18. package/dist/src/observable/cold/ColdMediatorObservable.js.map +1 -0
  19. package/dist/src/observable/cold/useColdObservers.d.ts +3 -0
  20. package/dist/src/observable/cold/useColdObservers.d.ts.map +1 -0
  21. package/dist/src/observable/cold/useColdObservers.js +21 -0
  22. package/dist/src/observable/cold/useColdObservers.js.map +1 -0
  23. package/dist/src/observable/mapObservablesToValues.d.ts +3 -0
  24. package/dist/src/observable/mapObservablesToValues.d.ts.map +1 -0
  25. package/dist/src/observable/mapObservablesToValues.js +8 -0
  26. package/dist/src/observable/mapObservablesToValues.js.map +1 -0
  27. package/dist/src/observable/mediator/MediatorObservable.d.ts +6 -0
  28. package/dist/src/observable/mediator/MediatorObservable.d.ts.map +1 -0
  29. package/dist/src/observable/{MediatorObservable.js → mediator/MediatorObservable.js} +1 -1
  30. package/dist/src/observable/mediator/MediatorObservable.js.map +1 -0
  31. package/dist/src/observable/types.d.ts +3 -0
  32. package/dist/src/observable/types.d.ts.map +1 -1
  33. package/dist/src/observable/useObserver.d.ts +4 -2
  34. package/dist/src/observable/useObserver.d.ts.map +1 -1
  35. package/dist/src/observable/useObserver.js +6 -1
  36. package/dist/src/observable/useObserver.js.map +1 -1
  37. package/dist/src/observable/useObservers.d.ts +3 -0
  38. package/dist/src/observable/useObservers.d.ts.map +1 -0
  39. package/dist/src/observable/useObservers.js +21 -0
  40. package/dist/src/observable/useObservers.js.map +1 -0
  41. package/documentation/docs/documentation/installation.mdx +1 -1
  42. package/documentation/docs/documentation/usage/Reactivity.mdx +20 -0
  43. package/documentation/package-lock.json +7 -7
  44. package/documentation/package.json +1 -1
  45. package/documentation/yarn.lock +8167 -0
  46. package/global.d.ts +1 -0
  47. package/jest.config.js +2 -1
  48. package/package.json +10 -8
  49. package/src/index.ts +4 -1
  50. package/src/model/Model.ts +15 -0
  51. package/src/observable/Observable.ts +2 -1
  52. package/src/observable/cold/ColdMediatorObservable.ts +47 -0
  53. package/src/observable/cold/useColdObservers.ts +23 -0
  54. package/src/observable/mapObservablesToValues.ts +7 -0
  55. package/src/observable/mediator/MediatorObservable.ts +9 -0
  56. package/src/observable/types.ts +2 -0
  57. package/src/observable/useObserver.ts +18 -3
  58. package/src/observable/useObservers.ts +21 -0
  59. package/tsconfig.base.json +2 -1
  60. package/dist/src/observable/MediatorObservable.d.ts +0 -6
  61. package/dist/src/observable/MediatorObservable.d.ts.map +0 -1
  62. package/dist/src/observable/MediatorObservable.js.map +0 -1
  63. package/src/observable/MediatorObservable.ts +0 -9
package/global.d.ts ADDED
@@ -0,0 +1 @@
1
+ import 'jest-extended';
package/jest.config.js CHANGED
@@ -8,7 +8,8 @@ const config = {
8
8
  'test',
9
9
  ],
10
10
  setupFilesAfterEnv: [
11
- './jest.setup-after-env.js'
11
+ './jest.setup-after-env.js',
12
+ 'jest-extended/all'
12
13
  ],
13
14
  testEnvironment: 'jsdom'
14
15
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-obsidian",
3
- "version": "0.0.46",
3
+ "version": "1.0.0",
4
4
  "description": "Dependency injection framework for React and React Native applications",
5
5
  "scripts": {
6
6
  "prepack": "npm run lint && tsc --project tsconfig.prod.json",
@@ -20,12 +20,13 @@
20
20
  "react": "*"
21
21
  },
22
22
  "devDependencies": {
23
- "@babel/core": "7.20.x",
24
- "@babel/plugin-proposal-decorators": "7.18.x",
25
- "@babel/preset-env": "7.20.x",
26
- "@babel/preset-react": "7.18.x",
27
- "@babel/preset-typescript": "7.18.x",
28
- "@babel/types": "7.20.x",
23
+ "@babel/core": "7.22.x",
24
+ "@babel/plugin-proposal-decorators": "7.22.x",
25
+ "@babel/plugin-transform-class-properties": "7.22.x",
26
+ "@babel/preset-env": "7.22.x",
27
+ "@babel/preset-react": "7.22.x",
28
+ "@babel/preset-typescript": "7.22.x",
29
+ "@babel/types": "7.22.x",
29
30
  "@johanblumenberg/ts-mockito": "1.x.x",
30
31
  "@testing-library/react": "14.x.x",
31
32
  "@testing-library/react-hooks": "^7.0.2",
@@ -48,6 +49,7 @@
48
49
  "eslint-plugin-unused-imports": "2.x.x",
49
50
  "jest": "29.5.x",
50
51
  "jest-environment-jsdom": "^29.5.0",
52
+ "jest-extended": "^4.0.0",
51
53
  "lodash": "^4.17.21",
52
54
  "react": "18.2.x",
53
55
  "react-dom": "18.2.x",
@@ -79,4 +81,4 @@
79
81
  "url": "https://github.com/wix-incubator/react-obsidian/issues"
80
82
  },
81
83
  "homepage": "https://github.com/wix-incubator/react-obsidian#readme"
82
- }
84
+ }
package/src/index.ts CHANGED
@@ -20,8 +20,11 @@ export { injectComponent } from './injectors/components/InjectComponent';
20
20
  export { injectHook, injectHookWithArguments } from './injectors/hooks/InjectHook';
21
21
 
22
22
  export { useObserver } from './observable/useObserver';
23
+ export { useObservers } from './observable/useObservers';
23
24
  export { Observable } from './observable/Observable';
24
- export { MediatorObservable } from './observable/MediatorObservable';
25
+ export { MediatorObservable } from './observable/mediator/MediatorObservable';
25
26
  export { OnNext, Unsubscribe } from './observable/types';
26
27
 
28
+ export { Model } from './model/Model';
29
+
27
30
  export { testKit } from '../testkit';
@@ -0,0 +1,15 @@
1
+ import { useColdObservables } from '../observable/cold/useColdObservers';
2
+ import { Observable } from '../observable/Observable';
3
+
4
+ export abstract class Model {
5
+ public use<T extends Model>(this: T) {
6
+ const observables: Record<string, Observable<any>> = {};
7
+ Object.getOwnPropertyNames(this).forEach((propertyName: string) => {
8
+ const property = (this as any)[propertyName];
9
+ if (property instanceof Observable) {
10
+ observables[propertyName] = property;
11
+ }
12
+ });
13
+ return useColdObservables<T>(observables as any);
14
+ }
15
+ }
@@ -1,5 +1,6 @@
1
1
  import { Observable as IObservable, OnNext, Unsubscribe } from './types';
2
2
 
3
+ const NOOP = () => {};
3
4
  export class Observable<T> implements IObservable<T> {
4
5
  private subscribers: Set<OnNext<T>> = new Set();
5
6
  private currentValue: T | undefined;
@@ -17,7 +18,7 @@ export class Observable<T> implements IObservable<T> {
17
18
  this.subscribers.forEach((subscriber) => subscriber(value));
18
19
  }
19
20
 
20
- public subscribe(onNext: OnNext<T>): Unsubscribe {
21
+ public subscribe(onNext: OnNext<T> = NOOP): Unsubscribe {
21
22
  if (this.subscribers.has(onNext)) {
22
23
  throw new Error('Subscriber already subscribed');
23
24
  }
@@ -0,0 +1,47 @@
1
+ import { MediatorObservable } from '../mediator/MediatorObservable';
2
+
3
+ export class ColdMediatorObservable<T extends object> extends MediatorObservable<T> {
4
+ constructor(obj: T, private readonly handler = new PropertyAccessTrackingProxy<T>()) {
5
+ super(new Proxy(obj, handler));
6
+ }
7
+
8
+ override set value(_: T) {
9
+ throw new Error('Cannot set value of ColdMediatorObservable, use setValue(value, key) instead');
10
+ }
11
+
12
+ override get value(): T {
13
+ return super.value;
14
+ }
15
+
16
+ setValue(key: keyof T, value: any) {
17
+ if (this.handler.hasAccessedProperty(key)) {
18
+ this.handler.suspendTracking();
19
+ super.value = { ...this.value, [key]: value };
20
+ this.handler.resumeTracking();
21
+ }
22
+ }
23
+ }
24
+
25
+ class PropertyAccessTrackingProxy<T extends object> implements ProxyHandler<T> {
26
+ private readonly accessedProperties = new Set<keyof T>();
27
+ private trackingSuspended = false;
28
+
29
+ get(target: T, p: string | symbol, receiver: any) {
30
+ if (!this.trackingSuspended) {
31
+ this.accessedProperties.add(p as keyof T);
32
+ }
33
+ return Reflect.get(target, p, receiver);
34
+ }
35
+
36
+ hasAccessedProperty(key: keyof T) {
37
+ return this.accessedProperties.has(key);
38
+ }
39
+
40
+ public suspendTracking() {
41
+ this.trackingSuspended = true;
42
+ }
43
+
44
+ public resumeTracking() {
45
+ this.trackingSuspended = false;
46
+ }
47
+ }
@@ -0,0 +1,23 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { ColdMediatorObservable } from './ColdMediatorObservable';
3
+ import { ObservedValues } from '../types';
4
+ import { mapObservablesToValues } from '../mapObservablesToValues';
5
+
6
+ export function useColdObservables<T extends Record<string, any>>(observables: T): ObservedValues<T> {
7
+ const [mediator] = useState(
8
+ () => new ColdMediatorObservable<T>(mapObservablesToValues(observables) as T),
9
+ );
10
+ const [values, setValues] = useState(() => mediator.value as ObservedValues<T>);
11
+
12
+ useEffect(() => {
13
+ Object.keys(observables as {}).forEach((key) => {
14
+ mediator.addSource(observables[key], (value) => {
15
+ mediator.setValue(key, value);
16
+ });
17
+ });
18
+
19
+ return mediator.subscribe(setValues);
20
+ }, []);
21
+
22
+ return values;
23
+ }
@@ -0,0 +1,7 @@
1
+ import { ObservedValues } from './types';
2
+
3
+ export function mapObservablesToValues<T extends Record<string, any>>(observables: T): ObservedValues<T> {
4
+ return Object.fromEntries(
5
+ Object.entries(observables).map(([key, observable]) => [key, observable.value]),
6
+ ) as ObservedValues<T>;
7
+ }
@@ -0,0 +1,9 @@
1
+ import { Observable } from '../Observable';
2
+ import { OnNext } from '../types';
3
+
4
+ export class MediatorObservable<T> extends Observable<T> {
5
+ addSource<S>(source: Observable<S>, onNext: OnNext<S>) {
6
+ source.subscribe(onNext);
7
+ return this;
8
+ }
9
+ }
@@ -5,3 +5,5 @@ export interface Observable<T> {
5
5
  value: T;
6
6
  subscribe(onNext: OnNext<T>): Unsubscribe;
7
7
  }
8
+
9
+ export type ObservedValues<T> = { [K in keyof T]: T[K] extends Observable<infer R> ? R : never };
@@ -1,8 +1,19 @@
1
1
  /* eslint-disable no-param-reassign */
2
- import { useCallback, useEffect, useState } from 'react';
3
- import { Observable } from './types';
2
+ import {
3
+ useCallback,
4
+ useEffect,
5
+ useMemo,
6
+ useState,
7
+ } from 'react';
8
+ import { Observable } from './Observable';
4
9
 
5
- export function useObserver<T>(observable: Observable<T>): [T, (next: T) => void] {
10
+ type ObservableOrGenerator<T> = Observable<T> | (() => Observable<T>);
11
+
12
+ export function useObserver<T>(observableOrGenerator: ObservableOrGenerator<T>): [T, (next: T) => void] {
13
+ const observable = useMemo(
14
+ () => getOrGenerateObservable(observableOrGenerator),
15
+ [],
16
+ );
6
17
  const [value, setValue] = useState(observable.value);
7
18
  const onNext = useCallback((next: T) => {
8
19
  observable.value = next;
@@ -14,3 +25,7 @@ export function useObserver<T>(observable: Observable<T>): [T, (next: T) => void
14
25
 
15
26
  return [value, onNext];
16
27
  }
28
+
29
+ function getOrGenerateObservable(observableOrGenerator: ObservableOrGenerator<any>) {
30
+ return observableOrGenerator instanceof Observable ? observableOrGenerator : observableOrGenerator();
31
+ }
@@ -0,0 +1,21 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { MediatorObservable } from './mediator/MediatorObservable';
3
+ import { ObservedValues } from './types';
4
+ import { mapObservablesToValues } from './mapObservablesToValues';
5
+
6
+ export function useObservers<T extends Record<string, any>>(observables: T): ObservedValues<T> {
7
+ const [values, setValues] = useState(() => mapObservablesToValues(observables));
8
+
9
+ useEffect(() => {
10
+ const mediator = new MediatorObservable();
11
+ Object.keys(observables as {}).forEach((key) => {
12
+ mediator.addSource(observables[key], (value) => {
13
+ setValues({ ...values, [key]: value });
14
+ });
15
+ });
16
+
17
+ return mediator.subscribe();
18
+ }, []);
19
+
20
+ return values;
21
+ }
@@ -3,7 +3,8 @@
3
3
  "src/**/*",
4
4
  "transformers/**/*",
5
5
  "test/**/*",
6
- "./clearGraphs.ts"
6
+ "./clearGraphs.ts",
7
+ "global.d.ts"
7
8
  ],
8
9
  "exclude": [
9
10
  "node_modules",
@@ -1,6 +0,0 @@
1
- import { Observable } from './Observable';
2
- import { OnNext } from './types';
3
- export declare class MediatorObservable<T> extends Observable<T> {
4
- addSource<S>(source: Observable<S>, onNext: OnNext<S>): MediatorObservable<T>;
5
- }
6
- //# sourceMappingURL=MediatorObservable.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"MediatorObservable.d.ts","sourceRoot":"","sources":["../../../src/observable/MediatorObservable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,qBAAa,kBAAkB,CAAC,CAAC,CAAE,SAAQ,UAAU,CAAC,CAAC,CAAC;IACtD,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC;CAI9E"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"MediatorObservable.js","sourceRoot":"","sources":["../../../src/observable/MediatorObservable.ts"],"names":[],"mappings":";;;AAAA,6CAA0C;AAG1C,MAAa,kBAAsB,SAAQ,uBAAa;IACtD,SAAS,CAAI,MAAqB,EAAE,MAAiB;QACnD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AALD,gDAKC"}
@@ -1,9 +0,0 @@
1
- import { Observable } from './Observable';
2
- import { OnNext } from './types';
3
-
4
- export class MediatorObservable<T> extends Observable<T> {
5
- addSource<S>(source: Observable<S>, onNext: OnNext<S>): MediatorObservable<T> {
6
- source.subscribe(onNext);
7
- return this;
8
- }
9
- }