@ptolemy2002/react-proxy-context 2.3.6 → 2.5.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.
package/README.md CHANGED
@@ -17,29 +17,25 @@ type OnChangePropCallback<T> =
17
17
  <K extends keyof T>(prop: K, current: T[K], prev?: T[K]) => void
18
18
  ;
19
19
  type OnChangeReinitCallback<T> =
20
- (current: T, prev?: T) => void
20
+ (current: T, prev?: T, initial?: boolean) => void
21
21
  ;
22
22
 
23
23
  type Dependency<_T, T=Exclude<_T, null | undefined>> = keyof T | (
24
24
  <K extends keyof T>(prop: K, current: T[K], prev: T[K], obj: T) => boolean
25
25
  ) | null | undefined | false | [keyof T, ...PropertyKey[]];
26
26
 
27
- type ProxyContext<T> = ContextWithName<ProxyContextValue<T> | undefined>;
27
+ type ProxyContext<T> = ContextWithName<ProxyContextValueWrapper<T> | undefined>;
28
28
 
29
- type ProxyContextValue<T> = {
30
- obj: T;
31
- set: (newObj: T) => T;
32
- subscribe: (
33
- propCallback: OnChangePropCallback<T>,
34
- reinitCallback: OnChangeReinitCallback<T>,
35
- deps: Dependency<T>[]
36
- ) => string;
37
- unsubscribe: (id: string) => void;
29
+ type ProxyContextChangeSubscriber<T> = {
30
+ id: string;
31
+ deps: Dependency<T>[] | null;
32
+ propCallback: OnChangePropCallback<T>;
33
+ reinitCallback: OnChangeReinitCallback<T>;
38
34
  };
39
35
 
40
36
  type ProxyContextProviderProps<T> = {
41
37
  children: ReactNode;
42
- value: T;
38
+ value: T | ProxyContextValueWrapper<T>;
43
39
  onChangeProp?: OnChangePropCallback<T>;
44
40
  onChangeReinit?: OnChangeReinitCallback<T>;
45
41
  proxyRef?: React.MutableRefObject<T>;
@@ -51,6 +47,36 @@ type UseProxyContextResult<T> = HookResultData<{
51
47
  }, readonly [T, (newObj: T) => T]>;
52
48
  ```
53
49
 
50
+ ## Classes
51
+ The following classes are available in the library:
52
+
53
+ ### ProxyContextValueWrapper<T>
54
+ #### Description
55
+ A class that wraps a value and provides proxy-based reactivity through subscription management. This class manages the proxy object internally and allows subscribers to listen to both property mutations and full object reassignments. The main benefit of this class is that it allows you to initialize a proxied value outside of a React context and pass it into the provider later, giving you more control over the proxy lifecycle.
56
+
57
+ #### Constructor
58
+ - `value` (`T`): The initial value to wrap in a proxy.
59
+
60
+ #### Methods
61
+ - `get()`: Returns the current proxied value.
62
+ - Returns: `T`
63
+ - `set(newObj: T)`: Sets a new value and wraps it in a proxy. Emits reinit events to all subscribers.
64
+ - Parameters:
65
+ - `newObj` (`T`): The new value to set
66
+ - Returns: `T` - The new proxied value
67
+ - `subscribe(propCallback, reinitCallback, deps)`: Subscribes to changes in the proxied object.
68
+ - Parameters:
69
+ - `propCallback` (`OnChangePropCallback<T>`): Called when a property changes
70
+ - `reinitCallback` (`OnChangeReinitCallback<T>`): Called when the entire object is reassigned
71
+ - `deps` (`Dependency<T>[] | null`): Array of dependencies to listen to, or null to listen to all changes
72
+ - Returns: `string` - A unique subscription ID
73
+ - `unsubscribe(id: string)`: Unsubscribes from changes using the subscription ID.
74
+ - `emitChange(prop, current, prev?)`: Emits a property change event to all relevant subscribers (internal use).
75
+ - `emitReinit(current, prev?)`: Emits a reinitialization event to all subscribers (internal use).
76
+
77
+ #### Properties
78
+ - `changeSubscribers`: A record of all current subscribers (internal use).
79
+
54
80
  ## Functions
55
81
  The following functions are available in the library:
56
82
 
@@ -74,7 +100,7 @@ Creates a new instance of the ProxyContext, essentially to be used as the contex
74
100
  #### Returns
75
101
  `ProxyContext<T>` - The context object that can be used in a provider.
76
102
 
77
- ### createProxyContextProvider<T extends object>
103
+ ### createProxyContextProvider<T extends object | null>
78
104
  #### Description
79
105
  Creates a new proxy context provider component with the specified type. `ProxyContextProvider` is no longer used due to a TypeScript limitation that prevents the context type from being inferred.
80
106
 
@@ -84,27 +110,27 @@ Creates a new proxy context provider component with the specified type. `ProxyCo
84
110
  #### Returns
85
111
  `React.MemoExoticComponent<FunctionComponent<ProxyContextProviderProps<T> & { renderDeps?: any[] }>>` - The provider component that can be used in the React tree. The resulting component is memoized to prevent unnecessary re-renders, but the `renderDeps` prop can be used to force a re-render when the specified dependencies change (necessary when working with the children prop).
86
112
 
87
- The component has the following other props:
88
- - `value` (T): The value of the context. This is what is reported when the context is not provided.
113
+ The component has the following props:
114
+ - `value` (`T | ProxyContextValueWrapper<T>`): The value of the context. This can be either a raw value of type `T`, which will be automatically wrapped in a `ProxyContextValueWrapper`, or a pre-existing `ProxyContextValueWrapper<T>` instance. This allows you to initialize the wrapper outside of the context and pass it in, giving you more control over the proxy lifecycle.
89
115
  - `onChangeProp` (`OnChangePropCallback<T>`): A function that is called whenever a property of the context is changed. The first parameter is the property that was changed, the second parameter is the current value of the property, and the third parameter is the previous value of the property. This is useful for listening to changes in the provider's parent component.
90
- - `onChangeReinit` (`OnChangeReinitCallback<T>`): A function that is called whenever the context is reinitialized. The first parameter is the current value of the context, and the second parameter is the previous value of the context. This is useful for listening to changes in the provider's parent component.
116
+ - `onChangeReinit` (`OnChangeReinitCallback<T>`): A function that is called whenever the context is reinitialized. The first parameter is the current value of the context, the second parameter is the previous value of the context, and the third parameter is a boolean indicating whether this is the first initialization. Also called on first initialization, with the previous value being `undefined` if you passed in a raw value instead of a `ProxyContextValueWrapper`. This is useful for listening to changes in the provider's parent component.
91
117
  - `proxyRef` (`React.MutableRefObject<T>`): A ref object that is assigned the proxy object of the context. This is useful for accessing the proxy object directly by the provider's parent component.
92
118
 
93
119
  ## Hooks
94
120
  The following hooks are available in the library:
95
121
 
96
122
  ### useProxyContext<T>
97
- A hook that uses the context provided by the `ProxyContextProvider` component. This hook also provides options to choose which properties to listen to and whether to listen to full reassignments. `T` represents the type of the object that is stored in the context.
123
+ A hook that uses the context provided by the `ProxyContextProvider` component. This hook uses React 18's `useSyncExternalStore` for optimal concurrent rendering support and provides options to choose which properties to listen to and whether to listen to full reassignments. `T` represents the type of the object that is stored in the context.
98
124
 
99
125
  #### Parameters
100
126
  - `contextClass` (`ProxyContext<T>`): The context class that was created using `createProxyContext`.
101
127
  - `deps` (`Dependency<T>[] | null`): An array of dependencies to listen to. If any of these properties on the context change, the hook will re-render. If this is falsy, any mutation will trigger a re-render. If a dependency is an array, it represents a nested property dependency. You can also specify a function that returns a boolean to determine whether to re-render. By default, this is an empty array.
102
- - `onChangeProp` (`OnChangePropCallback<T> | undefined`): A function that is called whenever a property of the context is changed. The first parameter is the property that was changed, the second parameter is the current value of the property, and the third parameter is the previous value of the property. This is useful for listening to changes in the provider's parent component.
103
- - `onChangeReinit` (`OnChangeReinitCallback<T> | undefined`): A function that is called whenever the context is reinitialized. The first parameter is the current value of the context, and the second parameter is the previous value of the context. This is useful for listening to changes in the provider's parent component.
128
+ - `onChangeProp` (`OnChangePropCallback<T> | undefined`): A function that is called whenever a property of the context is changed. The first parameter is the property that was changed, the second parameter is the current value of the property, and the third parameter is the previous value of the property. This is useful for listening to changes in the consumer component.
129
+ - `onChangeReinit` (`OnChangeReinitCallback<T> | undefined`): A function that is called whenever the context is reinitialized. The first parameter is the current value of the context, the second parameter is the previous value of the context, and the third parameter is a boolean indicating whether this is the first initialization.
104
130
  - `listenReinit` (`boolean`): Whether to listen to full reassignments of the context. If this is true, the hook will re-render whenever the context is reinitialized. By default, this is true.
105
131
 
106
132
  #### Returns
107
- `UseProxyContextResult<T>` - An object containing the current value of the context and a function to set the context. The function returns the new value of the context wrapped in a `Proxy`.
133
+ `UseProxyContextResult<T>` - An object containing the current value of the context and a function to set the context. The `value` property returns the unwrapped proxied object, and the `set` function returns the new value of the context wrapped in a `Proxy`. The hook subscribes to the `ProxyContextValueWrapper` and automatically manages subscription cleanup.
108
134
 
109
135
  ## Peer Dependencies
110
136
  These should be installed in order to use the library, as npm does not automatically add peer dependencies to your project.
package/dist/main.d.ts CHANGED
@@ -4,24 +4,35 @@ export type ContextWithName<T> = Context<T> & {
4
4
  name: string;
5
5
  };
6
6
  export type OnChangePropCallback<T> = <K extends keyof T>(prop: K, current: T[K], prev?: T[K]) => void;
7
- export type OnChangeReinitCallback<T> = (current: T, prev?: T) => void;
8
- export type ProxyContextValue<T> = {
9
- obj: T;
10
- set: (newObj: T) => T;
11
- subscribe: (propCallback: OnChangePropCallback<T>, reinitCallback: OnChangeReinitCallback<T>, deps: Dependency<T>[] | null) => string;
12
- unsubscribe: (id: string) => void;
13
- };
7
+ export type OnChangeReinitCallback<T> = (current: T, prev?: T, initial?: boolean) => void;
14
8
  export declare function createProxyContext<T>(name: string): ProxyContext<T>;
15
9
  export type Dependency<_T, T = Exclude<_T, null | undefined>> = keyof T | (<K extends keyof T>(prop: K, current: T[K], prev: T[K], obj: T) => boolean) | null | undefined | false | [keyof T, ...PropertyKey[]];
16
10
  export declare function evaluateDependency<T>(dep: Dependency<T>): Exclude<Dependency<T>, any[]>;
17
- export type ProxyContext<T> = ContextWithName<ProxyContextValue<T> | undefined>;
11
+ export type ProxyContext<T> = ContextWithName<ProxyContextValueWrapper<T> | undefined>;
18
12
  export type ProxyContextProviderProps<T> = {
19
13
  children: ReactNode;
20
- value: T;
14
+ value: T | ProxyContextValueWrapper<T>;
21
15
  onChangeProp?: OnChangePropCallback<T>;
22
16
  onChangeReinit?: OnChangeReinitCallback<T>;
23
17
  proxyRef?: React.MutableRefObject<T>;
24
18
  };
19
+ export type ProxyContextChangeSubscriber<T> = {
20
+ id: string;
21
+ deps: Dependency<T>[] | null;
22
+ propCallback: OnChangePropCallback<T>;
23
+ reinitCallback: OnChangeReinitCallback<T>;
24
+ };
25
+ export declare class ProxyContextValueWrapper<T> {
26
+ private value;
27
+ changeSubscribers: Record<string, ProxyContextChangeSubscriber<T>>;
28
+ constructor(value: T);
29
+ subscribe(propCallback: OnChangePropCallback<T>, reinitCallback: OnChangeReinitCallback<T>, deps: Dependency<T>[] | null): string;
30
+ unsubscribe(id: string): void;
31
+ emitChange(prop: keyof T, current: T[keyof T], prev?: T[keyof T]): void;
32
+ emitReinit(current: T, prev?: T, initial?: boolean): void;
33
+ get(): T;
34
+ set(newObj: T): T;
35
+ }
25
36
  export declare function createProxyContextProvider<T extends object | null>(contextClass: ProxyContext<T>): import('react').MemoExoticComponent<import('react').FunctionComponent<ProxyContextProviderProps<T> & {
26
37
  renderDeps?: unknown[] | null | false;
27
38
  }>>;