@webkrafters/react-observable-context 0.0.3 → 1.1.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 +13 -1
- package/dist/index.d.ts +18 -7
- package/dist/index.js +74 -22
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -14,7 +14,9 @@ The React-Observable-Context package exports only **2** modules namely: the **cr
|
|
|
14
14
|
|
|
15
15
|
`createContext` is a zero-parameter funtion returning a store-bearing context. Pass the context to the React::useContext() parameter to obtain the context's `store`.
|
|
16
16
|
|
|
17
|
-
The `Provider` can immediately be used as-is anywhere the React-Observable-Context is required. Supply the context to its `context` prop
|
|
17
|
+
The `Provider` can immediately be used as-is anywhere the React-Observable-Context is required. It accepts **3** props and the customary Provider `children` prop. Supply the context to its `context` prop; the initial state to the customary Provider `value` prop; and the optional `prehooks` props <i>(discussed in the prehooks section below)</i>.
|
|
18
|
+
|
|
19
|
+
<i><u>Note:</u></i> the Provider `context` prop is not updateable. Once set, all further updates to this prop are ignored.
|
|
18
20
|
|
|
19
21
|
The context's `store` exposes **4** methods for interacting with the context's internal state namely:
|
|
20
22
|
|
|
@@ -26,6 +28,16 @@ The context's `store` exposes **4** methods for interacting with the context's i
|
|
|
26
28
|
|
|
27
29
|
* **subscribe**: (listener: (newValue: PartialState\<State\>, oldValue: PartialState\<State\>) => void) => ***UnsubscribeFunction***
|
|
28
30
|
|
|
31
|
+
### Prehooks
|
|
32
|
+
|
|
33
|
+
The context's store update operation adheres to **2** user supplied prehooks when present. Otherwise, the update operation proceeds normally to completion. They are named **resetState** and **setState** after the store update methods which utilize them.
|
|
34
|
+
|
|
35
|
+
* **resetState**: (state: {current: State, original: State}) => boolean
|
|
36
|
+
|
|
37
|
+
* **setState**: (newChanges: PartialState\<State\>) => boolean
|
|
38
|
+
|
|
39
|
+
**usecase**: prehooks provide a central place for sanitizing, modifying, transforming, validating etc. all related incoming state updates. The prehook returns a **boolean** value (`true` to continue OR `false` to abort the update operation). The prehook may mutate (i.e. sanitize, transform, transpose) its argument values to accurately reflect the intended update value.
|
|
40
|
+
|
|
29
41
|
## Usage
|
|
30
42
|
|
|
31
43
|
<i><u>context.js</u></i>
|
package/dist/index.d.ts
CHANGED
|
@@ -1,30 +1,41 @@
|
|
|
1
1
|
export class UsageError extends Error {
|
|
2
2
|
}
|
|
3
|
-
export function createContext<
|
|
3
|
+
export function createContext<T_1 extends State>(): import("react").Context<Store<T_1>>;
|
|
4
4
|
/**
|
|
5
|
+
* Note: `context` prop is not updateable. Furtther updates to this prop are ignored.
|
|
6
|
+
*
|
|
5
7
|
* @type {import("react").FC<{
|
|
6
8
|
* children?: import("react").ReactNode,
|
|
7
9
|
* context: ObservableContext<T>,
|
|
10
|
+
* prehooks?: Prehooks<T>
|
|
8
11
|
* value: T
|
|
9
12
|
* }>}
|
|
10
13
|
* @template {State} T
|
|
11
14
|
*/
|
|
12
15
|
export const Provider: import("react").FC<{
|
|
13
16
|
children?: import("react").ReactNode;
|
|
14
|
-
context:
|
|
17
|
+
context: ObservableContext<T>;
|
|
18
|
+
prehooks?: Prehooks<T>;
|
|
15
19
|
value: T;
|
|
16
20
|
}>;
|
|
17
|
-
export type ObservableContext<
|
|
21
|
+
export type ObservableContext<T_1 extends State> = import("react").Context<Store<T>>;
|
|
18
22
|
export type OptionalTask<F = void> = F extends void ? () => never : F;
|
|
19
|
-
export type Listener<
|
|
23
|
+
export type Listener<T_1 extends State> = (newValue: PartialState<T>, oldValue: PartialState<T>) => void;
|
|
20
24
|
export type State = {
|
|
21
25
|
[x: string]: any;
|
|
22
26
|
};
|
|
23
|
-
export type PartialState<
|
|
27
|
+
export type PartialState<T_1 extends State> = {
|
|
24
28
|
[x: string]: any;
|
|
25
29
|
} & { [K in keyof T]?: T[K]; };
|
|
26
|
-
export type Selector<
|
|
27
|
-
export type
|
|
30
|
+
export type Selector<T_1 extends State> = (state: T) => any;
|
|
31
|
+
export type Prehooks<T_1 extends State> = {
|
|
32
|
+
resetState?: (state: {
|
|
33
|
+
current: T;
|
|
34
|
+
original: T;
|
|
35
|
+
}) => boolean;
|
|
36
|
+
setState?: (newChanges: PartialState<T>) => boolean;
|
|
37
|
+
};
|
|
38
|
+
export type Store<T_1 extends State> = {
|
|
28
39
|
getState: (selector?: Selector<T>) => any;
|
|
29
40
|
resetState: OptionalTask<VoidFunction>;
|
|
30
41
|
setState: (changes: PartialState<T>) => void;
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.createContext = exports.UsageError = exports.Provider = void 0;
|
|
8
8
|
var _react = _interopRequireWildcard(require("react"));
|
|
9
|
-
var _lodash = _interopRequireDefault(require("lodash.
|
|
9
|
+
var _lodash = _interopRequireDefault(require("lodash.clonedeep"));
|
|
10
|
+
var _lodash2 = _interopRequireDefault(require("lodash.isempty"));
|
|
10
11
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
|
11
12
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
12
13
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
@@ -66,61 +67,96 @@ var createContext = function createContext() {
|
|
|
66
67
|
};
|
|
67
68
|
|
|
68
69
|
/**
|
|
70
|
+
* @readonly
|
|
71
|
+
* @type {Prehooks<T>}
|
|
72
|
+
* @template {State} T
|
|
73
|
+
*/
|
|
74
|
+
exports.createContext = createContext;
|
|
75
|
+
var defaultPrehooks = Object.freeze({});
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param {T} state
|
|
79
|
+
* @param {PartialState<T>} newState
|
|
80
|
+
* @param {Listener<T>} onStateChange
|
|
81
|
+
* @template {State} T
|
|
82
|
+
*/
|
|
83
|
+
var _setState = function _setState(state, newState, onStateChange) {
|
|
84
|
+
/** @type {PartialState<T>} */
|
|
85
|
+
var newChanges = {};
|
|
86
|
+
/** @type {PartialState<T>} */
|
|
87
|
+
var replacedValue = {};
|
|
88
|
+
for (var k in newState) {
|
|
89
|
+
if (state[k] === newState[k]) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
replacedValue[k] = state[k];
|
|
93
|
+
state[k] = newState[k];
|
|
94
|
+
newChanges[k] = newState[k];
|
|
95
|
+
}
|
|
96
|
+
!(0, _lodash2["default"])(newChanges) && onStateChange(newChanges, replacedValue);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Note: `context` prop is not updateable. Furtther updates to this prop are ignored.
|
|
101
|
+
*
|
|
69
102
|
* @type {import("react").FC<{
|
|
70
103
|
* children?: import("react").ReactNode,
|
|
71
104
|
* context: ObservableContext<T>,
|
|
105
|
+
* prehooks?: Prehooks<T>
|
|
72
106
|
* value: T
|
|
73
107
|
* }>}
|
|
74
108
|
* @template {State} T
|
|
75
109
|
*/
|
|
76
|
-
exports.createContext = createContext;
|
|
77
110
|
var Provider = function Provider(_ref) {
|
|
78
111
|
var _ref$children = _ref.children,
|
|
79
112
|
children = _ref$children === void 0 ? null : _ref$children,
|
|
80
113
|
context = _ref.context,
|
|
114
|
+
_ref$prehooks = _ref.prehooks,
|
|
115
|
+
prehooks = _ref$prehooks === void 0 ? defaultPrehooks : _ref$prehooks,
|
|
81
116
|
value = _ref.value;
|
|
82
|
-
var
|
|
83
|
-
|
|
84
|
-
|
|
117
|
+
var prehooksRef = (0, _react.useRef)(prehooks);
|
|
118
|
+
var initialState = (0, _react.useRef)(value);
|
|
119
|
+
|
|
120
|
+
/** @type {[T, Function]} */
|
|
121
|
+
var _useState = (0, _react.useState)(function () {
|
|
122
|
+
return (0, _lodash["default"])(value);
|
|
123
|
+
}),
|
|
85
124
|
_useState2 = _slicedToArray(_useState, 1),
|
|
86
|
-
|
|
125
|
+
state = _useState2[0];
|
|
87
126
|
/** @type {[Set<Listener<T>>, Function]} */
|
|
88
127
|
var _useState3 = (0, _react.useState)(function () {
|
|
89
128
|
return new Set();
|
|
90
129
|
}),
|
|
91
130
|
_useState4 = _slicedToArray(_useState3, 1),
|
|
92
131
|
listeners = _useState4[0];
|
|
132
|
+
|
|
93
133
|
/** @type {Listener<T>} */
|
|
94
134
|
var onChange = function onChange(newValue, oldValue) {
|
|
95
135
|
return listeners.forEach(function (listener) {
|
|
96
136
|
return listener(newValue, oldValue);
|
|
97
137
|
});
|
|
98
138
|
};
|
|
139
|
+
|
|
99
140
|
/** @type {Store<T>["getState"]} */
|
|
100
141
|
var getState = (0, _react.useCallback)(function () {
|
|
101
142
|
var selector = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultSelector;
|
|
102
|
-
return selector(
|
|
143
|
+
return selector(state);
|
|
103
144
|
}, []);
|
|
145
|
+
|
|
104
146
|
/** @type {Store<T>["resetState"]} */
|
|
105
147
|
var resetState = (0, _react.useCallback)(function () {
|
|
106
|
-
|
|
148
|
+
var original = (0, _lodash["default"])(initialState.current);
|
|
149
|
+
(!('resetState' in prehooksRef.current) || prehooksRef.current.resetState({
|
|
150
|
+
current: (0, _lodash["default"])(state),
|
|
151
|
+
original: original
|
|
152
|
+
})) && _setState(state, original, onChange);
|
|
107
153
|
}, []);
|
|
154
|
+
|
|
108
155
|
/** @type {Store<T>["setState"]} */
|
|
109
156
|
var setState = (0, _react.useCallback)(function (changes) {
|
|
110
|
-
|
|
111
|
-
var newChanges = {};
|
|
112
|
-
/** @type {PartialState<T>} */
|
|
113
|
-
var replacedValue = {};
|
|
114
|
-
for (var k in changes) {
|
|
115
|
-
if (valueRef.current[k] === changes[k]) {
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
replacedValue[k] = valueRef.current[k];
|
|
119
|
-
valueRef.current[k] = changes[k];
|
|
120
|
-
newChanges[k] = changes[k];
|
|
121
|
-
}
|
|
122
|
-
!(0, _lodash["default"])(newChanges) && onChange(newChanges, replacedValue);
|
|
157
|
+
(!('setState' in prehooksRef.current) || prehooksRef.current.setState(changes)) && _setState(state, changes, onChange);
|
|
123
158
|
}, []);
|
|
159
|
+
|
|
124
160
|
/** @type {Store<T>["subscribe"]} */
|
|
125
161
|
var subscribe = (0, _react.useCallback)(function (listener) {
|
|
126
162
|
listeners.add(listener);
|
|
@@ -129,9 +165,13 @@ var Provider = function Provider(_ref) {
|
|
|
129
165
|
};
|
|
130
166
|
}, []);
|
|
131
167
|
(0, _react.useEffect)(function () {
|
|
132
|
-
return setState(value);
|
|
168
|
+
return setState((0, _lodash["default"])(value));
|
|
133
169
|
}, [value]);
|
|
170
|
+
(0, _react.useEffect)(function () {
|
|
171
|
+
prehooksRef.current = prehooks;
|
|
172
|
+
}, [prehooks]);
|
|
134
173
|
/** @type {[Store<T>, Function]} */
|
|
174
|
+
|
|
135
175
|
var _useState5 = (0, _react.useState)(function () {
|
|
136
176
|
return {
|
|
137
177
|
getState: getState,
|
|
@@ -142,6 +182,10 @@ var Provider = function Provider(_ref) {
|
|
|
142
182
|
}),
|
|
143
183
|
_useState6 = _slicedToArray(_useState5, 1),
|
|
144
184
|
store = _useState6[0];
|
|
185
|
+
/** @type {ObservableContext<T>} */
|
|
186
|
+
var _useState7 = (0, _react.useState)(context),
|
|
187
|
+
_useState8 = _slicedToArray(_useState7, 1),
|
|
188
|
+
StoreContext = _useState8[0];
|
|
145
189
|
return /*#__PURE__*/_react["default"].createElement(StoreContext.Provider, {
|
|
146
190
|
value: store
|
|
147
191
|
}, children);
|
|
@@ -176,6 +220,14 @@ Provider.displayName = 'ObservableContext.Provider';
|
|
|
176
220
|
* @template {State} T
|
|
177
221
|
*/
|
|
178
222
|
|
|
223
|
+
/**
|
|
224
|
+
* @typedef {{
|
|
225
|
+
* resetState?: (state: { current: T, original: T}) => boolean,
|
|
226
|
+
* setState?: (newChanges: PartialState<T>) => boolean
|
|
227
|
+
* }} Prehooks
|
|
228
|
+
* @template {State} T
|
|
229
|
+
*/
|
|
230
|
+
|
|
179
231
|
/**
|
|
180
232
|
* @typedef {{
|
|
181
233
|
* getState: OptionalTask<(selector?: Selector<T>) => *>,
|
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
],
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@types/react": "^18.0.17",
|
|
11
|
+
"lodash.clonedeep": "^4.5.0",
|
|
11
12
|
"lodash.isempty": "^4.4.0",
|
|
12
13
|
"react": "^18.2.0"
|
|
13
14
|
},
|
|
@@ -74,5 +75,5 @@
|
|
|
74
75
|
"test:watch": "eslint --fix && jest --watchAll"
|
|
75
76
|
},
|
|
76
77
|
"types": "dist/index.d.ts",
|
|
77
|
-
"version": "
|
|
78
|
+
"version": "1.1.0"
|
|
78
79
|
}
|