@cervello/react 0.12.2 → 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.
- package/README.md +23 -168
- package/dist/cervello.cjs +1 -1
- package/dist/cervello.cjs.map +1 -1
- package/dist/cervello.esm.js +1 -1
- package/dist/cervello.esm.js.map +1 -1
- package/dist/cervello.umd.js +1 -1
- package/dist/cervello.umd.js.map +1 -1
- package/package.json +35 -37
- package/types/lib/helpers/constants.d.ts +1 -0
- package/types/lib/helpers/create-store-selector-hook.d.ts +3 -0
- package/types/lib/helpers/index.d.ts +1 -2
- package/types/lib/helpers/proxify-store.d.ts +2 -2
- package/types/lib/store/index.d.ts +11 -9
- package/types/lib/utils/index.d.ts +1 -1
- package/types/lib/utils/object.d.ts +38 -2
- package/types/lib/utils/subject.d.ts +13 -0
- package/types/types/shared.d.ts +1 -0
- package/types/lib/helpers/create-use-selector.d.ts +0 -5
- package/types/lib/helpers/create-use-store.d.ts +0 -5
- package/types/lib/utils/subscribe-for-react.d.ts +0 -2
package/README.md
CHANGED
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
# Cervello
|
|
2
|
-
<img src="https://img.shields.io/npm/v/@cervello/react?color=blue&style=flat-square"></a>
|
|
3
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@cervello/react)
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
<a href="https://www.cervello.dev">
|
|
5
7
|
<img src="https://github.com/chempogonzalez/cervello/blob/main/assets/emoji-logo.png" style="display:block;">
|
|
8
|
+
</a>
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
> 🤯 Simplest and truly reactive state manager for React _(just 1.5kb)_
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
|
|
14
|
+
<br>
|
|
15
|
+
<br>
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
<a href="https://www.cervello.dev">
|
|
19
|
+
<p align="center">
|
|
20
|
+
<strong>📖 Documentation website</strong>
|
|
21
|
+
</p>
|
|
22
|
+
</a>
|
|
23
|
+
|
|
24
|
+
<br>
|
|
11
25
|
|
|
12
26
|
|
|
13
27
|
## 🚀 **Features**
|
|
@@ -31,7 +45,7 @@ pnpm add @cervello/react
|
|
|
31
45
|
```
|
|
32
46
|
|
|
33
47
|
|
|
34
|
-
## 💻 **Usage**
|
|
48
|
+
## 💻 **Quick Usage**
|
|
35
49
|
The `cervello` function allows you to create a new store in an easy way.
|
|
36
50
|
Just set the initial value _`(the type will be inferred based on this value)`_ and you have it
|
|
37
51
|
|
|
@@ -39,181 +53,22 @@ Just set the initial value _`(the type will be inferred based on this value)`_ a
|
|
|
39
53
|
// - store-example.ts
|
|
40
54
|
import { cervello } from '@cervello/react'
|
|
41
55
|
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* The cervello function returns a reactive store and 2 hooks
|
|
45
|
-
* to be ready to changes inside react components
|
|
46
|
-
*
|
|
47
|
-
*/
|
|
48
56
|
export const {
|
|
49
|
-
store, //
|
|
50
|
-
useStore, //
|
|
51
|
-
useSelector, //
|
|
52
|
-
reset, //
|
|
57
|
+
store, // Reactive store object
|
|
58
|
+
useStore, // Hook to listen for store changes
|
|
59
|
+
useSelector, // Hook to listen for changes on parts of the store
|
|
60
|
+
reset, // Function to reset the store to initial value
|
|
53
61
|
} = cervello({ count: 0 })
|
|
54
62
|
```
|
|
55
63
|
<br>
|
|
56
64
|
<br>
|
|
57
65
|
|
|
58
|
-
------
|
|
59
|
-
### `📖 Documentation`
|
|
60
|
-
------
|
|
61
|
-
### 🟢 `store`
|
|
62
|
-
The store object that you can use `inside or outside react components` to modify the store. It will automatically notify all the components listening for changes
|
|
63
|
-
|
|
64
|
-
```tsx
|
|
65
|
-
import { store } from './store-example'
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* It can be used outside the react components
|
|
69
|
-
* It will notify all the components listening for changes
|
|
70
|
-
*/
|
|
71
|
-
const increment = () => { store.count++ }
|
|
72
|
-
|
|
73
|
-
const CounterButton = () => (
|
|
74
|
-
/**
|
|
75
|
-
* This makes all the components using the store (i.e.: CounterLabel)
|
|
76
|
-
* to be reactive and re-renders with the new value
|
|
77
|
-
*/
|
|
78
|
-
<button onClick={increment}>
|
|
79
|
-
Increment
|
|
80
|
-
</button>
|
|
81
|
-
)
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
<br>
|
|
85
|
-
|
|
86
|
-
### 🟢 `useStore`
|
|
87
|
-
|
|
88
|
-
React hook that allows you to have a reactive store which re-renders when a new value was set
|
|
89
|
-
```tsx
|
|
90
|
-
import { useStore } from './store-example'
|
|
91
|
-
|
|
92
|
-
const CounterLabel = () => {
|
|
93
|
-
const { count } = useStore()
|
|
94
|
-
|
|
95
|
-
return (<span>{ count }</span>)
|
|
96
|
-
}
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
<br>
|
|
100
|
-
|
|
101
|
-
### 🟢 `useSelector`
|
|
102
|
-
|
|
103
|
-
React hook that allows you to have a reactive store which re-renders when a new value was set on properties you specified
|
|
104
|
-
- _Parameters_:
|
|
105
|
-
- `selectors`: an array of store properties to be watched
|
|
106
|
-
- `isEqualFunction`: a custom function to compare the new value with the old one
|
|
107
|
-
```tsx
|
|
108
|
-
import { useSelector } from './store-example'
|
|
109
|
-
|
|
110
|
-
const CounterLabel = () => {
|
|
111
|
-
/**
|
|
112
|
-
* This will re-render just only when the property `count` changes
|
|
113
|
-
*/
|
|
114
|
-
const { count } = useSelector(['count'])
|
|
115
|
-
|
|
116
|
-
return (<span>{ count }</span>)
|
|
117
|
-
}
|
|
118
|
-
```
|
|
119
|
-
<br>
|
|
120
|
-
|
|
121
|
-
### 🟢 `reset`
|
|
122
|
-
|
|
123
|
-
Function to reset the store to the initial value
|
|
124
|
-
```tsx
|
|
125
|
-
import { reset } from './store-example'
|
|
126
|
-
|
|
127
|
-
function LogoutButton() {
|
|
128
|
-
|
|
129
|
-
const onLogoutClick = () => reset()
|
|
130
|
-
|
|
131
|
-
return (<button onClick={onLogoutClick}>Logout</button>)
|
|
132
|
-
}
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
<br>
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
----
|
|
139
|
-
### 🟣 The `Use` function
|
|
140
|
-
The use function allows you to implement side effects due to a store change
|
|
141
|
-
#### 🔽 Example
|
|
142
|
-
```ts
|
|
143
|
-
import type { UseFunction } from '@cervello/react'
|
|
144
|
-
|
|
145
|
-
const logger: UseFunction<typeof store> = ({ onChange }): void => {
|
|
146
|
-
onChange((store) => {
|
|
147
|
-
console.log('[Store-changed] to ==>', store)
|
|
148
|
-
})
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const { store } = cervello({
|
|
153
|
-
name: 'chempo',
|
|
154
|
-
surname: 'gonzalez'
|
|
155
|
-
}).use(logger, /* ... */)
|
|
156
|
-
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
#### 🗳️ Use function - `utility functions`
|
|
160
|
-
```ts
|
|
161
|
-
import type { UseFunction } from '@cervello/react'
|
|
162
|
-
|
|
163
|
-
const logger: UseFunction<typeof store> = ({ onChange, onPartialChange }): void => {
|
|
164
|
-
// Listen to all the changes happened in the store
|
|
165
|
-
onChange((store) => {
|
|
166
|
-
console.log('Store changed to :>>', store)
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// Listen to the changes happened in the store's attributes provided
|
|
170
|
-
onPartialChange(['name'], (store) => {
|
|
171
|
-
console.log('Name has changed to:', store.name)
|
|
172
|
-
})
|
|
173
|
-
}
|
|
174
|
-
```
|
|
175
|
-
------
|
|
176
|
-
<br>
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
## 💡 Features out-of-the-box
|
|
180
|
-
### **`💠 Nested objects reactivity`**
|
|
181
|
-
You can change a nested property of an object and it will be notified automatically as well without any problem
|
|
182
|
-
|
|
183
|
-
```jsx
|
|
184
|
-
import { store } from './other-example'
|
|
185
|
-
|
|
186
|
-
const AddressChanger = () => {
|
|
187
|
-
return (
|
|
188
|
-
<button onClick={() => { store.address.city = 'Seville' }}>
|
|
189
|
-
Change city to Seville
|
|
190
|
-
</button>
|
|
191
|
-
)
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
```tsx
|
|
196
|
-
import { useSelector } from './other-example'
|
|
197
|
-
|
|
198
|
-
// Component listening for address object changes
|
|
199
|
-
const Address = () => {
|
|
200
|
-
const { address } = useSelector(['address'])
|
|
201
|
-
const { street, city } = address
|
|
202
|
-
|
|
203
|
-
return (
|
|
204
|
-
<div>
|
|
205
|
-
<span>{ street }</span>
|
|
206
|
-
<span>{ city }</span>
|
|
207
|
-
</div>
|
|
208
|
-
)
|
|
209
|
-
}
|
|
210
|
-
```
|
|
211
|
-
|
|
212
66
|
|
|
213
67
|
---------
|
|
214
|
-
|
|
68
|
+
### To see more in depth explanations 📖 [Documentation website](https://www.cervello.dev)
|
|
215
69
|
--------
|
|
216
70
|
|
|
71
|
+
<br>
|
|
217
72
|
|
|
218
73
|
## 🤓 Happy Code
|
|
219
74
|
|
package/dist/cervello.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e=require("
|
|
1
|
+
var e=require("react"),n=require("use-sync-external-store/shim/index.js");function r(e){if(!e||"object"!=typeof e)return e;var n={};return Array.isArray(e)?n=e.map(function(e){return r(e)}):Object.entries(e).forEach(function(e){n[e[0]]=r(e[1])}),n}var t=function(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)},u=function(e){var n;return null!=(n=e.$$value$$)?n:e};function c(e,n){return e.reduce(function(e,r){return e[r]=n[r],e},{})}var i=function(e){return JSON.stringify(e)},o=function(e,n){return i(e)===i(n)};function f(e,n,c,i){if("object"!=typeof n)throw new Error("Store must be an object");return new Proxy(n,{get:function(n,r){var o=u(n);if("toJSON"===r)return function(){return o};var a=Reflect.get(o,r);if(i&&t(a)){var s=c[r];if(s)return s;var l=f(e,a,c,i);return c[r]=l,l}return a},set:function(n,o,a){var s=Object.hasOwn(n,"$$value$$");if("$value"===o&&s){var l=r(a);return c={},Reflect.set(n,"$$value$$",l),e.next(l),!0}var v=u(n),b=Reflect.get(v,o);if(b===a)return!0;if(Reflect.set(v,o,a),i&&t(b)&&c[o]){var $=f(e,a,c,i);c[o]=$}return e.next(Object.assign({},e.getValue())),!0},has:function(e,n){return Reflect.has(u(e),n)},ownKeys:function(e){return Reflect.ownKeys(u(e))},getOwnPropertyDescriptor:function(e,n){return Reflect.getOwnPropertyDescriptor(u(e),n)}})}var a=Symbol("_isServer");function s(r,t,u){var i,f=Object.assign({},r.getValue().$$value$$,((i={})[a]=!0,i));return function(i,s){var l=e.useRef(null),v=n.useSyncExternalStore(function(e){var n=r.subscribe({next:function(n){if("full"===u)return e();var r=c(i,n);(null!=s?s:o)(l.current,r)||(l.current=r,e())}});return function(){n.unsubscribe()}},function(){return r.getValue()},function(){return f});return Object.getOwnPropertySymbols(v).includes(a)?v:t}}exports.cervello=function(e,n){var t;void 0===n&&(n={reactiveNestedObjects:!0});var i="function"==typeof e?e():e,a=((t={}).$$value$$=r(i),t),l=function(e,n){void 0===n&&(n=!0);var r=[],t=e;return{getValue:function(){return t},next:function(e){t=e,r.forEach(function(n){n.next(e)})},subscribe:function(e){return n&&e.next(t),r.push(e),{unsubscribe:function(){r=r.filter(function(n){return n!==e})}}},unSubscribeAll:function(){r=[]}}}(a,!1),v=f(l,a,{},n.reactiveNestedObjects),b={store:v,reset:function(){v.$value=i},useStore:s(l,v,"full"),useSelector:s(l,v,"slice"),use:function(){return[].slice.call(arguments).forEach(function(e){e({onChange:function(e){l.subscribe({next:function(n){e(v)}})},onPartialChange:function(e,n){var t=c(e,u(a));l.subscribe({next:function(i){var f=u(i),a=c(e,f);o(t,a)||(n(v),t=r(a))}})}})}),this}};return b};
|
|
2
2
|
//# sourceMappingURL=cervello.cjs.map
|
package/dist/cervello.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cervello.cjs","sources":["../src/lib/utils/object.ts","../src/lib/utils/subscribe-for-react.ts","../src/lib/helpers/proxify-store.ts","../src/lib/helpers/create-use-store.ts","../src/lib/helpers/create-use-selector.ts","../src/lib/store/index.ts"],"sourcesContent":["export function deepClone <T> (obj: any): T {\n if (!obj || typeof obj !== 'object') {\n return obj\n }\n let newObj = {} as any\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n } else {\n Object.keys(obj).forEach((key) => {\n // eslint-disable-next-line no-return-assign\n return newObj[key] = deepClone(obj[key])\n })\n }\n return newObj as T\n}\n\nexport function isEqualObject (obj1: any, obj2: any): boolean {\n return JSON.stringify(obj1) === JSON.stringify(obj2)\n}\n","import type { BehaviorSubject } from 'rxjs'\n\n\n\nexport const subscribeForReactHook = <T>(store$$: BehaviorSubject<T>): typeof subscribe => {\n const subscribe = (onStoreChange: () => void): () => void => {\n const subscription = store$$.subscribe(onStoreChange)\n return () => {\n subscription.unsubscribe()\n }\n }\n return subscribe\n}\n","\nimport { deepClone, isEqualObject } from '../utils'\n\nimport type { BehaviorSubject } from 'rxjs'\n\n\n\nconst NESTED_ATTRIBUTES_SYMBOL = '$$p-a' // parent-attributes\nconst nestedAttrs = Symbol(NESTED_ATTRIBUTES_SYMBOL)\n\nfunction assignNestedProperty (obj: any, keyPath: Array<string>, prop: string, value: unknown): any {\n keyPath.forEach((key) => { obj = obj[key] })\n obj[prop] = value\n}\n\nexport function proxifyStore <T extends any> (store$$: BehaviorSubject<T>, storeObject: T, proxiedNestedObjectMap: any): T\n\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (store$$: BehaviorSubject<T>, storeObject: T, proxiedNestedObjectMap: any): T {\n if (typeof storeObject !== 'object') throw new Error('Store must be an object')\n\n return new Proxy<T>(\n storeObject,\n {\n get: function (target: T, prop: string | symbol): any {\n\n const currentStore = target?.[nestedAttrs] ? target : store$$.getValue()\n const valueByProp = currentStore[prop]\n\n if (prop in currentStore) {\n if (typeof valueByProp === 'function') {\n return valueByProp.bind(proxifyStore(store$$, store$$.getValue(), proxiedNestedObjectMap))\n }\n\n // Return proxied object for nested reactivity\n if (valueByProp\n && typeof valueByProp === 'object'\n && !Array.isArray(valueByProp)\n && typeof prop !== 'symbol'\n ) {\n const currentNestedAttrs = target?.[nestedAttrs]\n const nestedAttrsPrefix = currentNestedAttrs ? `${currentNestedAttrs as string}.` : ''\n\n const cacheKey = `${nestedAttrsPrefix}-${prop}`\n\n if (\n proxiedNestedObjectMap[cacheKey]\n && isEqualObject(proxiedNestedObjectMap[cacheKey], valueByProp)\n ) return proxiedNestedObjectMap[cacheKey]\n\n const proxiedNestedObject = proxifyStore(\n store$$,\n Object.defineProperty(\n valueByProp,\n nestedAttrs,\n {\n value: `${nestedAttrsPrefix}${prop}`,\n enumerable: false,\n writable: false,\n configurable: false,\n },\n ),\n proxiedNestedObjectMap,\n )\n\n proxiedNestedObjectMap[cacheKey] = proxiedNestedObject\n\n return proxiedNestedObject\n }\n\n return valueByProp\n }\n\n return Reflect.get(target, prop)\n },\n set: function (target: T, prop: string | symbol, value: any) {\n const currentStore = store$$.getValue() as any\n const isNestedProp = Boolean(target[nestedAttrs]?.length)\n let clonedStore = deepClone<any>(currentStore)\n\n if (isNestedProp) {\n const nestedAttributes = (target[nestedAttrs] as string).split('.')\n assignNestedProperty(clonedStore, nestedAttributes, prop as string, value)\n } else {\n if (prop === '$value') clonedStore = value\n else clonedStore[prop] = value\n }\n\n if (!isEqualObject(currentStore, clonedStore)) {\n store$$.next(clonedStore)\n }\n\n return true\n },\n },\n )\n}\n","\nimport { useMemo } from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { subscribeForReactHook } from '../utils/subscribe-for-react'\nimport { proxifyStore } from './proxify-store'\n\nimport type { BehaviorSubject } from 'rxjs'\nimport type { Maybe } from 'src/types/shared'\n\n\n\nexport function createUseStore <T> (store$$: BehaviorSubject<T>, proxiedNestedObjectMap: any): () => T & { $value: Maybe<T> } {\n const subscribe = subscribeForReactHook(store$$)\n const getValue = store$$.getValue.bind(store$$)\n\n\n // USE STORE HOOK -------------------------------------------------\n const useStore = (): T & { $value: Maybe<T> } => {\n const store = useSyncExternalStore(subscribe, getValue, getValue)\n\n const cachedStore = useMemo(() => proxifyStore(store$$, store, proxiedNestedObjectMap), [store])\n\n return cachedStore as T & { $value: Maybe<T> }\n }\n\n\n return useStore\n}\n","\nimport { useMemo } from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector.js'\n\n\nimport { isEqualObject } from '../utils'\nimport { subscribeForReactHook } from '../utils/subscribe-for-react'\nimport { proxifyStore } from './proxify-store'\n\nimport type { ObjectFromAttributes, WithoutType } from '../../types/shared'\nimport type { BehaviorSubject } from 'rxjs'\n\n\n\nexport function getPartialObjectFromAttributes <T> (attributes: Array<keyof T>, store: T): any {\n return attributes.reduce<any>((acc, curr) => {\n acc[curr] = store[curr]\n return acc\n }, {})\n}\n\nexport type UseSelector<T> = <Attributes extends Array< keyof WithoutType<T, Function> >>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ) => ObjectFromAttributes<T, Attributes>\n\n\n\nexport function createUseSelector <T> (store$$: BehaviorSubject<T>, proxiedNestedObjectMap: any): UseSelector<T> {\n const subscribe = subscribeForReactHook(store$$)\n const getValue = store$$.getValue.bind(store$$)\n\n // USE SELECTOR HOOK -------------------------------------------------\n const useSelector = <Attributes extends Array< keyof WithoutType<T, Function> >>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ): ObjectFromAttributes<T, Attributes> => {\n const store = useSyncExternalStoreWithSelector<T, ObjectFromAttributes<T, Attributes>>(\n subscribe,\n getValue,\n getValue,\n (store) => getPartialObjectFromAttributes(selectors, store),\n (prev, curr) => isEqualFunction\n ? isEqualFunction(prev, curr)\n : isEqualObject(prev, curr),\n )\n\n const cachedStore = useMemo(() => proxifyStore(\n store$$ as any,\n store,\n proxiedNestedObjectMap,\n ), [store])\n\n return cachedStore\n }\n\n return useSelector\n}\n","import { BehaviorSubject, distinctUntilChanged } from 'rxjs'\n\nimport { createUseSelector, createUseStore, proxifyStore } from '../helpers'\nimport { isEqualObject } from '../utils'\n\nimport type { Maybe, WithoutType } from '../../types/shared'\nimport type { UseSelector } from '../helpers'\n\n\n\n// const STORE_SYMBOL = '__cervello-store__'\n\ninterface CervelloStoreUseParam<StoreType> {\n onChange: (cb: (store: StoreType) => void) => void\n onPartialChange: <\n Attributes extends Array< keyof WithoutType<StoreType, Function>>\n > (selectors: Attributes, cb: (store: StoreType) => void) => void\n}\n\n/**\n * Use function which allows you to listen for changes in the store.\n */\nexport type CervelloUseFunction<StoreType> = (param: CervelloStoreUseParam<StoreType>) => void\n\n\ninterface CervelloStore<StoreType> {\n /** Reactive store */\n store: StoreType\n /** Hook to react to all changes done to 'store' */\n useStore: () => StoreType\n /** Hook to react to changes done to 'store' in all the attributes provided */\n useSelector: UseSelector<StoreType>\n /** Resets the value to the initial value passed in */\n reset: () => void\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType>\n}\n\n// /**\n// * @note Currently not working\n// */\n// export interface CervelloOptions {\n// persist?:\n// | boolean\n// // | {\n// // getItem: (key: string) => any\n// // }\n// }\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue Object with the default values for the store\n *\n * @returns - { store, useStore, useSelector }\n */\nexport function cervello <T> (initialValue: T): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue Function which returns the default values for the store\n *\n * @returns - { store, useStore, useSelector }\n */\nexport function cervello <T> (initialValue: () => T): CervelloStore<T & { $value: Maybe<T> }>\n\n\n\n\n\n/** @internal */\nexport function cervello <T> (initialValue: T | (() => T)): CervelloStore<T & { $value: Maybe<T> }> {\n const defaultValue = typeof initialValue === 'function' ? (initialValue as any)() : initialValue\n const store$$ = new BehaviorSubject<T>(defaultValue)\n\n // Object map to keep reference of nested object proxies created\n // to avoid problems with reference equality (i.e.: useEffect dependencies array)\n const proxiedNestedObjectMap: any = {}\n\n const proxiedStore = proxifyStore<T>(store$$, defaultValue, proxiedNestedObjectMap)\n\n const cervelloStore = {\n store: proxiedStore,\n reset () {\n if (!isEqualObject(store$$.getValue(), defaultValue)) {\n store$$.next(defaultValue)\n }\n },\n\n // TO BE SEPARATED IN cervello/react package ---------------------\n useStore: createUseStore<T>(store$$, proxiedNestedObjectMap),\n useSelector: createUseSelector<T>(store$$, proxiedNestedObjectMap),\n // ---------------------------------------------------------------\n\n use (...functionList: any) {\n functionList.forEach((func: any) => {\n func({\n onChange (cb: any) {\n store$$.subscribe((_) => cb(proxiedStore))\n },\n onPartialChange (attrs: Array<keyof T>, cb: any) {\n store$$.pipe(\n distinctUntilChanged((prev, curr) => {\n let isEqual = true\n attrs.forEach((selector) => {\n const currentPropertyValue = curr[selector]\n const prevPropertyValue = prev[selector]\n if (isEqual) {\n isEqual = typeof currentPropertyValue === 'object'\n ? isEqualObject(prevPropertyValue, currentPropertyValue)\n : prevPropertyValue === currentPropertyValue\n }\n })\n return isEqual\n }),\n ).subscribe((_) => cb(proxiedStore))\n },\n })\n })\n return this\n },\n } as any\n\n\n\n return cervelloStore as CervelloStore<T & { $value: Maybe<T> }>\n}\n"],"names":["obj","newObj","Array","isArray","map","item","deepClone","Object","keys","forEach","key","obj1","obj2","JSON","stringify","subscribeForReactHook","store$$","onStoreChange","subscription","subscribe","unsubscribe","nestedAttrs","Symbol","storeObject","proxiedNestedObjectMap","Error","get","target","prop","currentStore","getValue","valueByProp","bind","proxifyStore","nestedAttrsPrefix","currentNestedAttrs","cacheKey","isEqualObject","proxiedNestedObject","defineProperty","value","enumerable","writable","configurable","Reflect","set","_target$nestedAttrs","isNestedProp","Boolean","length","clonedStore","keyPath","assignNestedProperty","split","next","createUseStore","store","useSyncExternalStore","useMemo","createUseSelector","selectors","isEqualFunction","useSyncExternalStoreWithSelector","getPartialObjectFromAttributes","attributes","reduce","acc","curr","prev","cervello","initialValue","defaultValue","BehaviorSubject","proxiedStore","cervelloStore","reset","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","pipe","distinctUntilChanged","isEqual","selector","currentPropertyValue","prevPropertyValue","this"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cervello.cjs","sources":["../src/lib/utils/object.ts","../src/lib/helpers/proxify-store.ts","../src/lib/helpers/constants.ts","../src/lib/helpers/create-store-selector-hook.ts","../src/lib/store/index.ts","../src/lib/utils/subject.ts"],"sourcesContent":["import { INTERNAL_VALUE_PROP } from '../helpers/constants'\n\n\n/**\n * Clones all the provided object and nested properties and it also\n * iterates nested arrays to deepClone them\n *\n * @param obj - base object to be cloned\n * @returns new cloned object with new reference\n */\nexport function deepClone <T> (obj: T): T {\n if (!obj || typeof obj !== 'object')\n return obj\n\n let newObj = {} as any\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n } else {\n Object.entries(obj).forEach(([key, value]) => {\n newObj[key] = deepClone(value)\n })\n }\n return newObj as T\n}\n\n\n/**\n * Guard to check is variable is an object\n * @param obj - variable to be checked\n * @returns boolean\n */\nexport const isObject = (obj: unknown): obj is Record<string | symbol, unknown> => (\n obj !== null\n && typeof obj === 'object'\n && !Array.isArray(obj)\n)\n\n\n\n\n/**\n * Returns the actual target value instead of root\n * object with internals props like $$value$$\n *\n * @param target - object from subscription or proxy\n * @returns actual value\n */\nexport const okTarget = (target: any): any => target[INTERNAL_VALUE_PROP] ?? target\n\n\n\n\n/**\n * Gets an object with just the properties requested\n * instead of the full object\n *\n * @param properties - object properties\n * @param obj - target to get the properties\n * @returns New object with just the requested properties\n */\nexport function getPartialObjectFromProperties<T> (properties: Array<keyof T>, obj: T): any {\n return properties.reduce<any>((acc, curr) => {\n acc[curr] = obj[curr]\n return acc\n }, {})\n}\n\n\n\nconst stringify = (obj: any): string => JSON.stringify(obj)\n/**\n * Compare 2 provided objects by stringing them\n * @param a - first object\n * @param b - second object\n * @returns boolean\n */\nexport const contentComparer = (a: any, b: any): boolean => stringify(a) === stringify(b)\n","import { deepClone, isObject, okTarget } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nexport function proxifyStore <T> (store$$: CacheableSubject<T>, objectToProxify: T, proxiedNestedObjectMap: any, shouldProxifyNestedObj: boolean): T\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (\n store$$: CacheableSubject<T>,\n objectToProxify: T,\n proxiedNestedObjectMap: any,\n shouldProxifyNestedObj: boolean,\n): T {\n if (typeof objectToProxify !== 'object') throw new Error('Store must be an object')\n\n /** Proxify object and push value to subject */\n return new Proxy(objectToProxify, {\n get (t, prop) {\n const target = okTarget(t)\n\n /**\n * Return actual object when toJSON\n * is called instead of $$value$$\n */\n if (prop === 'toJSON') return () => target\n\n const propertyValue = Reflect.get(target, prop)\n\n if (shouldProxifyNestedObj && isObject(propertyValue)) {\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[prop]\n if (cachedValue) return cachedValue\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n // const proxied = proxifyStore(store$$ as any, { $$value$$: propertyValue }, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[prop] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, value) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newValue = deepClone(value)\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newValue)\n store$$.next(newValue)\n return true\n }\n\n const target = okTarget(t)\n const propValue = Reflect.get(target, prop)\n\n /** If new value is the same as the current one */\n if (propValue === value) return true\n\n\n /** Set value to target reference */\n Reflect.set(target, prop, value)\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(propValue) && proxiedNestedObjectMap[prop]) {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n const proxied = proxifyStore(store$$ as any, value, proxiedNestedObjectMap, shouldProxifyNestedObj)\n proxiedNestedObjectMap[prop] = proxied\n }\n\n /** Push new store object (new reference for immutability) */\n store$$.next(Object.assign({}, store$$.getValue()))\n\n return true\n },\n\n\n\n\n has (t, p) {\n return Reflect.has(okTarget(t), p)\n },\n\n ownKeys (t) {\n return Reflect.ownKeys(okTarget(t))\n },\n\n getOwnPropertyDescriptor (t, p) {\n return Reflect.getOwnPropertyDescriptor(okTarget(t), p)\n },\n\n\n\n }) as any\n}\n","export const INTERNAL_VALUE_PROP = '$$value$$'\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { useRef } from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { contentComparer, getPartialObjectFromProperties } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol('_isServer')\n\n\nexport function createStoreSelectorHook<T> (store$$: CacheableSubject<T>, proxiedStore: any, type: 'full' | 'slice'): UseSelector<T> {\n const serverInitialValue = Object.assign({}, (store$$.getValue() as any)[INTERNAL_VALUE_PROP], { [isServerSymbol]: true })\n\n\n // SELECTOR HOOK -------------------------------------------------\n const useStoreWithSelectors = <Attributes extends Array<keyof WithoutType<T, Function>>>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ): ObjectFromAttributes<T, Attributes> => {\n const prevSlice = useRef< ObjectFromAttributes<T, Attributes> | null >(null)\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') return onStoreChange()\n\n const currentSlice = getPartialObjectFromProperties(selectors, v)\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n if (!isEquals) {\n prevSlice.current = currentSlice\n onStoreChange()\n }\n },\n })\n\n return () => { subscription.unsubscribe() }\n },\n () => store$$.getValue(),\n () => serverInitialValue,\n )\n\n\n const isServerStore = Object.getOwnPropertySymbols(store).includes(isServerSymbol)\n\n return isServerStore ? store : proxiedStore\n }\n\n return useStoreWithSelectors\n}\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { createStoreSelectorHook, proxifyStore } from '../helpers'\nimport { INTERNAL_VALUE_PROP } from '../helpers/constants'\nimport {\n contentComparer,\n deepClone,\n getPartialObjectFromProperties,\n createCacheableSubject,\n okTarget,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ninterface CervelloStoreUseParam<StoreType> {\n onChange: (cb: (store: StoreType) => void) => void\n onPartialChange: <\n Attributes extends keyof WithoutType<StoreType, Function>,\n R extends Exclude<Attributes, '$value'>,\n ArrayOfAttributes extends Array <R>,\n > (selectors: ArrayOfAttributes, cb: (store: StoreType) => void) => void\n}\n\n/**\n * Use function which allows you to listen for changes in the store.\n */\nexport type CervelloUseFunction<StoreType> = (param: CervelloStoreUseParam<StoreType>) => void\n\n\ninterface CervelloStore<StoreType> {\n /** Reactive store */\n store: StoreType\n /** Hook to react to all changes done to 'store' */\n useStore: () => StoreType\n /** Hook to react to changes done to 'store' in all the attributes provided */\n useSelector: UseSelector<StoreType>\n /** Resets the value to the initial value passed in */\n reset: () => void\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType>\n}\n\n\nexport interface CervelloOptions {\n reactiveNestedObjects: boolean\n}\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Object with the default values for the store\n *\n * @returns - \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: () => T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/** @internal */\nexport function cervello <T> (\n initialValue: T | (() => T),\n options: CervelloOptions = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }> {\n const defaultValue: T = typeof initialValue === 'function' ? (initialValue as any)() : initialValue\n\n\n const clonedInitialValue = { [INTERNAL_VALUE_PROP]: deepClone(defaultValue) } as any as T\n\n /**\n * Object map to keep reference of nested object proxies created\n * to avoid problems with reference equality (i.e.: useEffect dependencies array)\n */\n const proxiedNestedObjectMap: any = {}\n\n const store$$ = createCacheableSubject(clonedInitialValue, false) as any\n const proxiedStore = proxifyStore<T>(store$$, clonedInitialValue, proxiedNestedObjectMap, options.reactiveNestedObjects)\n\n const cervelloStore = {\n store: proxiedStore,\n reset () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n useStore: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n useSelector: createStoreSelectorHook<T>(store$$, proxiedStore, 'slice'),\n // --------------------------------------------------------------------------\n\n use (...functionList: any) {\n functionList.forEach((func: any) => {\n func({\n onChange (cb: any) {\n store$$.subscribe({ next: (_: any) => { cb(proxiedStore) } })\n },\n onPartialChange (attrs: Array<keyof T>, cb: any) {\n let prevSlice: any = getPartialObjectFromProperties(attrs, okTarget(clonedInitialValue))\n store$$.subscribe({\n next: (v: T) => {\n const target = okTarget(v)\n const currentSlice = getPartialObjectFromProperties(attrs, target)\n\n const isEquals = contentComparer(prevSlice, currentSlice)\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n return this\n },\n } as any\n\n\n\n return cervelloStore as CervelloStore<T & { $value: Maybe<T> }>\n}\n","\nexport type Noop = () => void\n\n\nexport interface Observer<T> {\n next: (value: T) => void\n}\n\nexport interface Subscription {\n unsubscribe: Noop\n}\n\nexport type CacheableSubject<T> = {\n getValue: () => T\n subscribe: (value: Observer<T>) => Subscription\n unSubscribeAll: Noop\n} & Observer<T>\n\n\n\nexport function createCacheableSubject<T> (defaultValue: T, getValueOnSubscribe = true): CacheableSubject<T> {\n let observerList: Array<Observer<T>> = []\n let value = defaultValue\n\n const getValue = (): T => value\n\n const next = (newValue: T): void => {\n value = newValue\n observerList.forEach((o) => { o.next(newValue) })\n }\n\n const subscribe = (observer: Observer<T>): Subscription => {\n // Push cached value on subscribe\n if (getValueOnSubscribe) observer.next(value)\n // Store the observer to be notified\n observerList.push(observer)\n return {\n unsubscribe: () => {\n observerList = observerList.filter(o => o !== observer)\n },\n }\n }\n\n const unSubscribeAll = (): void => {\n observerList = []\n }\n\n return {\n getValue,\n next,\n subscribe,\n unSubscribeAll,\n }\n}\n"],"names":["deepClone","obj","newObj","Array","isArray","map","item","Object","entries","forEach","_ref","okTarget","target","_target$INTERNAL_VALU","getPartialObjectFromProperties","properties","reduce","acc","curr","stringify","JSON","contentComparer","a","b","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","Reflect","isObject","cachedValue","proxied","set","value","hasOwn","isRootTarget","newValue","next","propValue","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","Symbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","cervello","initialValue","options","reactiveNestedObjects","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","o","observer","push","filter","unSubscribeAll","cervelloStore","reset","$value","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
|
package/dist/cervello.esm.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{useRef as n}from"react";import{useSyncExternalStore as e}from"use-sync-external-store/shim/index.js";function r(n){if(!n||"object"!=typeof n)return n;var e={};return Array.isArray(n)?e=n.map(function(n){return r(n)}):Object.entries(n).forEach(function(n){e[n[0]]=r(n[1])}),e}var t=function(n){return null!==n&&"object"==typeof n&&!Array.isArray(n)},u=function(n){var e;return null!=(e=n.$$value$$)?e:n};function c(n,e){return n.reduce(function(n,r){return n[r]=e[r],n},{})}var i=function(n){return JSON.stringify(n)},o=function(n,e){return i(n)===i(e)};function f(n,e,c,i){if("object"!=typeof e)throw new Error("Store must be an object");return new Proxy(e,{get:function(e,r){var o=u(e);if("toJSON"===r)return function(){return o};var a=Reflect.get(o,r);if(i&&t(a)){var s=c[r];if(s)return s;var l=f(n,a,c,i);return c[r]=l,l}return a},set:function(e,o,a){var s=Object.hasOwn(e,"$$value$$");if("$value"===o&&s){var l=r(a);return c={},Reflect.set(e,"$$value$$",l),n.next(l),!0}var v=u(e),b=Reflect.get(v,o);if(b===a)return!0;if(Reflect.set(v,o,a),i&&t(b)&&c[o]){var $=f(n,a,c,i);c[o]=$}return n.next(Object.assign({},n.getValue())),!0},has:function(n,e){return Reflect.has(u(n),e)},ownKeys:function(n){return Reflect.ownKeys(u(n))},getOwnPropertyDescriptor:function(n,e){return Reflect.getOwnPropertyDescriptor(u(n),e)}})}var a=Symbol("_isServer");function s(r,t,u){var i,f=Object.assign({},r.getValue().$$value$$,((i={})[a]=!0,i));return function(i,s){var l=n(null),v=e(function(n){var e=r.subscribe({next:function(e){if("full"===u)return n();var r=c(i,e);(null!=s?s:o)(l.current,r)||(l.current=r,n())}});return function(){e.unsubscribe()}},function(){return r.getValue()},function(){return f});return Object.getOwnPropertySymbols(v).includes(a)?v:t}}function l(n,e){var t;void 0===e&&(e={reactiveNestedObjects:!0});var i="function"==typeof n?n():n,a=((t={}).$$value$$=r(i),t),l=function(n,e){void 0===e&&(e=!0);var r=[],t=n;return{getValue:function(){return t},next:function(n){t=n,r.forEach(function(e){e.next(n)})},subscribe:function(n){return e&&n.next(t),r.push(n),{unsubscribe:function(){r=r.filter(function(e){return e!==n})}}},unSubscribeAll:function(){r=[]}}}(a,!1),v=f(l,a,{},e.reactiveNestedObjects),b={store:v,reset:function(){v.$value=i},useStore:s(l,v,"full"),useSelector:s(l,v,"slice"),use:function(){return[].slice.call(arguments).forEach(function(n){n({onChange:function(n){l.subscribe({next:function(e){n(v)}})},onPartialChange:function(n,e){var t=c(n,u(a));l.subscribe({next:function(i){var f=u(i),a=c(n,f);o(t,a)||(e(v),t=r(a))}})}})}),this}};return b}export{l as cervello};
|
|
2
2
|
//# sourceMappingURL=cervello.esm.js.map
|
package/dist/cervello.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cervello.esm.js","sources":["../src/lib/utils/object.ts","../src/lib/utils/subscribe-for-react.ts","../src/lib/helpers/proxify-store.ts","../src/lib/helpers/create-use-store.ts","../src/lib/helpers/create-use-selector.ts","../src/lib/store/index.ts"],"sourcesContent":["export function deepClone <T> (obj: any): T {\n if (!obj || typeof obj !== 'object') {\n return obj\n }\n let newObj = {} as any\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n } else {\n Object.keys(obj).forEach((key) => {\n // eslint-disable-next-line no-return-assign\n return newObj[key] = deepClone(obj[key])\n })\n }\n return newObj as T\n}\n\nexport function isEqualObject (obj1: any, obj2: any): boolean {\n return JSON.stringify(obj1) === JSON.stringify(obj2)\n}\n","import type { BehaviorSubject } from 'rxjs'\n\n\n\nexport const subscribeForReactHook = <T>(store$$: BehaviorSubject<T>): typeof subscribe => {\n const subscribe = (onStoreChange: () => void): () => void => {\n const subscription = store$$.subscribe(onStoreChange)\n return () => {\n subscription.unsubscribe()\n }\n }\n return subscribe\n}\n","\nimport { deepClone, isEqualObject } from '../utils'\n\nimport type { BehaviorSubject } from 'rxjs'\n\n\n\nconst NESTED_ATTRIBUTES_SYMBOL = '$$p-a' // parent-attributes\nconst nestedAttrs = Symbol(NESTED_ATTRIBUTES_SYMBOL)\n\nfunction assignNestedProperty (obj: any, keyPath: Array<string>, prop: string, value: unknown): any {\n keyPath.forEach((key) => { obj = obj[key] })\n obj[prop] = value\n}\n\nexport function proxifyStore <T extends any> (store$$: BehaviorSubject<T>, storeObject: T, proxiedNestedObjectMap: any): T\n\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (store$$: BehaviorSubject<T>, storeObject: T, proxiedNestedObjectMap: any): T {\n if (typeof storeObject !== 'object') throw new Error('Store must be an object')\n\n return new Proxy<T>(\n storeObject,\n {\n get: function (target: T, prop: string | symbol): any {\n\n const currentStore = target?.[nestedAttrs] ? target : store$$.getValue()\n const valueByProp = currentStore[prop]\n\n if (prop in currentStore) {\n if (typeof valueByProp === 'function') {\n return valueByProp.bind(proxifyStore(store$$, store$$.getValue(), proxiedNestedObjectMap))\n }\n\n // Return proxied object for nested reactivity\n if (valueByProp\n && typeof valueByProp === 'object'\n && !Array.isArray(valueByProp)\n && typeof prop !== 'symbol'\n ) {\n const currentNestedAttrs = target?.[nestedAttrs]\n const nestedAttrsPrefix = currentNestedAttrs ? `${currentNestedAttrs as string}.` : ''\n\n const cacheKey = `${nestedAttrsPrefix}-${prop}`\n\n if (\n proxiedNestedObjectMap[cacheKey]\n && isEqualObject(proxiedNestedObjectMap[cacheKey], valueByProp)\n ) return proxiedNestedObjectMap[cacheKey]\n\n const proxiedNestedObject = proxifyStore(\n store$$,\n Object.defineProperty(\n valueByProp,\n nestedAttrs,\n {\n value: `${nestedAttrsPrefix}${prop}`,\n enumerable: false,\n writable: false,\n configurable: false,\n },\n ),\n proxiedNestedObjectMap,\n )\n\n proxiedNestedObjectMap[cacheKey] = proxiedNestedObject\n\n return proxiedNestedObject\n }\n\n return valueByProp\n }\n\n return Reflect.get(target, prop)\n },\n set: function (target: T, prop: string | symbol, value: any) {\n const currentStore = store$$.getValue() as any\n const isNestedProp = Boolean(target[nestedAttrs]?.length)\n let clonedStore = deepClone<any>(currentStore)\n\n if (isNestedProp) {\n const nestedAttributes = (target[nestedAttrs] as string).split('.')\n assignNestedProperty(clonedStore, nestedAttributes, prop as string, value)\n } else {\n if (prop === '$value') clonedStore = value\n else clonedStore[prop] = value\n }\n\n if (!isEqualObject(currentStore, clonedStore)) {\n store$$.next(clonedStore)\n }\n\n return true\n },\n },\n )\n}\n","\nimport { useMemo } from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { subscribeForReactHook } from '../utils/subscribe-for-react'\nimport { proxifyStore } from './proxify-store'\n\nimport type { BehaviorSubject } from 'rxjs'\nimport type { Maybe } from 'src/types/shared'\n\n\n\nexport function createUseStore <T> (store$$: BehaviorSubject<T>, proxiedNestedObjectMap: any): () => T & { $value: Maybe<T> } {\n const subscribe = subscribeForReactHook(store$$)\n const getValue = store$$.getValue.bind(store$$)\n\n\n // USE STORE HOOK -------------------------------------------------\n const useStore = (): T & { $value: Maybe<T> } => {\n const store = useSyncExternalStore(subscribe, getValue, getValue)\n\n const cachedStore = useMemo(() => proxifyStore(store$$, store, proxiedNestedObjectMap), [store])\n\n return cachedStore as T & { $value: Maybe<T> }\n }\n\n\n return useStore\n}\n","\nimport { useMemo } from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector.js'\n\n\nimport { isEqualObject } from '../utils'\nimport { subscribeForReactHook } from '../utils/subscribe-for-react'\nimport { proxifyStore } from './proxify-store'\n\nimport type { ObjectFromAttributes, WithoutType } from '../../types/shared'\nimport type { BehaviorSubject } from 'rxjs'\n\n\n\nexport function getPartialObjectFromAttributes <T> (attributes: Array<keyof T>, store: T): any {\n return attributes.reduce<any>((acc, curr) => {\n acc[curr] = store[curr]\n return acc\n }, {})\n}\n\nexport type UseSelector<T> = <Attributes extends Array< keyof WithoutType<T, Function> >>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ) => ObjectFromAttributes<T, Attributes>\n\n\n\nexport function createUseSelector <T> (store$$: BehaviorSubject<T>, proxiedNestedObjectMap: any): UseSelector<T> {\n const subscribe = subscribeForReactHook(store$$)\n const getValue = store$$.getValue.bind(store$$)\n\n // USE SELECTOR HOOK -------------------------------------------------\n const useSelector = <Attributes extends Array< keyof WithoutType<T, Function> >>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ): ObjectFromAttributes<T, Attributes> => {\n const store = useSyncExternalStoreWithSelector<T, ObjectFromAttributes<T, Attributes>>(\n subscribe,\n getValue,\n getValue,\n (store) => getPartialObjectFromAttributes(selectors, store),\n (prev, curr) => isEqualFunction\n ? isEqualFunction(prev, curr)\n : isEqualObject(prev, curr),\n )\n\n const cachedStore = useMemo(() => proxifyStore(\n store$$ as any,\n store,\n proxiedNestedObjectMap,\n ), [store])\n\n return cachedStore\n }\n\n return useSelector\n}\n","import { BehaviorSubject, distinctUntilChanged } from 'rxjs'\n\nimport { createUseSelector, createUseStore, proxifyStore } from '../helpers'\nimport { isEqualObject } from '../utils'\n\nimport type { Maybe, WithoutType } from '../../types/shared'\nimport type { UseSelector } from '../helpers'\n\n\n\n// const STORE_SYMBOL = '__cervello-store__'\n\ninterface CervelloStoreUseParam<StoreType> {\n onChange: (cb: (store: StoreType) => void) => void\n onPartialChange: <\n Attributes extends Array< keyof WithoutType<StoreType, Function>>\n > (selectors: Attributes, cb: (store: StoreType) => void) => void\n}\n\n/**\n * Use function which allows you to listen for changes in the store.\n */\nexport type CervelloUseFunction<StoreType> = (param: CervelloStoreUseParam<StoreType>) => void\n\n\ninterface CervelloStore<StoreType> {\n /** Reactive store */\n store: StoreType\n /** Hook to react to all changes done to 'store' */\n useStore: () => StoreType\n /** Hook to react to changes done to 'store' in all the attributes provided */\n useSelector: UseSelector<StoreType>\n /** Resets the value to the initial value passed in */\n reset: () => void\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType>\n}\n\n// /**\n// * @note Currently not working\n// */\n// export interface CervelloOptions {\n// persist?:\n// | boolean\n// // | {\n// // getItem: (key: string) => any\n// // }\n// }\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue Object with the default values for the store\n *\n * @returns - { store, useStore, useSelector }\n */\nexport function cervello <T> (initialValue: T): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue Function which returns the default values for the store\n *\n * @returns - { store, useStore, useSelector }\n */\nexport function cervello <T> (initialValue: () => T): CervelloStore<T & { $value: Maybe<T> }>\n\n\n\n\n\n/** @internal */\nexport function cervello <T> (initialValue: T | (() => T)): CervelloStore<T & { $value: Maybe<T> }> {\n const defaultValue = typeof initialValue === 'function' ? (initialValue as any)() : initialValue\n const store$$ = new BehaviorSubject<T>(defaultValue)\n\n // Object map to keep reference of nested object proxies created\n // to avoid problems with reference equality (i.e.: useEffect dependencies array)\n const proxiedNestedObjectMap: any = {}\n\n const proxiedStore = proxifyStore<T>(store$$, defaultValue, proxiedNestedObjectMap)\n\n const cervelloStore = {\n store: proxiedStore,\n reset () {\n if (!isEqualObject(store$$.getValue(), defaultValue)) {\n store$$.next(defaultValue)\n }\n },\n\n // TO BE SEPARATED IN cervello/react package ---------------------\n useStore: createUseStore<T>(store$$, proxiedNestedObjectMap),\n useSelector: createUseSelector<T>(store$$, proxiedNestedObjectMap),\n // ---------------------------------------------------------------\n\n use (...functionList: any) {\n functionList.forEach((func: any) => {\n func({\n onChange (cb: any) {\n store$$.subscribe((_) => cb(proxiedStore))\n },\n onPartialChange (attrs: Array<keyof T>, cb: any) {\n store$$.pipe(\n distinctUntilChanged((prev, curr) => {\n let isEqual = true\n attrs.forEach((selector) => {\n const currentPropertyValue = curr[selector]\n const prevPropertyValue = prev[selector]\n if (isEqual) {\n isEqual = typeof currentPropertyValue === 'object'\n ? isEqualObject(prevPropertyValue, currentPropertyValue)\n : prevPropertyValue === currentPropertyValue\n }\n })\n return isEqual\n }),\n ).subscribe((_) => cb(proxiedStore))\n },\n })\n })\n return this\n },\n } as any\n\n\n\n return cervelloStore as CervelloStore<T & { $value: Maybe<T> }>\n}\n"],"names":["obj","newObj","Array","isArray","map","item","deepClone","Object","keys","forEach","key","obj1","obj2","JSON","stringify","subscribeForReactHook","store$$","onStoreChange","subscription","subscribe","unsubscribe","nestedAttrs","Symbol","storeObject","proxiedNestedObjectMap","Error","get","target","prop","currentStore","getValue","valueByProp","bind","proxifyStore","nestedAttrsPrefix","currentNestedAttrs","cacheKey","isEqualObject","proxiedNestedObject","defineProperty","value","enumerable","writable","configurable","Reflect","set","_target$nestedAttrs","isNestedProp","Boolean","length","clonedStore","keyPath","assignNestedProperty","split","next","createUseStore","store","useSyncExternalStore","useMemo","createUseSelector","selectors","isEqualFunction","useSyncExternalStoreWithSelector","getPartialObjectFromAttributes","attributes","reduce","acc","curr","prev","cervello","initialValue","defaultValue","BehaviorSubject","proxiedStore","cervelloStore","reset","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","pipe","distinctUntilChanged","isEqual","selector","currentPropertyValue","prevPropertyValue","this"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cervello.esm.js","sources":["../src/lib/utils/object.ts","../src/lib/helpers/proxify-store.ts","../src/lib/helpers/constants.ts","../src/lib/helpers/create-store-selector-hook.ts","../src/lib/store/index.ts","../src/lib/utils/subject.ts"],"sourcesContent":["import { INTERNAL_VALUE_PROP } from '../helpers/constants'\n\n\n/**\n * Clones all the provided object and nested properties and it also\n * iterates nested arrays to deepClone them\n *\n * @param obj - base object to be cloned\n * @returns new cloned object with new reference\n */\nexport function deepClone <T> (obj: T): T {\n if (!obj || typeof obj !== 'object')\n return obj\n\n let newObj = {} as any\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n } else {\n Object.entries(obj).forEach(([key, value]) => {\n newObj[key] = deepClone(value)\n })\n }\n return newObj as T\n}\n\n\n/**\n * Guard to check is variable is an object\n * @param obj - variable to be checked\n * @returns boolean\n */\nexport const isObject = (obj: unknown): obj is Record<string | symbol, unknown> => (\n obj !== null\n && typeof obj === 'object'\n && !Array.isArray(obj)\n)\n\n\n\n\n/**\n * Returns the actual target value instead of root\n * object with internals props like $$value$$\n *\n * @param target - object from subscription or proxy\n * @returns actual value\n */\nexport const okTarget = (target: any): any => target[INTERNAL_VALUE_PROP] ?? target\n\n\n\n\n/**\n * Gets an object with just the properties requested\n * instead of the full object\n *\n * @param properties - object properties\n * @param obj - target to get the properties\n * @returns New object with just the requested properties\n */\nexport function getPartialObjectFromProperties<T> (properties: Array<keyof T>, obj: T): any {\n return properties.reduce<any>((acc, curr) => {\n acc[curr] = obj[curr]\n return acc\n }, {})\n}\n\n\n\nconst stringify = (obj: any): string => JSON.stringify(obj)\n/**\n * Compare 2 provided objects by stringing them\n * @param a - first object\n * @param b - second object\n * @returns boolean\n */\nexport const contentComparer = (a: any, b: any): boolean => stringify(a) === stringify(b)\n","import { deepClone, isObject, okTarget } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nexport function proxifyStore <T> (store$$: CacheableSubject<T>, objectToProxify: T, proxiedNestedObjectMap: any, shouldProxifyNestedObj: boolean): T\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (\n store$$: CacheableSubject<T>,\n objectToProxify: T,\n proxiedNestedObjectMap: any,\n shouldProxifyNestedObj: boolean,\n): T {\n if (typeof objectToProxify !== 'object') throw new Error('Store must be an object')\n\n /** Proxify object and push value to subject */\n return new Proxy(objectToProxify, {\n get (t, prop) {\n const target = okTarget(t)\n\n /**\n * Return actual object when toJSON\n * is called instead of $$value$$\n */\n if (prop === 'toJSON') return () => target\n\n const propertyValue = Reflect.get(target, prop)\n\n if (shouldProxifyNestedObj && isObject(propertyValue)) {\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[prop]\n if (cachedValue) return cachedValue\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n // const proxied = proxifyStore(store$$ as any, { $$value$$: propertyValue }, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[prop] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, value) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newValue = deepClone(value)\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newValue)\n store$$.next(newValue)\n return true\n }\n\n const target = okTarget(t)\n const propValue = Reflect.get(target, prop)\n\n /** If new value is the same as the current one */\n if (propValue === value) return true\n\n\n /** Set value to target reference */\n Reflect.set(target, prop, value)\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(propValue) && proxiedNestedObjectMap[prop]) {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n const proxied = proxifyStore(store$$ as any, value, proxiedNestedObjectMap, shouldProxifyNestedObj)\n proxiedNestedObjectMap[prop] = proxied\n }\n\n /** Push new store object (new reference for immutability) */\n store$$.next(Object.assign({}, store$$.getValue()))\n\n return true\n },\n\n\n\n\n has (t, p) {\n return Reflect.has(okTarget(t), p)\n },\n\n ownKeys (t) {\n return Reflect.ownKeys(okTarget(t))\n },\n\n getOwnPropertyDescriptor (t, p) {\n return Reflect.getOwnPropertyDescriptor(okTarget(t), p)\n },\n\n\n\n }) as any\n}\n","export const INTERNAL_VALUE_PROP = '$$value$$'\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { useRef } from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { contentComparer, getPartialObjectFromProperties } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol('_isServer')\n\n\nexport function createStoreSelectorHook<T> (store$$: CacheableSubject<T>, proxiedStore: any, type: 'full' | 'slice'): UseSelector<T> {\n const serverInitialValue = Object.assign({}, (store$$.getValue() as any)[INTERNAL_VALUE_PROP], { [isServerSymbol]: true })\n\n\n // SELECTOR HOOK -------------------------------------------------\n const useStoreWithSelectors = <Attributes extends Array<keyof WithoutType<T, Function>>>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ): ObjectFromAttributes<T, Attributes> => {\n const prevSlice = useRef< ObjectFromAttributes<T, Attributes> | null >(null)\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') return onStoreChange()\n\n const currentSlice = getPartialObjectFromProperties(selectors, v)\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n if (!isEquals) {\n prevSlice.current = currentSlice\n onStoreChange()\n }\n },\n })\n\n return () => { subscription.unsubscribe() }\n },\n () => store$$.getValue(),\n () => serverInitialValue,\n )\n\n\n const isServerStore = Object.getOwnPropertySymbols(store).includes(isServerSymbol)\n\n return isServerStore ? store : proxiedStore\n }\n\n return useStoreWithSelectors\n}\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { createStoreSelectorHook, proxifyStore } from '../helpers'\nimport { INTERNAL_VALUE_PROP } from '../helpers/constants'\nimport {\n contentComparer,\n deepClone,\n getPartialObjectFromProperties,\n createCacheableSubject,\n okTarget,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ninterface CervelloStoreUseParam<StoreType> {\n onChange: (cb: (store: StoreType) => void) => void\n onPartialChange: <\n Attributes extends keyof WithoutType<StoreType, Function>,\n R extends Exclude<Attributes, '$value'>,\n ArrayOfAttributes extends Array <R>,\n > (selectors: ArrayOfAttributes, cb: (store: StoreType) => void) => void\n}\n\n/**\n * Use function which allows you to listen for changes in the store.\n */\nexport type CervelloUseFunction<StoreType> = (param: CervelloStoreUseParam<StoreType>) => void\n\n\ninterface CervelloStore<StoreType> {\n /** Reactive store */\n store: StoreType\n /** Hook to react to all changes done to 'store' */\n useStore: () => StoreType\n /** Hook to react to changes done to 'store' in all the attributes provided */\n useSelector: UseSelector<StoreType>\n /** Resets the value to the initial value passed in */\n reset: () => void\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType>\n}\n\n\nexport interface CervelloOptions {\n reactiveNestedObjects: boolean\n}\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Object with the default values for the store\n *\n * @returns - \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: () => T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/** @internal */\nexport function cervello <T> (\n initialValue: T | (() => T),\n options: CervelloOptions = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }> {\n const defaultValue: T = typeof initialValue === 'function' ? (initialValue as any)() : initialValue\n\n\n const clonedInitialValue = { [INTERNAL_VALUE_PROP]: deepClone(defaultValue) } as any as T\n\n /**\n * Object map to keep reference of nested object proxies created\n * to avoid problems with reference equality (i.e.: useEffect dependencies array)\n */\n const proxiedNestedObjectMap: any = {}\n\n const store$$ = createCacheableSubject(clonedInitialValue, false) as any\n const proxiedStore = proxifyStore<T>(store$$, clonedInitialValue, proxiedNestedObjectMap, options.reactiveNestedObjects)\n\n const cervelloStore = {\n store: proxiedStore,\n reset () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n useStore: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n useSelector: createStoreSelectorHook<T>(store$$, proxiedStore, 'slice'),\n // --------------------------------------------------------------------------\n\n use (...functionList: any) {\n functionList.forEach((func: any) => {\n func({\n onChange (cb: any) {\n store$$.subscribe({ next: (_: any) => { cb(proxiedStore) } })\n },\n onPartialChange (attrs: Array<keyof T>, cb: any) {\n let prevSlice: any = getPartialObjectFromProperties(attrs, okTarget(clonedInitialValue))\n store$$.subscribe({\n next: (v: T) => {\n const target = okTarget(v)\n const currentSlice = getPartialObjectFromProperties(attrs, target)\n\n const isEquals = contentComparer(prevSlice, currentSlice)\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n return this\n },\n } as any\n\n\n\n return cervelloStore as CervelloStore<T & { $value: Maybe<T> }>\n}\n","\nexport type Noop = () => void\n\n\nexport interface Observer<T> {\n next: (value: T) => void\n}\n\nexport interface Subscription {\n unsubscribe: Noop\n}\n\nexport type CacheableSubject<T> = {\n getValue: () => T\n subscribe: (value: Observer<T>) => Subscription\n unSubscribeAll: Noop\n} & Observer<T>\n\n\n\nexport function createCacheableSubject<T> (defaultValue: T, getValueOnSubscribe = true): CacheableSubject<T> {\n let observerList: Array<Observer<T>> = []\n let value = defaultValue\n\n const getValue = (): T => value\n\n const next = (newValue: T): void => {\n value = newValue\n observerList.forEach((o) => { o.next(newValue) })\n }\n\n const subscribe = (observer: Observer<T>): Subscription => {\n // Push cached value on subscribe\n if (getValueOnSubscribe) observer.next(value)\n // Store the observer to be notified\n observerList.push(observer)\n return {\n unsubscribe: () => {\n observerList = observerList.filter(o => o !== observer)\n },\n }\n }\n\n const unSubscribeAll = (): void => {\n observerList = []\n }\n\n return {\n getValue,\n next,\n subscribe,\n unSubscribeAll,\n }\n}\n"],"names":["deepClone","obj","newObj","Array","isArray","map","item","Object","entries","forEach","_ref","okTarget","target","_target$INTERNAL_VALU","getPartialObjectFromProperties","properties","reduce","acc","curr","stringify","JSON","contentComparer","a","b","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","Reflect","isObject","cachedValue","proxied","set","value","hasOwn","isRootTarget","newValue","next","propValue","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","Symbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","cervello","initialValue","options","reactiveNestedObjects","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","o","observer","push","filter","unSubscribeAll","cervelloStore","reset","$value","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
|
package/dist/cervello.umd.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("
|
|
1
|
+
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("react"),require("use-sync-external-store/shim/index.js")):"function"==typeof define&&define.amd?define(["exports","react","use-sync-external-store/shim/index.js"],n):n((e||self).react={},e.react,e.index_js)}(this,function(e,n,t){var r="$$value$$";function u(e){if(!e||"object"!=typeof e)return e;var n={};return Array.isArray(e)?n=e.map(function(e){return u(e)}):Object.entries(e).forEach(function(e){n[e[0]]=u(e[1])}),n}var i=function(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)},c=function(e){var n;return null!=(n=e.$$value$$)?n:e};function o(e,n){return e.reduce(function(e,t){return e[t]=n[t],e},{})}var f=function(e){return JSON.stringify(e)},s=function(e,n){return f(e)===f(n)};function a(e,n,t,o){if("object"!=typeof n)throw new Error("Store must be an object");return new Proxy(n,{get:function(n,r){var u=c(n);if("toJSON"===r)return function(){return u};var f=Reflect.get(u,r);if(o&&i(f)){var s=t[r];if(s)return s;var l=a(e,f,t,o);return t[r]=l,l}return f},set:function(n,f,s){var l=Object.hasOwn(n,r);if("$value"===f&&l){var v=u(s);return t={},Reflect.set(n,r,v),e.next(v),!0}var b=c(n),y=Reflect.get(b,f);if(y===s)return!0;if(Reflect.set(b,f,s),o&&i(y)&&t[f]){var d=a(e,s,t,o);t[f]=d}return e.next(Object.assign({},e.getValue())),!0},has:function(e,n){return Reflect.has(c(e),n)},ownKeys:function(e){return Reflect.ownKeys(c(e))},getOwnPropertyDescriptor:function(e,n){return Reflect.getOwnPropertyDescriptor(c(e),n)}})}var l=Symbol("_isServer");function v(e,r,u){var i,c=Object.assign({},e.getValue().$$value$$,((i={})[l]=!0,i));return function(i,f){var a=n.useRef(null),v=t.useSyncExternalStore(function(n){var t=e.subscribe({next:function(e){if("full"===u)return n();var t=o(i,e);(null!=f?f:s)(a.current,t)||(a.current=t,n())}});return function(){t.unsubscribe()}},function(){return e.getValue()},function(){return c});return Object.getOwnPropertySymbols(v).includes(l)?v:r}}e.cervello=function(e,n){var t;void 0===n&&(n={reactiveNestedObjects:!0});var r="function"==typeof e?e():e,i=((t={}).$$value$$=u(r),t),f=function(e,n){void 0===n&&(n=!0);var t=[],r=e;return{getValue:function(){return r},next:function(e){r=e,t.forEach(function(n){n.next(e)})},subscribe:function(e){return n&&e.next(r),t.push(e),{unsubscribe:function(){t=t.filter(function(n){return n!==e})}}},unSubscribeAll:function(){t=[]}}}(i,!1),l=a(f,i,{},n.reactiveNestedObjects),b={store:l,reset:function(){l.$value=r},useStore:v(f,l,"full"),useSelector:v(f,l,"slice"),use:function(){return[].slice.call(arguments).forEach(function(e){e({onChange:function(e){f.subscribe({next:function(n){e(l)}})},onPartialChange:function(e,n){var t=o(e,c(i));f.subscribe({next:function(r){var i=c(r),f=o(e,i);s(t,f)||(n(l),t=u(f))}})}})}),this}};return b}});
|
|
2
2
|
//# sourceMappingURL=cervello.umd.js.map
|
package/dist/cervello.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cervello.umd.js","sources":["../src/lib/utils/object.ts","../src/lib/utils/subscribe-for-react.ts","../src/lib/helpers/proxify-store.ts","../src/lib/helpers/create-use-store.ts","../src/lib/helpers/create-use-selector.ts","../src/lib/store/index.ts"],"sourcesContent":["export function deepClone <T> (obj: any): T {\n if (!obj || typeof obj !== 'object') {\n return obj\n }\n let newObj = {} as any\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n } else {\n Object.keys(obj).forEach((key) => {\n // eslint-disable-next-line no-return-assign\n return newObj[key] = deepClone(obj[key])\n })\n }\n return newObj as T\n}\n\nexport function isEqualObject (obj1: any, obj2: any): boolean {\n return JSON.stringify(obj1) === JSON.stringify(obj2)\n}\n","import type { BehaviorSubject } from 'rxjs'\n\n\n\nexport const subscribeForReactHook = <T>(store$$: BehaviorSubject<T>): typeof subscribe => {\n const subscribe = (onStoreChange: () => void): () => void => {\n const subscription = store$$.subscribe(onStoreChange)\n return () => {\n subscription.unsubscribe()\n }\n }\n return subscribe\n}\n","\nimport { deepClone, isEqualObject } from '../utils'\n\nimport type { BehaviorSubject } from 'rxjs'\n\n\n\nconst NESTED_ATTRIBUTES_SYMBOL = '$$p-a' // parent-attributes\nconst nestedAttrs = Symbol(NESTED_ATTRIBUTES_SYMBOL)\n\nfunction assignNestedProperty (obj: any, keyPath: Array<string>, prop: string, value: unknown): any {\n keyPath.forEach((key) => { obj = obj[key] })\n obj[prop] = value\n}\n\nexport function proxifyStore <T extends any> (store$$: BehaviorSubject<T>, storeObject: T, proxiedNestedObjectMap: any): T\n\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (store$$: BehaviorSubject<T>, storeObject: T, proxiedNestedObjectMap: any): T {\n if (typeof storeObject !== 'object') throw new Error('Store must be an object')\n\n return new Proxy<T>(\n storeObject,\n {\n get: function (target: T, prop: string | symbol): any {\n\n const currentStore = target?.[nestedAttrs] ? target : store$$.getValue()\n const valueByProp = currentStore[prop]\n\n if (prop in currentStore) {\n if (typeof valueByProp === 'function') {\n return valueByProp.bind(proxifyStore(store$$, store$$.getValue(), proxiedNestedObjectMap))\n }\n\n // Return proxied object for nested reactivity\n if (valueByProp\n && typeof valueByProp === 'object'\n && !Array.isArray(valueByProp)\n && typeof prop !== 'symbol'\n ) {\n const currentNestedAttrs = target?.[nestedAttrs]\n const nestedAttrsPrefix = currentNestedAttrs ? `${currentNestedAttrs as string}.` : ''\n\n const cacheKey = `${nestedAttrsPrefix}-${prop}`\n\n if (\n proxiedNestedObjectMap[cacheKey]\n && isEqualObject(proxiedNestedObjectMap[cacheKey], valueByProp)\n ) return proxiedNestedObjectMap[cacheKey]\n\n const proxiedNestedObject = proxifyStore(\n store$$,\n Object.defineProperty(\n valueByProp,\n nestedAttrs,\n {\n value: `${nestedAttrsPrefix}${prop}`,\n enumerable: false,\n writable: false,\n configurable: false,\n },\n ),\n proxiedNestedObjectMap,\n )\n\n proxiedNestedObjectMap[cacheKey] = proxiedNestedObject\n\n return proxiedNestedObject\n }\n\n return valueByProp\n }\n\n return Reflect.get(target, prop)\n },\n set: function (target: T, prop: string | symbol, value: any) {\n const currentStore = store$$.getValue() as any\n const isNestedProp = Boolean(target[nestedAttrs]?.length)\n let clonedStore = deepClone<any>(currentStore)\n\n if (isNestedProp) {\n const nestedAttributes = (target[nestedAttrs] as string).split('.')\n assignNestedProperty(clonedStore, nestedAttributes, prop as string, value)\n } else {\n if (prop === '$value') clonedStore = value\n else clonedStore[prop] = value\n }\n\n if (!isEqualObject(currentStore, clonedStore)) {\n store$$.next(clonedStore)\n }\n\n return true\n },\n },\n )\n}\n","\nimport { useMemo } from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { subscribeForReactHook } from '../utils/subscribe-for-react'\nimport { proxifyStore } from './proxify-store'\n\nimport type { BehaviorSubject } from 'rxjs'\nimport type { Maybe } from 'src/types/shared'\n\n\n\nexport function createUseStore <T> (store$$: BehaviorSubject<T>, proxiedNestedObjectMap: any): () => T & { $value: Maybe<T> } {\n const subscribe = subscribeForReactHook(store$$)\n const getValue = store$$.getValue.bind(store$$)\n\n\n // USE STORE HOOK -------------------------------------------------\n const useStore = (): T & { $value: Maybe<T> } => {\n const store = useSyncExternalStore(subscribe, getValue, getValue)\n\n const cachedStore = useMemo(() => proxifyStore(store$$, store, proxiedNestedObjectMap), [store])\n\n return cachedStore as T & { $value: Maybe<T> }\n }\n\n\n return useStore\n}\n","\nimport { useMemo } from 'react'\nimport { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector.js'\n\n\nimport { isEqualObject } from '../utils'\nimport { subscribeForReactHook } from '../utils/subscribe-for-react'\nimport { proxifyStore } from './proxify-store'\n\nimport type { ObjectFromAttributes, WithoutType } from '../../types/shared'\nimport type { BehaviorSubject } from 'rxjs'\n\n\n\nexport function getPartialObjectFromAttributes <T> (attributes: Array<keyof T>, store: T): any {\n return attributes.reduce<any>((acc, curr) => {\n acc[curr] = store[curr]\n return acc\n }, {})\n}\n\nexport type UseSelector<T> = <Attributes extends Array< keyof WithoutType<T, Function> >>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ) => ObjectFromAttributes<T, Attributes>\n\n\n\nexport function createUseSelector <T> (store$$: BehaviorSubject<T>, proxiedNestedObjectMap: any): UseSelector<T> {\n const subscribe = subscribeForReactHook(store$$)\n const getValue = store$$.getValue.bind(store$$)\n\n // USE SELECTOR HOOK -------------------------------------------------\n const useSelector = <Attributes extends Array< keyof WithoutType<T, Function> >>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ): ObjectFromAttributes<T, Attributes> => {\n const store = useSyncExternalStoreWithSelector<T, ObjectFromAttributes<T, Attributes>>(\n subscribe,\n getValue,\n getValue,\n (store) => getPartialObjectFromAttributes(selectors, store),\n (prev, curr) => isEqualFunction\n ? isEqualFunction(prev, curr)\n : isEqualObject(prev, curr),\n )\n\n const cachedStore = useMemo(() => proxifyStore(\n store$$ as any,\n store,\n proxiedNestedObjectMap,\n ), [store])\n\n return cachedStore\n }\n\n return useSelector\n}\n","import { BehaviorSubject, distinctUntilChanged } from 'rxjs'\n\nimport { createUseSelector, createUseStore, proxifyStore } from '../helpers'\nimport { isEqualObject } from '../utils'\n\nimport type { Maybe, WithoutType } from '../../types/shared'\nimport type { UseSelector } from '../helpers'\n\n\n\n// const STORE_SYMBOL = '__cervello-store__'\n\ninterface CervelloStoreUseParam<StoreType> {\n onChange: (cb: (store: StoreType) => void) => void\n onPartialChange: <\n Attributes extends Array< keyof WithoutType<StoreType, Function>>\n > (selectors: Attributes, cb: (store: StoreType) => void) => void\n}\n\n/**\n * Use function which allows you to listen for changes in the store.\n */\nexport type CervelloUseFunction<StoreType> = (param: CervelloStoreUseParam<StoreType>) => void\n\n\ninterface CervelloStore<StoreType> {\n /** Reactive store */\n store: StoreType\n /** Hook to react to all changes done to 'store' */\n useStore: () => StoreType\n /** Hook to react to changes done to 'store' in all the attributes provided */\n useSelector: UseSelector<StoreType>\n /** Resets the value to the initial value passed in */\n reset: () => void\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType>\n}\n\n// /**\n// * @note Currently not working\n// */\n// export interface CervelloOptions {\n// persist?:\n// | boolean\n// // | {\n// // getItem: (key: string) => any\n// // }\n// }\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue Object with the default values for the store\n *\n * @returns - { store, useStore, useSelector }\n */\nexport function cervello <T> (initialValue: T): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue Function which returns the default values for the store\n *\n * @returns - { store, useStore, useSelector }\n */\nexport function cervello <T> (initialValue: () => T): CervelloStore<T & { $value: Maybe<T> }>\n\n\n\n\n\n/** @internal */\nexport function cervello <T> (initialValue: T | (() => T)): CervelloStore<T & { $value: Maybe<T> }> {\n const defaultValue = typeof initialValue === 'function' ? (initialValue as any)() : initialValue\n const store$$ = new BehaviorSubject<T>(defaultValue)\n\n // Object map to keep reference of nested object proxies created\n // to avoid problems with reference equality (i.e.: useEffect dependencies array)\n const proxiedNestedObjectMap: any = {}\n\n const proxiedStore = proxifyStore<T>(store$$, defaultValue, proxiedNestedObjectMap)\n\n const cervelloStore = {\n store: proxiedStore,\n reset () {\n if (!isEqualObject(store$$.getValue(), defaultValue)) {\n store$$.next(defaultValue)\n }\n },\n\n // TO BE SEPARATED IN cervello/react package ---------------------\n useStore: createUseStore<T>(store$$, proxiedNestedObjectMap),\n useSelector: createUseSelector<T>(store$$, proxiedNestedObjectMap),\n // ---------------------------------------------------------------\n\n use (...functionList: any) {\n functionList.forEach((func: any) => {\n func({\n onChange (cb: any) {\n store$$.subscribe((_) => cb(proxiedStore))\n },\n onPartialChange (attrs: Array<keyof T>, cb: any) {\n store$$.pipe(\n distinctUntilChanged((prev, curr) => {\n let isEqual = true\n attrs.forEach((selector) => {\n const currentPropertyValue = curr[selector]\n const prevPropertyValue = prev[selector]\n if (isEqual) {\n isEqual = typeof currentPropertyValue === 'object'\n ? isEqualObject(prevPropertyValue, currentPropertyValue)\n : prevPropertyValue === currentPropertyValue\n }\n })\n return isEqual\n }),\n ).subscribe((_) => cb(proxiedStore))\n },\n })\n })\n return this\n },\n } as any\n\n\n\n return cervelloStore as CervelloStore<T & { $value: Maybe<T> }>\n}\n"],"names":["obj","newObj","Array","isArray","map","item","deepClone","Object","keys","forEach","key","obj1","obj2","JSON","stringify","subscribeForReactHook","store$$","onStoreChange","subscription","subscribe","unsubscribe","nestedAttrs","Symbol","storeObject","proxiedNestedObjectMap","Error","get","target","prop","currentStore","getValue","valueByProp","bind","proxifyStore","nestedAttrsPrefix","currentNestedAttrs","cacheKey","isEqualObject","proxiedNestedObject","defineProperty","value","enumerable","writable","configurable","Reflect","set","_target$nestedAttrs","isNestedProp","Boolean","length","clonedStore","keyPath","assignNestedProperty","split","next","createUseStore","store","useSyncExternalStore","useMemo","createUseSelector","selectors","isEqualFunction","useSyncExternalStoreWithSelector","getPartialObjectFromAttributes","attributes","reduce","acc","curr","prev","cervello","initialValue","defaultValue","BehaviorSubject","proxiedStore","cervelloStore","reset","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","pipe","distinctUntilChanged","isEqual","selector","currentPropertyValue","prevPropertyValue","this"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cervello.umd.js","sources":["../src/lib/helpers/constants.ts","../src/lib/utils/object.ts","../src/lib/helpers/proxify-store.ts","../src/lib/helpers/create-store-selector-hook.ts","../src/lib/store/index.ts","../src/lib/utils/subject.ts"],"sourcesContent":["export const INTERNAL_VALUE_PROP = '$$value$$'\n","import { INTERNAL_VALUE_PROP } from '../helpers/constants'\n\n\n/**\n * Clones all the provided object and nested properties and it also\n * iterates nested arrays to deepClone them\n *\n * @param obj - base object to be cloned\n * @returns new cloned object with new reference\n */\nexport function deepClone <T> (obj: T): T {\n if (!obj || typeof obj !== 'object')\n return obj\n\n let newObj = {} as any\n if (Array.isArray(obj)) {\n newObj = obj.map(item => deepClone(item))\n } else {\n Object.entries(obj).forEach(([key, value]) => {\n newObj[key] = deepClone(value)\n })\n }\n return newObj as T\n}\n\n\n/**\n * Guard to check is variable is an object\n * @param obj - variable to be checked\n * @returns boolean\n */\nexport const isObject = (obj: unknown): obj is Record<string | symbol, unknown> => (\n obj !== null\n && typeof obj === 'object'\n && !Array.isArray(obj)\n)\n\n\n\n\n/**\n * Returns the actual target value instead of root\n * object with internals props like $$value$$\n *\n * @param target - object from subscription or proxy\n * @returns actual value\n */\nexport const okTarget = (target: any): any => target[INTERNAL_VALUE_PROP] ?? target\n\n\n\n\n/**\n * Gets an object with just the properties requested\n * instead of the full object\n *\n * @param properties - object properties\n * @param obj - target to get the properties\n * @returns New object with just the requested properties\n */\nexport function getPartialObjectFromProperties<T> (properties: Array<keyof T>, obj: T): any {\n return properties.reduce<any>((acc, curr) => {\n acc[curr] = obj[curr]\n return acc\n }, {})\n}\n\n\n\nconst stringify = (obj: any): string => JSON.stringify(obj)\n/**\n * Compare 2 provided objects by stringing them\n * @param a - first object\n * @param b - second object\n * @returns boolean\n */\nexport const contentComparer = (a: any, b: any): boolean => stringify(a) === stringify(b)\n","import { deepClone, isObject, okTarget } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nexport function proxifyStore <T> (store$$: CacheableSubject<T>, objectToProxify: T, proxiedNestedObjectMap: any, shouldProxifyNestedObj: boolean): T\n\nexport function proxifyStore <T extends Record<string | symbol, any>> (\n store$$: CacheableSubject<T>,\n objectToProxify: T,\n proxiedNestedObjectMap: any,\n shouldProxifyNestedObj: boolean,\n): T {\n if (typeof objectToProxify !== 'object') throw new Error('Store must be an object')\n\n /** Proxify object and push value to subject */\n return new Proxy(objectToProxify, {\n get (t, prop) {\n const target = okTarget(t)\n\n /**\n * Return actual object when toJSON\n * is called instead of $$value$$\n */\n if (prop === 'toJSON') return () => target\n\n const propertyValue = Reflect.get(target, prop)\n\n if (shouldProxifyNestedObj && isObject(propertyValue)) {\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[prop]\n if (cachedValue) return cachedValue\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n // const proxied = proxifyStore(store$$ as any, { $$value$$: propertyValue }, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[prop] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, value) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newValue = deepClone(value)\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newValue)\n store$$.next(newValue)\n return true\n }\n\n const target = okTarget(t)\n const propValue = Reflect.get(target, prop)\n\n /** If new value is the same as the current one */\n if (propValue === value) return true\n\n\n /** Set value to target reference */\n Reflect.set(target, prop, value)\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(propValue) && proxiedNestedObjectMap[prop]) {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n const proxied = proxifyStore(store$$ as any, value, proxiedNestedObjectMap, shouldProxifyNestedObj)\n proxiedNestedObjectMap[prop] = proxied\n }\n\n /** Push new store object (new reference for immutability) */\n store$$.next(Object.assign({}, store$$.getValue()))\n\n return true\n },\n\n\n\n\n has (t, p) {\n return Reflect.has(okTarget(t), p)\n },\n\n ownKeys (t) {\n return Reflect.ownKeys(okTarget(t))\n },\n\n getOwnPropertyDescriptor (t, p) {\n return Reflect.getOwnPropertyDescriptor(okTarget(t), p)\n },\n\n\n\n }) as any\n}\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { useRef } from 'react'\nimport { useSyncExternalStore } from 'use-sync-external-store/shim/index.js'\n\nimport { contentComparer, getPartialObjectFromProperties } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol('_isServer')\n\n\nexport function createStoreSelectorHook<T> (store$$: CacheableSubject<T>, proxiedStore: any, type: 'full' | 'slice'): UseSelector<T> {\n const serverInitialValue = Object.assign({}, (store$$.getValue() as any)[INTERNAL_VALUE_PROP], { [isServerSymbol]: true })\n\n\n // SELECTOR HOOK -------------------------------------------------\n const useStoreWithSelectors = <Attributes extends Array<keyof WithoutType<T, Function>>>(\n selectors: Attributes,\n isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean,\n ): ObjectFromAttributes<T, Attributes> => {\n const prevSlice = useRef< ObjectFromAttributes<T, Attributes> | null >(null)\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') return onStoreChange()\n\n const currentSlice = getPartialObjectFromProperties(selectors, v)\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n if (!isEquals) {\n prevSlice.current = currentSlice\n onStoreChange()\n }\n },\n })\n\n return () => { subscription.unsubscribe() }\n },\n () => store$$.getValue(),\n () => serverInitialValue,\n )\n\n\n const isServerStore = Object.getOwnPropertySymbols(store).includes(isServerSymbol)\n\n return isServerStore ? store : proxiedStore\n }\n\n return useStoreWithSelectors\n}\n","/* eslint-disable @typescript-eslint/ban-types */\nimport { createStoreSelectorHook, proxifyStore } from '../helpers'\nimport { INTERNAL_VALUE_PROP } from '../helpers/constants'\nimport {\n contentComparer,\n deepClone,\n getPartialObjectFromProperties,\n createCacheableSubject,\n okTarget,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ninterface CervelloStoreUseParam<StoreType> {\n onChange: (cb: (store: StoreType) => void) => void\n onPartialChange: <\n Attributes extends keyof WithoutType<StoreType, Function>,\n R extends Exclude<Attributes, '$value'>,\n ArrayOfAttributes extends Array <R>,\n > (selectors: ArrayOfAttributes, cb: (store: StoreType) => void) => void\n}\n\n/**\n * Use function which allows you to listen for changes in the store.\n */\nexport type CervelloUseFunction<StoreType> = (param: CervelloStoreUseParam<StoreType>) => void\n\n\ninterface CervelloStore<StoreType> {\n /** Reactive store */\n store: StoreType\n /** Hook to react to all changes done to 'store' */\n useStore: () => StoreType\n /** Hook to react to changes done to 'store' in all the attributes provided */\n useSelector: UseSelector<StoreType>\n /** Resets the value to the initial value passed in */\n reset: () => void\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType>\n}\n\n\nexport interface CervelloOptions {\n reactiveNestedObjects: boolean\n}\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Object with the default values for the store\n *\n * @returns - \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/**\n * Creates a store that is reactive and can be used inside and outside of React components.\n * @param initialValue - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\}\n */\nexport function cervello <T> (initialValue: () => T, options?: CervelloOptions): CervelloStore<T & { $value: Maybe<T> }>\n\n\n/** @internal */\nexport function cervello <T> (\n initialValue: T | (() => T),\n options: CervelloOptions = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }> {\n const defaultValue: T = typeof initialValue === 'function' ? (initialValue as any)() : initialValue\n\n\n const clonedInitialValue = { [INTERNAL_VALUE_PROP]: deepClone(defaultValue) } as any as T\n\n /**\n * Object map to keep reference of nested object proxies created\n * to avoid problems with reference equality (i.e.: useEffect dependencies array)\n */\n const proxiedNestedObjectMap: any = {}\n\n const store$$ = createCacheableSubject(clonedInitialValue, false) as any\n const proxiedStore = proxifyStore<T>(store$$, clonedInitialValue, proxiedNestedObjectMap, options.reactiveNestedObjects)\n\n const cervelloStore = {\n store: proxiedStore,\n reset () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n useStore: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n useSelector: createStoreSelectorHook<T>(store$$, proxiedStore, 'slice'),\n // --------------------------------------------------------------------------\n\n use (...functionList: any) {\n functionList.forEach((func: any) => {\n func({\n onChange (cb: any) {\n store$$.subscribe({ next: (_: any) => { cb(proxiedStore) } })\n },\n onPartialChange (attrs: Array<keyof T>, cb: any) {\n let prevSlice: any = getPartialObjectFromProperties(attrs, okTarget(clonedInitialValue))\n store$$.subscribe({\n next: (v: T) => {\n const target = okTarget(v)\n const currentSlice = getPartialObjectFromProperties(attrs, target)\n\n const isEquals = contentComparer(prevSlice, currentSlice)\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n return this\n },\n } as any\n\n\n\n return cervelloStore as CervelloStore<T & { $value: Maybe<T> }>\n}\n","\nexport type Noop = () => void\n\n\nexport interface Observer<T> {\n next: (value: T) => void\n}\n\nexport interface Subscription {\n unsubscribe: Noop\n}\n\nexport type CacheableSubject<T> = {\n getValue: () => T\n subscribe: (value: Observer<T>) => Subscription\n unSubscribeAll: Noop\n} & Observer<T>\n\n\n\nexport function createCacheableSubject<T> (defaultValue: T, getValueOnSubscribe = true): CacheableSubject<T> {\n let observerList: Array<Observer<T>> = []\n let value = defaultValue\n\n const getValue = (): T => value\n\n const next = (newValue: T): void => {\n value = newValue\n observerList.forEach((o) => { o.next(newValue) })\n }\n\n const subscribe = (observer: Observer<T>): Subscription => {\n // Push cached value on subscribe\n if (getValueOnSubscribe) observer.next(value)\n // Store the observer to be notified\n observerList.push(observer)\n return {\n unsubscribe: () => {\n observerList = observerList.filter(o => o !== observer)\n },\n }\n }\n\n const unSubscribeAll = (): void => {\n observerList = []\n }\n\n return {\n getValue,\n next,\n subscribe,\n unSubscribeAll,\n }\n}\n"],"names":["INTERNAL_VALUE_PROP","deepClone","obj","newObj","Array","isArray","map","item","Object","entries","forEach","_ref","okTarget","target","_target$INTERNAL_VALU","getPartialObjectFromProperties","properties","reduce","acc","curr","stringify","JSON","contentComparer","a","b","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","Reflect","isObject","cachedValue","proxied","set","value","hasOwn","isRootTarget","newValue","next","propValue","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","Symbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","cervello","initialValue","options","reactiveNestedObjects","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","o","observer","push","filter","unSubscribeAll","cervelloStore","reset","$value","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,37 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cervello/react",
|
|
3
|
-
"version": "0.12.2",
|
|
4
|
-
"description": "🤯 Simplest and truly reactive state manager for React",
|
|
5
|
-
"main": "./dist/cervello.cjs",
|
|
6
|
-
"module": "./dist/cervello.esm.js",
|
|
7
|
-
"unpkg": "./dist/cervello.umd.js",
|
|
8
3
|
"type": "module",
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"import": "./dist/cervello.esm.js",
|
|
15
|
-
"umd": "./dist/cervello.umd.js",
|
|
16
|
-
"require": "./dist/cervello.cjs",
|
|
17
|
-
"default": "./dist/cervello.modern.js"
|
|
18
|
-
},
|
|
19
|
-
"./types": {
|
|
20
|
-
"browser": "./types/index.d.ts",
|
|
21
|
-
"import": "./types/index.d.ts",
|
|
22
|
-
"require": "./types/index.d.ts",
|
|
23
|
-
"default": "./types/index.d.ts"
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
"files": [
|
|
27
|
-
"dist",
|
|
28
|
-
"types"
|
|
29
|
-
],
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "🤯 Simplest and truly reactive state manager for React",
|
|
6
|
+
"author": "Chempo",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/chempogonzalez/cervello#readme",
|
|
30
9
|
"repository": {
|
|
31
10
|
"type": "git",
|
|
32
11
|
"url": "git+https://github.com/chempogonzalez/cervello.git"
|
|
33
12
|
},
|
|
34
|
-
"
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/chempogonzalez/cervello/issues"
|
|
15
|
+
},
|
|
35
16
|
"keywords": [
|
|
36
17
|
"react",
|
|
37
18
|
"state",
|
|
@@ -44,28 +25,44 @@
|
|
|
44
25
|
"global",
|
|
45
26
|
"local"
|
|
46
27
|
],
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"browser": "./dist/cervello.esm.js",
|
|
32
|
+
"require": "./dist/cervello.cjs",
|
|
33
|
+
"import": "./dist/cervello.esm.js",
|
|
34
|
+
"umd": "./dist/cervello.umd.js",
|
|
35
|
+
"default": "./dist/cervello.modern.js"
|
|
36
|
+
},
|
|
37
|
+
"./types": {
|
|
38
|
+
"browser": "./types/index.d.ts",
|
|
39
|
+
"require": "./types/index.d.ts",
|
|
40
|
+
"import": "./types/index.d.ts",
|
|
41
|
+
"default": "./types/index.d.ts"
|
|
42
|
+
}
|
|
51
43
|
},
|
|
52
|
-
"
|
|
44
|
+
"main": "./dist/cervello.cjs",
|
|
45
|
+
"module": "./dist/cervello.esm.js",
|
|
46
|
+
"unpkg": "./dist/cervello.umd.js",
|
|
47
|
+
"source": "src/index.ts",
|
|
48
|
+
"types": "./types/index.d.ts",
|
|
49
|
+
"files": [
|
|
50
|
+
"dist",
|
|
51
|
+
"types"
|
|
52
|
+
],
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
|
55
|
-
"rxjs": ">= 7.4.0"
|
|
54
|
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
|
56
55
|
},
|
|
57
56
|
"dependencies": {
|
|
58
57
|
"use-sync-external-store": "^1.2.0"
|
|
59
58
|
},
|
|
60
59
|
"devDependencies": {
|
|
61
|
-
"@chempo/ec-linter": "^1.0.10",
|
|
62
60
|
"@testing-library/dom": "^8.17.1",
|
|
63
61
|
"@testing-library/react": "^13.3.0",
|
|
64
62
|
"@types/react": "18.0.18",
|
|
65
63
|
"@types/use-sync-external-store": "^0.0.3",
|
|
66
64
|
"microbundle": "0.15.1",
|
|
67
65
|
"react": "18.2.0",
|
|
68
|
-
"rxjs": "7.5.6",
|
|
69
66
|
"typescript": "4.8.2",
|
|
70
67
|
"vitest": "^0.23.1",
|
|
71
68
|
"vitest-react": "^0.9.5"
|
|
@@ -73,7 +70,8 @@
|
|
|
73
70
|
"scripts": {
|
|
74
71
|
"release": "pnpx bumpp --push=false && npm publish --access public",
|
|
75
72
|
"test": "vitest --watch",
|
|
76
|
-
"
|
|
73
|
+
"test:release": "vitest run",
|
|
74
|
+
"build": "(rm -rf types & rm -rf dist) && microbundle",
|
|
77
75
|
"dev": "microbundle watch"
|
|
78
76
|
}
|
|
79
77
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const INTERNAL_VALUE_PROP = "$$value$$";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function proxifyStore<T
|
|
1
|
+
import type { CacheableSubject } from '../utils/subject';
|
|
2
|
+
export declare function proxifyStore<T>(store$$: CacheableSubject<T>, objectToProxify: T, proxiedNestedObjectMap: any, shouldProxifyNestedObj: boolean): T;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type { Maybe, WithoutType } from '../../types/shared';
|
|
2
|
-
import type { UseSelector } from '../helpers';
|
|
1
|
+
import type { Maybe, UseSelector, WithoutType } from '../../types/shared';
|
|
3
2
|
interface CervelloStoreUseParam<StoreType> {
|
|
4
3
|
onChange: (cb: (store: StoreType) => void) => void;
|
|
5
|
-
onPartialChange: <Attributes extends
|
|
4
|
+
onPartialChange: <Attributes extends keyof WithoutType<StoreType, Function>, R extends Exclude<Attributes, '$value'>, ArrayOfAttributes extends Array<R>>(selectors: ArrayOfAttributes, cb: (store: StoreType) => void) => void;
|
|
6
5
|
}
|
|
7
6
|
/**
|
|
8
7
|
* Use function which allows you to listen for changes in the store.
|
|
@@ -20,22 +19,25 @@ interface CervelloStore<StoreType> {
|
|
|
20
19
|
/** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */
|
|
21
20
|
use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType>;
|
|
22
21
|
}
|
|
22
|
+
export interface CervelloOptions {
|
|
23
|
+
reactiveNestedObjects: boolean;
|
|
24
|
+
}
|
|
23
25
|
/**
|
|
24
26
|
* Creates a store that is reactive and can be used inside and outside of React components.
|
|
25
|
-
* @param initialValue Object with the default values for the store
|
|
27
|
+
* @param initialValue - Object with the default values for the store
|
|
26
28
|
*
|
|
27
|
-
* @returns - { store, useStore, useSelector }
|
|
29
|
+
* @returns - \{ store, useStore, useSelector \}
|
|
28
30
|
*/
|
|
29
|
-
export declare function cervello<T>(initialValue: T): CervelloStore<T & {
|
|
31
|
+
export declare function cervello<T>(initialValue: T, options?: CervelloOptions): CervelloStore<T & {
|
|
30
32
|
$value: Maybe<T>;
|
|
31
33
|
}>;
|
|
32
34
|
/**
|
|
33
35
|
* Creates a store that is reactive and can be used inside and outside of React components.
|
|
34
|
-
* @param initialValue Function which returns the default values for the store
|
|
36
|
+
* @param initialValue - Function which returns the default values for the store
|
|
35
37
|
*
|
|
36
|
-
* @returns
|
|
38
|
+
* @returns \{ store, useStore, useSelector \}
|
|
37
39
|
*/
|
|
38
|
-
export declare function cervello<T>(initialValue: () => T): CervelloStore<T & {
|
|
40
|
+
export declare function cervello<T>(initialValue: () => T, options?: CervelloOptions): CervelloStore<T & {
|
|
39
41
|
$value: Maybe<T>;
|
|
40
42
|
}>;
|
|
41
43
|
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from './object';
|
|
2
|
-
export * from './
|
|
2
|
+
export * from './subject';
|
|
@@ -1,2 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Clones all the provided object and nested properties and it also
|
|
3
|
+
* iterates nested arrays to deepClone them
|
|
4
|
+
*
|
|
5
|
+
* @param obj - base object to be cloned
|
|
6
|
+
* @returns new cloned object with new reference
|
|
7
|
+
*/
|
|
8
|
+
export declare function deepClone<T>(obj: T): T;
|
|
9
|
+
/**
|
|
10
|
+
* Guard to check is variable is an object
|
|
11
|
+
* @param obj - variable to be checked
|
|
12
|
+
* @returns boolean
|
|
13
|
+
*/
|
|
14
|
+
export declare const isObject: (obj: unknown) => obj is Record<string | symbol, unknown>;
|
|
15
|
+
/**
|
|
16
|
+
* Returns the actual target value instead of root
|
|
17
|
+
* object with internals props like $$value$$
|
|
18
|
+
*
|
|
19
|
+
* @param target - object from subscription or proxy
|
|
20
|
+
* @returns actual value
|
|
21
|
+
*/
|
|
22
|
+
export declare const okTarget: (target: any) => any;
|
|
23
|
+
/**
|
|
24
|
+
* Gets an object with just the properties requested
|
|
25
|
+
* instead of the full object
|
|
26
|
+
*
|
|
27
|
+
* @param properties - object properties
|
|
28
|
+
* @param obj - target to get the properties
|
|
29
|
+
* @returns New object with just the requested properties
|
|
30
|
+
*/
|
|
31
|
+
export declare function getPartialObjectFromProperties<T>(properties: Array<keyof T>, obj: T): any;
|
|
32
|
+
/**
|
|
33
|
+
* Compare 2 provided objects by stringing them
|
|
34
|
+
* @param a - first object
|
|
35
|
+
* @param b - second object
|
|
36
|
+
* @returns boolean
|
|
37
|
+
*/
|
|
38
|
+
export declare const contentComparer: (a: any, b: any) => boolean;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare type Noop = () => void;
|
|
2
|
+
export interface Observer<T> {
|
|
3
|
+
next: (value: T) => void;
|
|
4
|
+
}
|
|
5
|
+
export interface Subscription {
|
|
6
|
+
unsubscribe: Noop;
|
|
7
|
+
}
|
|
8
|
+
export declare type CacheableSubject<T> = {
|
|
9
|
+
getValue: () => T;
|
|
10
|
+
subscribe: (value: Observer<T>) => Subscription;
|
|
11
|
+
unSubscribeAll: Noop;
|
|
12
|
+
} & Observer<T>;
|
|
13
|
+
export declare function createCacheableSubject<T>(defaultValue: T, getValueOnSubscribe?: boolean): CacheableSubject<T>;
|
package/types/types/shared.d.ts
CHANGED
|
@@ -7,3 +7,4 @@ export declare type ObjectFromAttributes<T, Attributes extends Array<keyof Witho
|
|
|
7
7
|
[k in Attributes[number]]: T[k];
|
|
8
8
|
};
|
|
9
9
|
export declare type Maybe<T> = T | undefined;
|
|
10
|
+
export declare type UseSelector<T> = <Attributes extends Array<Exclude<keyof WithoutType<T, Function>, '$value'>>>(selectors: Attributes, isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean) => ObjectFromAttributes<T, Attributes>;
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { ObjectFromAttributes, WithoutType } from '../../types/shared';
|
|
2
|
-
import type { BehaviorSubject } from 'rxjs';
|
|
3
|
-
export declare function getPartialObjectFromAttributes<T>(attributes: Array<keyof T>, store: T): any;
|
|
4
|
-
export declare type UseSelector<T> = <Attributes extends Array<keyof WithoutType<T, Function>>>(selectors: Attributes, isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean) => ObjectFromAttributes<T, Attributes>;
|
|
5
|
-
export declare function createUseSelector<T>(store$$: BehaviorSubject<T>, proxiedNestedObjectMap: any): UseSelector<T>;
|