@cervello/react 1.2.0 β†’ 2.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 CHANGED
@@ -3,19 +3,15 @@
3
3
  [![npm version](https://img.shields.io/npm/v/@cervello/react?color=blue&style=flat-square)](https://www.npmjs.com/package/@cervello/react)
4
4
  [![bundle-size](https://img.shields.io/bundlephobia/minzip/@cervello/react/latest?color=orange&style=flat-square)](https://bundlephobia.com/package/@cervello/react@latest)
5
5
 
6
-
7
6
  <a href="https://www.cervello.dev">
8
7
  <img src="https://github.com/chempogonzalez/cervello/blob/main/assets/emoji-logo.png" style="display:block;">
9
8
  </a>
10
9
 
11
-
12
10
  > 🀯 Simplest and truly reactive state manager for React _(just 1.5kb)_
13
11
 
14
-
15
12
  <br>
16
13
  <br>
17
14
 
18
-
19
15
  <a href="https://www.cervello.dev">
20
16
  <p align="center">
21
17
  <strong>πŸ“– Documentation website</strong>
@@ -24,9 +20,9 @@
24
20
 
25
21
  <br>
26
22
 
27
-
28
23
  ## πŸš€ **Features**
29
- - βš›οΈ Truly reactive on store change like normal objects without functions **_(nested properties too!!)_**
24
+
25
+ - βš›οΈ Truly reactive on store change like normal objects without functions **_(nested properties too πŸš€!!)_**
30
26
  - βœ… Super simple and minimalistic API
31
27
  - 🐨 Listen properties lazily
32
28
  - πŸ‘Œ No unnecessary re-renders
@@ -34,21 +30,22 @@
34
30
  - πŸ”‘ Typescript support
35
31
 
36
32
  ## πŸ“¦ **Install**
33
+
37
34
  ```bash
38
35
  # NPM
39
36
  npm install @cervello/react
40
37
 
41
- # YARN
42
- yarn add @cervello/react
43
-
44
38
  # PNPM
45
39
  pnpm add @cervello/react
46
- ```
47
40
 
41
+ # YARN
42
+ yarn add @cervello/react
43
+ ```
48
44
 
49
45
  ## πŸ’» **Quick Usage**
46
+
50
47
  The `cervello` function allows you to create a new store in an easy way.
51
- Just set the initial value _`(the type will be inferred based on this value)`_ and you have it
48
+ Just set the initial value _`(the type will be inferred based on this value)`_ and you have it!
52
49
 
53
50
  ```ts
54
51
  // - store-example.ts
@@ -59,11 +56,15 @@ export const {
59
56
  useStore, // Hook to listen for store changes
60
57
  useSelector, // Hook to listen for changes on parts of the store
61
58
  reset, // Function to reset the store to initial value
62
- } = cervello({ count: 0 })
59
+ } = cervello({
60
+ count: 0,
61
+ isModalOpen: false,
62
+ /* ... */
63
+ })
63
64
 
64
65
 
65
66
  // With the store object you can use it outside of React components
66
- const increment = () => store.count++
67
+ const increment = () => { store.count++ }
67
68
 
68
69
 
69
70
  const Button = () => {
@@ -76,7 +77,7 @@ const Button = () => {
76
77
  }
77
78
 
78
79
  const ButtonWithSelector = () => {
79
- const { count } = useSelector(['count']) // Listen for changes just on count property
80
+ const { count } = useSelector(['count']) // Listen for changes just on 'count' property
80
81
  return (
81
82
  <button onClick={increment}>
82
83
  {count}
@@ -84,21 +85,16 @@ const ButtonWithSelector = () => {
84
85
  )
85
86
  }
86
87
  ```
88
+
87
89
  <br>
88
90
  <br>
89
91
 
90
-
91
92
  ---------
92
- ### To see more in depth explanations πŸ“– [Documentation website](https://www.cervello.dev)
93
+
94
+ ### To see more in depth explanations or API references and more examples: πŸ“– [Documentation website](https://www.cervello.dev)
95
+
93
96
  --------
94
97
 
95
98
  <br>
96
99
 
97
- ## πŸ€“ Happy Code
98
-
99
100
  > Created with Typescript! ⚑ and latin music 🎺🎡
100
-
101
- ### This README.md file has been written keeping in mind
102
-
103
- - [GitHub Markdown](https://guides.github.com/features/mastering-markdown/)
104
- - [Emoji Cheat Sheet](https://www.webfx.com/tools/emoji-cheat-sheet/)
package/dist/cervello.cjs CHANGED
@@ -1,2 +1,2 @@
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 o(e,n){return e.reduce(function(e,r){return e[r]=n[r],e},{})}var c=function(e){return JSON.stringify(e)},i=function(e,n){return c(e)===c(n)},f=Symbol.for("nestedPath");function a(e,n,o,c){if("object"!=typeof n)throw new Error("Store must be an object");return new Proxy(n,{get:function(n,r){var i=u(n);if("toJSON"===r)return function(){return i};var s=i[r];if(c&&t(s)&&"symbol"!=typeof r){var l=Object.hasOwn(n,"$$value$$")?r:i[f]+"."+r,v=o[l];if(v)return v;s[f]=l;var $=a(e,s,o,c);return o[l]=$,$}return s},set:function(n,i,s){var l=Object.hasOwn(n,"$$value$$");if("$value"===i&&l){var v,$=r(s);return o={},Reflect.set(n,"$$value$$",$),e.next(((v={}).$$value$$=$,v)),!0}var b=u(n);if(b[i]===s)return!0;if(c&&t(s)&&"symbol"!=typeof i){var y=l?i:b[f]+"."+i,h=r(s);h[f]=y;var O=a(e,h,o,c);Object.keys(o).forEach(function(e){e.startsWith(y)&&delete o[e]}),o[y]=O,b[i]=h}else b[i]=s;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 s=Symbol.for("_isServer");function l(r,t,u){var c,f=Object.assign({},r.getValue().$$value$$,((c={})[s]=!0,c));return function(c,a){var l=e.useRef(null),v=n.useSyncExternalStore(function(e){var n=r.subscribe({next:function(n){if("full"===u)return e();var r=o(c,null==n?void 0:n.$$value$$);(null!=a?a:i)(l.current,r)||(l.current=r,e())}});return function(){n.unsubscribe()}},function(){return r.getValue()},function(){return f});return Object.getOwnPropertySymbols(v).includes(s)?v:t}}exports.cervello=function(e,n){var t;void 0===n&&(n={reactiveNestedObjects:!0});var c="function"==typeof e?e():e,f=((t={}).$$value$$=r(c),t),s=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=[]}}}(f,!1),v=a(s,f,{},n.reactiveNestedObjects),$={store:v,reset:function(){v.$value=c},useStore:l(s,v,"full"),useSelector:l(s,v,"slice"),use:function(){return[].slice.call(arguments).forEach(function(e){e({onChange:function(e){s.subscribe({next:function(n){e(v)}})},onPartialChange:function(e,n){var t=o(e,u(f));s.subscribe({next:function(c){var f=u(c),a=o(e,f);i(t,a)||(n(v),t=r(a))}})}})}),this}};return $};
1
+ var e=require("react");function t(e){if(!e||"object"!=typeof e)return e;var r={};return Array.isArray(e)?r=e.map(function(e){return t(e)}):Object.entries(e).forEach(function(e){r[e[0]]=t(e[1])}),r}var r=function(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)},n=function(e){var t;return null!=(t=e.$$value$$)?t:e};function u(e,t){return e.reduce(function(e,r){return e[r]=t[r],e},{})}var o=function(e){return JSON.stringify(e)},c=function(e,t){return o(e)===o(t)};function i(e){return e.charAt(0).toUpperCase()+e.slice(1).toLocaleLowerCase()}"hasOwn"in Object||(Object.hasOwn=Object.call.bind(Object.hasOwnProperty));var a=Symbol.for("nestedPath");function s(e,u,o,c){if("object"!=typeof u)throw new Error("Store must be an object");return new Proxy(u,{get:function(t,u){var i=n(t);if("toJSON"===u)return function(){return i};var f=i[u];if(c&&r(f)&&"symbol"!=typeof u){var l=Object.hasOwn(t,"$$value$$")?u:i[a]+"."+u,v=o[l];if(v)return v;f[a]=l;var b=s(e,f,o,c);return o[l]=b,b}return f},set:function(u,i,f){var l=Object.hasOwn(u,"$$value$$");if("$value"===i&&l){var v,b=t(f);return o={},Reflect.set(u,"$$value$$",b),e.next(((v={}).$$value$$=b,v)),!0}var $=n(u);if($[i]===f)return!0;if(c&&r(f)&&"symbol"!=typeof i){var y=l?i:$[a]+"."+i,O=t(f);O[a]=y;var h=s(e,O,o,c);Object.keys(o).forEach(function(e){e.startsWith(y)&&delete o[e]}),o[y]=h,$[i]=O}else $[i]=f;return e.next(Object.assign({},e.getValue())),!0},has:function(e,t){return Reflect.has(n(e),t)},ownKeys:function(e){return Reflect.ownKeys(n(e))},getOwnPropertyDescriptor:function(e,t){return Reflect.getOwnPropertyDescriptor(n(e),t)}})}var f=Symbol.for("_isServer");function l(r,n,o){var i,a=Object.assign({},r.getValue().$$value$$,((i={})[f]=!0,i));return function(i,s){var l,v=e.useRef("full"===o?null:u(i,null==(l=r.getValue())?void 0:l.$$value$$)),b=e.useSyncExternalStore(function(e){var n=r.subscribe({next:function(r){if("full"!==o){var n=u(i,null==r?void 0:r.$$value$$);(null!=s?s:c)(v.current,n)||(v.current=t(n),e())}else e()}});return function(){n.unsubscribe()}},function(){return r.getValue()},function(){return a});return Object.getOwnPropertySymbols(b).includes(f)?b:n}}exports.cervello=function(e,r){var o,a;void 0===r&&(r={reactiveNestedObjects:!0});var f=r.name,v=r.reactiveNestedObjects,b=void 0===v||v;if(f&&!/^[a-z]+([A-Z][a-z]*)*$/.test(f))throw new Error('[cervello]: options.name must be in camelCase and "'+f+"\" doesn't respect this rule.");var $="function"==typeof e?e():e,y=((o={}).$$value$$=t($),o),O=function(e,t){void 0===t&&(t=!0);var r=[],n=e;return{getValue:function(){return n},next:function(e){n=e,r.forEach(function(t){t.next(e)})},subscribe:function(e){return t&&e.next(n),r.push(e),{unsubscribe:function(){r=r.filter(function(t){return t!==e})}}},unSubscribeAll:function(){r=[]}}}(y,!1),h=s(O,y,{},b),p=((a={})[f?f+"Store":"store"]=h,a[f?"reset"+i(f)+"Store":"reset"]=function(){h.$value=$},a[f?"use"+i(f)+"Store":"useStore"]=l(O,h,"full"),a[f?"use"+i(f)+"Selector":"useSelector"]=l(O,h,"slice"),a.use=function(){return[].slice.call(arguments).forEach(function(e){e({onChange:function(e){O.subscribe({next:function(t){e(h)}})},onPartialChange:function(e,r){var o=u(e,n(y));O.subscribe({next:function(i){var a=n(i),s=u(e,a);c(o,s)||(r(h),o=t(s))}})}})}),this},a);return p};
2
2
  //# sourceMappingURL=cervello.cjs.map
@@ -1 +1 @@
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","/* eslint-disable @typescript-eslint/restrict-template-expressions */\n/* eslint-disable @typescript-eslint/no-dynamic-delete */\nimport { deepClone, isObject, okTarget } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst nestedPath = Symbol.for('nestedPath')\n\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 = target[prop]\n\n if (shouldProxifyNestedObj && isObject(propertyValue) && typeof prop !== 'symbol') {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[propNestedPath]\n if (cachedValue) return cachedValue\n\n /** Set the nestedPath symbol to keep track of proxied */\n propertyValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, newValue) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newClonedValue = deepClone(newValue)\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newClonedValue)\n store$$.next({ [INTERNAL_VALUE_PROP]: newClonedValue } as unknown as T)\n return true\n }\n\n\n const target = okTarget(t)\n const propValue = target[prop]\n\n /** If new value is the same as the current one */\n if (propValue === newValue) return true\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(newValue) && typeof prop !== 'symbol') {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n const newClonedValue = deepClone(newValue)\n\n newClonedValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, newClonedValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n // Remove nested object props from cache\n // nestedPath: 'a.b.c': remove -> 'a.b.c.d' -> 'a.b.c.d.e'\n Object.keys(proxiedNestedObjectMap).forEach((cachedProxyKey: string) => {\n if (cachedProxyKey.startsWith(propNestedPath)) delete proxiedNestedObjectMap[cachedProxyKey]\n })\n\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n target[prop] = newClonedValue\n } else {\n target[prop] = newValue\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.for('_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 ): T => {\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 as any)?.[INTERNAL_VALUE_PROP])\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","nestedPath","Symbol","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","isObject","propNestedPath","hasOwn","cachedValue","proxied","set","newValue","isRootTarget","_store$$$next","newClonedValue","Reflect","next","INTERNAL_VALUE_PROP","_newClonedValue","keys","cachedProxyKey","startsWith","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","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","value","o","observer","push","filter","unSubscribeAll","cervelloStore","reset","$value","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
1
+ {"version":3,"file":"cervello.cjs","sources":["../src/lib/utils/object.ts","../src/lib/utils/string.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","\nexport function capitalize (str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1).toLocaleLowerCase()\n}\n\nexport function isCamelCase (str: string): boolean {\n const regex = /^[a-z]+([A-Z][a-z]*)*$/\n\n return regex.test(str)\n}\n","\n/* eslint-disable @typescript-eslint/no-dynamic-delete */\nimport { INTERNAL_VALUE_PROP } from './constants'\nimport { deepClone, isObject, okTarget } from '../utils'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n// @ts-expect-error - Object.hasOwn is not defined in older Safari's browsers\n('hasOwn' in Object) || (Object.hasOwn = Object.call.bind(Object.hasOwnProperty))\n\nconst nestedPath = Symbol.for('nestedPath')\n\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 = target[prop]\n\n if (shouldProxifyNestedObj && isObject(propertyValue) && typeof prop !== 'symbol') {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[propNestedPath]\n\n if (cachedValue) return cachedValue\n\n /** Set the nestedPath symbol to keep track of proxied */\n propertyValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, newValue) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newClonedValue = deepClone(newValue)\n\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newClonedValue)\n store$$.next({ [INTERNAL_VALUE_PROP]: newClonedValue } as unknown as T)\n\n return true\n }\n\n\n const target = okTarget(t)\n const propValue = target[prop]\n\n /** If new value is the same as the current one */\n if (propValue === newValue) return true\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(newValue) && typeof prop !== 'symbol') {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n const newClonedValue = deepClone(newValue)\n\n newClonedValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, newClonedValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n // Remove nested object props from cache\n // nestedPath: 'a.b.c': remove -> 'a.b.c.d' -> 'a.b.c.d.e'\n Object.keys(proxiedNestedObjectMap).forEach((cachedProxyKey: string) => {\n if (cachedProxyKey.startsWith(propNestedPath)) delete proxiedNestedObjectMap[cachedProxyKey]\n })\n\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n target[prop] = newClonedValue\n } else {\n target[prop] = newValue\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, useSyncExternalStore } from 'react'\n\nimport { INTERNAL_VALUE_PROP } from './constants'\nimport { contentComparer, deepClone, getPartialObjectFromProperties } from '../utils'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol.for('_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 ): T => {\n const prevSlice = useRef< ObjectFromAttributes<T, Attributes> | null >(\n type === 'full'\n ? null\n // To avoid the first render to be always different even\n // if store changed other than selected attributes\n : getPartialObjectFromProperties(selectors, (store$$.getValue() as any)?.[INTERNAL_VALUE_PROP]),\n )\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') {\n onStoreChange()\n\n return\n }\n\n // Partial store section ------------------------------------------------------------------\n const currentSlice = getPartialObjectFromProperties(selectors, (v as any)?.[INTERNAL_VALUE_PROP])\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n\n if (!isEquals) {\n /**\n * Update previous slice with deepClone to avoid storing direct store$$ value reference.\n * This solve reference/value problems when changing the store object\n * (proxy.set is changing the target object which is 'v' here)\n */\n prevSlice.current = deepClone(currentSlice)\n onStoreChange()\n }\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","\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 capitalize,\n isCamelCase,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ntype 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\ndeclare type Prettify<T> = {} & {\n [K in keyof T]: T[K];\n}\n\n\n\n\ntype CervelloStore<StoreType, StoreName extends string | undefined = undefined> =\n StoreName extends string\n ? Prettify<{\n // /** Reactive store */\n [K in `${StoreName}Store`]: StoreType\n }\n & {\n /** Hook to react to all changes done to 'store' */\n [K in `use${Capitalize<StoreName>}Store`]: () => StoreType\n }\n & {\n /** Hook to react to all changes done to 'store' */\n [K in `use${Capitalize<StoreName>}Selector`]: UseSelector<StoreType>\n }\n & {\n /** Resets the value to the initial value passed in */\n [K in `reset${Capitalize<StoreName>}Store`]: () => void\n }\n & {\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType, StoreName>\n }>\n :\n {\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, StoreName>\n }\n\n\nexport type CervelloOptions<StoreName extends string | undefined = undefined> = {\n name?: StoreName\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 - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\} or `{ exampleStore, useExampleStore, useExampleSelector }` if name is provided in options with 'example' value\n */\nexport function cervello <\nT,\nStoreName extends string | undefined = undefined,\n> (initialValue: () => T, options?: CervelloOptions<StoreName>): Prettify< CervelloStore<Prettify<T & { $value: Maybe<T> }>, StoreName> >\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 \\} or `{ exampleStore, useExampleStore, useExampleSelector }` if name is provided in options with 'example' value\n */\nexport function cervello <\nT extends Record<string, unknown>,\nStoreName extends string | undefined = undefined,\n> (initialValue: T, options?: CervelloOptions<StoreName>): Prettify< CervelloStore<Prettify<T & { $value: Maybe<T> }>, StoreName> >\n\n\n\n/** @internal */\nexport function cervello <T, StoreName extends string | undefined = undefined> (\n initialValue: T | (() => T),\n options: CervelloOptions<StoreName> = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }, StoreName> {\n const { name: optionsName, reactiveNestedObjects = true } = options\n\n if (optionsName && !isCamelCase(optionsName))\n throw new Error(`[cervello]: options.name must be in camelCase and \"${optionsName}\" doesn't respect this rule.`)\n\n\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, reactiveNestedObjects)\n\n const cervelloStore = {\n [optionsName\n ? `${optionsName}Store`\n : 'store'\n ]: proxiedStore,\n\n [optionsName\n ? `reset${capitalize(optionsName)}Store`\n : 'reset'\n ] () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n [optionsName\n ? `use${capitalize(optionsName)}Store`\n : 'useStore'\n ]: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n\n [optionsName\n ? `use${capitalize(optionsName)}Selector`\n : 'useSelector'\n ]: 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\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\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n\n return this\n },\n } as any\n\n\n\n return cervelloStore\n}\n","\nexport type Noop = () => void\n\n\nexport type Observer<T> = {\n next: (value: T) => void\n}\n\nexport type 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\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","str","charAt","toUpperCase","slice","toLocaleLowerCase","hasOwn","call","bind","hasOwnProperty","nestedPath","Symbol","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","isObject","propNestedPath","cachedValue","proxied","set","newValue","isRootTarget","_store$$$next","newClonedValue","Reflect","next","keys","cachedProxyKey","startsWith","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","_store$$$getValue","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","initialValue","options","reactiveNestedObjects","optionsName","name","_options$reactiveNest","test","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","value","o","observer","push","filter","unSubscribeAll","cervelloStore","capitalize","$value","_cervelloStore","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{useRef as e}from"react";import{useSyncExternalStore as n}from"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 o(e,n){return e.reduce(function(e,r){return e[r]=n[r],e},{})}var c=function(e){return JSON.stringify(e)},i=function(e,n){return c(e)===c(n)},f=Symbol.for("nestedPath");function a(e,n,o,c){if("object"!=typeof n)throw new Error("Store must be an object");return new Proxy(n,{get:function(n,r){var i=u(n);if("toJSON"===r)return function(){return i};var s=i[r];if(c&&t(s)&&"symbol"!=typeof r){var l=Object.hasOwn(n,"$$value$$")?r:i[f]+"."+r,v=o[l];if(v)return v;s[f]=l;var $=a(e,s,o,c);return o[l]=$,$}return s},set:function(n,i,s){var l=Object.hasOwn(n,"$$value$$");if("$value"===i&&l){var v,$=r(s);return o={},Reflect.set(n,"$$value$$",$),e.next(((v={}).$$value$$=$,v)),!0}var b=u(n);if(b[i]===s)return!0;if(c&&t(s)&&"symbol"!=typeof i){var y=l?i:b[f]+"."+i,h=r(s);h[f]=y;var p=a(e,h,o,c);Object.keys(o).forEach(function(e){e.startsWith(y)&&delete o[e]}),o[y]=p,b[i]=h}else b[i]=s;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 s=Symbol.for("_isServer");function l(r,t,u){var c,f=Object.assign({},r.getValue().$$value$$,((c={})[s]=!0,c));return function(c,a){var l=e(null),v=n(function(e){var n=r.subscribe({next:function(n){if("full"===u)return e();var r=o(c,null==n?void 0:n.$$value$$);(null!=a?a:i)(l.current,r)||(l.current=r,e())}});return function(){n.unsubscribe()}},function(){return r.getValue()},function(){return f});return Object.getOwnPropertySymbols(v).includes(s)?v:t}}function v(e,n){var t;void 0===n&&(n={reactiveNestedObjects:!0});var c="function"==typeof e?e():e,f=((t={}).$$value$$=r(c),t),s=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=[]}}}(f,!1),v=a(s,f,{},n.reactiveNestedObjects),$={store:v,reset:function(){v.$value=c},useStore:l(s,v,"full"),useSelector:l(s,v,"slice"),use:function(){return[].slice.call(arguments).forEach(function(e){e({onChange:function(e){s.subscribe({next:function(n){e(v)}})},onPartialChange:function(e,n){var t=o(e,u(f));s.subscribe({next:function(c){var f=u(c),a=o(e,f);i(t,a)||(n(v),t=r(a))}})}})}),this}};return $}export{v as cervello};
1
+ import{useRef as e,useSyncExternalStore as t}from"react";function n(e){if(!e||"object"!=typeof e)return e;var t={};return Array.isArray(e)?t=e.map(function(e){return n(e)}):Object.entries(e).forEach(function(e){t[e[0]]=n(e[1])}),t}var r=function(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)},u=function(e){var t;return null!=(t=e.$$value$$)?t:e};function o(e,t){return e.reduce(function(e,n){return e[n]=t[n],e},{})}var c=function(e){return JSON.stringify(e)},i=function(e,t){return c(e)===c(t)};function a(e){return e.charAt(0).toUpperCase()+e.slice(1).toLocaleLowerCase()}"hasOwn"in Object||(Object.hasOwn=Object.call.bind(Object.hasOwnProperty));var f=Symbol.for("nestedPath");function s(e,t,o,c){if("object"!=typeof t)throw new Error("Store must be an object");return new Proxy(t,{get:function(t,n){var i=u(t);if("toJSON"===n)return function(){return i};var a=i[n];if(c&&r(a)&&"symbol"!=typeof n){var l=Object.hasOwn(t,"$$value$$")?n:i[f]+"."+n,v=o[l];if(v)return v;a[f]=l;var b=s(e,a,o,c);return o[l]=b,b}return a},set:function(t,i,a){var l=Object.hasOwn(t,"$$value$$");if("$value"===i&&l){var v,b=n(a);return o={},Reflect.set(t,"$$value$$",b),e.next(((v={}).$$value$$=b,v)),!0}var $=u(t);if($[i]===a)return!0;if(c&&r(a)&&"symbol"!=typeof i){var y=l?i:$[f]+"."+i,O=n(a);O[f]=y;var h=s(e,O,o,c);Object.keys(o).forEach(function(e){e.startsWith(y)&&delete o[e]}),o[y]=h,$[i]=O}else $[i]=a;return e.next(Object.assign({},e.getValue())),!0},has:function(e,t){return Reflect.has(u(e),t)},ownKeys:function(e){return Reflect.ownKeys(u(e))},getOwnPropertyDescriptor:function(e,t){return Reflect.getOwnPropertyDescriptor(u(e),t)}})}var l=Symbol.for("_isServer");function v(r,u,c){var a,f=Object.assign({},r.getValue().$$value$$,((a={})[l]=!0,a));return function(a,s){var v,b=e("full"===c?null:o(a,null==(v=r.getValue())?void 0:v.$$value$$)),$=t(function(e){var t=r.subscribe({next:function(t){if("full"!==c){var r=o(a,null==t?void 0:t.$$value$$);(null!=s?s:i)(b.current,r)||(b.current=n(r),e())}else e()}});return function(){t.unsubscribe()}},function(){return r.getValue()},function(){return f});return Object.getOwnPropertySymbols($).includes(l)?$:u}}function b(e,t){var r,c;void 0===t&&(t={reactiveNestedObjects:!0});var f=t.name,l=t.reactiveNestedObjects,b=void 0===l||l;if(f&&!/^[a-z]+([A-Z][a-z]*)*$/.test(f))throw new Error('[cervello]: options.name must be in camelCase and "'+f+"\" doesn't respect this rule.");var $="function"==typeof e?e():e,y=((r={}).$$value$$=n($),r),O=function(e,t){void 0===t&&(t=!0);var n=[],r=e;return{getValue:function(){return r},next:function(e){r=e,n.forEach(function(t){t.next(e)})},subscribe:function(e){return t&&e.next(r),n.push(e),{unsubscribe:function(){n=n.filter(function(t){return t!==e})}}},unSubscribeAll:function(){n=[]}}}(y,!1),h=s(O,y,{},b),p=((c={})[f?f+"Store":"store"]=h,c[f?"reset"+a(f)+"Store":"reset"]=function(){h.$value=$},c[f?"use"+a(f)+"Store":"useStore"]=v(O,h,"full"),c[f?"use"+a(f)+"Selector":"useSelector"]=v(O,h,"slice"),c.use=function(){return[].slice.call(arguments).forEach(function(e){e({onChange:function(e){O.subscribe({next:function(t){e(h)}})},onPartialChange:function(e,t){var r=o(e,u(y));O.subscribe({next:function(c){var a=u(c),f=o(e,a);i(r,f)||(t(h),r=n(f))}})}})}),this},c);return p}export{b as cervello};
2
2
  //# sourceMappingURL=cervello.esm.js.map
@@ -1 +1 @@
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","/* eslint-disable @typescript-eslint/restrict-template-expressions */\n/* eslint-disable @typescript-eslint/no-dynamic-delete */\nimport { deepClone, isObject, okTarget } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst nestedPath = Symbol.for('nestedPath')\n\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 = target[prop]\n\n if (shouldProxifyNestedObj && isObject(propertyValue) && typeof prop !== 'symbol') {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[propNestedPath]\n if (cachedValue) return cachedValue\n\n /** Set the nestedPath symbol to keep track of proxied */\n propertyValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, newValue) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newClonedValue = deepClone(newValue)\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newClonedValue)\n store$$.next({ [INTERNAL_VALUE_PROP]: newClonedValue } as unknown as T)\n return true\n }\n\n\n const target = okTarget(t)\n const propValue = target[prop]\n\n /** If new value is the same as the current one */\n if (propValue === newValue) return true\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(newValue) && typeof prop !== 'symbol') {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n const newClonedValue = deepClone(newValue)\n\n newClonedValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, newClonedValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n // Remove nested object props from cache\n // nestedPath: 'a.b.c': remove -> 'a.b.c.d' -> 'a.b.c.d.e'\n Object.keys(proxiedNestedObjectMap).forEach((cachedProxyKey: string) => {\n if (cachedProxyKey.startsWith(propNestedPath)) delete proxiedNestedObjectMap[cachedProxyKey]\n })\n\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n target[prop] = newClonedValue\n } else {\n target[prop] = newValue\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.for('_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 ): T => {\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 as any)?.[INTERNAL_VALUE_PROP])\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","nestedPath","Symbol","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","isObject","propNestedPath","hasOwn","cachedValue","proxied","set","newValue","isRootTarget","_store$$$next","newClonedValue","Reflect","next","INTERNAL_VALUE_PROP","_newClonedValue","keys","cachedProxyKey","startsWith","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","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","value","o","observer","push","filter","unSubscribeAll","cervelloStore","reset","$value","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
1
+ {"version":3,"file":"cervello.esm.js","sources":["../src/lib/utils/object.ts","../src/lib/utils/string.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","\nexport function capitalize (str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1).toLocaleLowerCase()\n}\n\nexport function isCamelCase (str: string): boolean {\n const regex = /^[a-z]+([A-Z][a-z]*)*$/\n\n return regex.test(str)\n}\n","\n/* eslint-disable @typescript-eslint/no-dynamic-delete */\nimport { INTERNAL_VALUE_PROP } from './constants'\nimport { deepClone, isObject, okTarget } from '../utils'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n// @ts-expect-error - Object.hasOwn is not defined in older Safari's browsers\n('hasOwn' in Object) || (Object.hasOwn = Object.call.bind(Object.hasOwnProperty))\n\nconst nestedPath = Symbol.for('nestedPath')\n\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 = target[prop]\n\n if (shouldProxifyNestedObj && isObject(propertyValue) && typeof prop !== 'symbol') {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[propNestedPath]\n\n if (cachedValue) return cachedValue\n\n /** Set the nestedPath symbol to keep track of proxied */\n propertyValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, newValue) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newClonedValue = deepClone(newValue)\n\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newClonedValue)\n store$$.next({ [INTERNAL_VALUE_PROP]: newClonedValue } as unknown as T)\n\n return true\n }\n\n\n const target = okTarget(t)\n const propValue = target[prop]\n\n /** If new value is the same as the current one */\n if (propValue === newValue) return true\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(newValue) && typeof prop !== 'symbol') {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n const newClonedValue = deepClone(newValue)\n\n newClonedValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, newClonedValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n // Remove nested object props from cache\n // nestedPath: 'a.b.c': remove -> 'a.b.c.d' -> 'a.b.c.d.e'\n Object.keys(proxiedNestedObjectMap).forEach((cachedProxyKey: string) => {\n if (cachedProxyKey.startsWith(propNestedPath)) delete proxiedNestedObjectMap[cachedProxyKey]\n })\n\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n target[prop] = newClonedValue\n } else {\n target[prop] = newValue\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, useSyncExternalStore } from 'react'\n\nimport { INTERNAL_VALUE_PROP } from './constants'\nimport { contentComparer, deepClone, getPartialObjectFromProperties } from '../utils'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol.for('_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 ): T => {\n const prevSlice = useRef< ObjectFromAttributes<T, Attributes> | null >(\n type === 'full'\n ? null\n // To avoid the first render to be always different even\n // if store changed other than selected attributes\n : getPartialObjectFromProperties(selectors, (store$$.getValue() as any)?.[INTERNAL_VALUE_PROP]),\n )\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') {\n onStoreChange()\n\n return\n }\n\n // Partial store section ------------------------------------------------------------------\n const currentSlice = getPartialObjectFromProperties(selectors, (v as any)?.[INTERNAL_VALUE_PROP])\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n\n if (!isEquals) {\n /**\n * Update previous slice with deepClone to avoid storing direct store$$ value reference.\n * This solve reference/value problems when changing the store object\n * (proxy.set is changing the target object which is 'v' here)\n */\n prevSlice.current = deepClone(currentSlice)\n onStoreChange()\n }\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","\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 capitalize,\n isCamelCase,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ntype 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\ndeclare type Prettify<T> = {} & {\n [K in keyof T]: T[K];\n}\n\n\n\n\ntype CervelloStore<StoreType, StoreName extends string | undefined = undefined> =\n StoreName extends string\n ? Prettify<{\n // /** Reactive store */\n [K in `${StoreName}Store`]: StoreType\n }\n & {\n /** Hook to react to all changes done to 'store' */\n [K in `use${Capitalize<StoreName>}Store`]: () => StoreType\n }\n & {\n /** Hook to react to all changes done to 'store' */\n [K in `use${Capitalize<StoreName>}Selector`]: UseSelector<StoreType>\n }\n & {\n /** Resets the value to the initial value passed in */\n [K in `reset${Capitalize<StoreName>}Store`]: () => void\n }\n & {\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType, StoreName>\n }>\n :\n {\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, StoreName>\n }\n\n\nexport type CervelloOptions<StoreName extends string | undefined = undefined> = {\n name?: StoreName\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 - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\} or `{ exampleStore, useExampleStore, useExampleSelector }` if name is provided in options with 'example' value\n */\nexport function cervello <\nT,\nStoreName extends string | undefined = undefined,\n> (initialValue: () => T, options?: CervelloOptions<StoreName>): Prettify< CervelloStore<Prettify<T & { $value: Maybe<T> }>, StoreName> >\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 \\} or `{ exampleStore, useExampleStore, useExampleSelector }` if name is provided in options with 'example' value\n */\nexport function cervello <\nT extends Record<string, unknown>,\nStoreName extends string | undefined = undefined,\n> (initialValue: T, options?: CervelloOptions<StoreName>): Prettify< CervelloStore<Prettify<T & { $value: Maybe<T> }>, StoreName> >\n\n\n\n/** @internal */\nexport function cervello <T, StoreName extends string | undefined = undefined> (\n initialValue: T | (() => T),\n options: CervelloOptions<StoreName> = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }, StoreName> {\n const { name: optionsName, reactiveNestedObjects = true } = options\n\n if (optionsName && !isCamelCase(optionsName))\n throw new Error(`[cervello]: options.name must be in camelCase and \"${optionsName}\" doesn't respect this rule.`)\n\n\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, reactiveNestedObjects)\n\n const cervelloStore = {\n [optionsName\n ? `${optionsName}Store`\n : 'store'\n ]: proxiedStore,\n\n [optionsName\n ? `reset${capitalize(optionsName)}Store`\n : 'reset'\n ] () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n [optionsName\n ? `use${capitalize(optionsName)}Store`\n : 'useStore'\n ]: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n\n [optionsName\n ? `use${capitalize(optionsName)}Selector`\n : 'useSelector'\n ]: 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\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\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n\n return this\n },\n } as any\n\n\n\n return cervelloStore\n}\n","\nexport type Noop = () => void\n\n\nexport type Observer<T> = {\n next: (value: T) => void\n}\n\nexport type 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\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","str","charAt","toUpperCase","slice","toLocaleLowerCase","hasOwn","call","bind","hasOwnProperty","nestedPath","Symbol","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","isObject","propNestedPath","cachedValue","proxied","set","newValue","isRootTarget","_store$$$next","newClonedValue","Reflect","next","keys","cachedProxyKey","startsWith","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","_store$$$getValue","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","initialValue","options","reactiveNestedObjects","optionsName","name","_options$reactiveNest","test","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","value","o","observer","push","filter","unSubscribeAll","cervelloStore","capitalize","$value","_cervelloStore","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
@@ -1,2 +1,2 @@
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 o=function(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)},i=function(e){var n;return null!=(n=e.$$value$$)?n:e};function c(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)},a=Symbol.for("nestedPath");function l(e,n,t,c){if("object"!=typeof n)throw new Error("Store must be an object");return new Proxy(n,{get:function(n,u){var f=i(n);if("toJSON"===u)return function(){return f};var s=f[u];if(c&&o(s)&&"symbol"!=typeof u){var v=Object.hasOwn(n,r)?u:f[a]+"."+u,b=t[v];if(b)return b;s[a]=v;var y=l(e,s,t,c);return t[v]=y,y}return s},set:function(n,f,s){var v=Object.hasOwn(n,r);if("$value"===f&&v){var b,y=u(s);return t={},Reflect.set(n,r,y),e.next(((b={}).$$value$$=y,b)),!0}var $=i(n);if($[f]===s)return!0;if(c&&o(s)&&"symbol"!=typeof f){var d=v?f:$[a]+"."+f,h=u(s);h[a]=d;var p=l(e,h,t,c);Object.keys(t).forEach(function(e){e.startsWith(d)&&delete t[e]}),t[d]=p,$[f]=h}else $[f]=s;return e.next(Object.assign({},e.getValue())),!0},has:function(e,n){return Reflect.has(i(e),n)},ownKeys:function(e){return Reflect.ownKeys(i(e))},getOwnPropertyDescriptor:function(e,n){return Reflect.getOwnPropertyDescriptor(i(e),n)}})}var v=Symbol.for("_isServer");function b(e,r,u){var o,i=Object.assign({},e.getValue().$$value$$,((o={})[v]=!0,o));return function(o,f){var a=n.useRef(null),l=t.useSyncExternalStore(function(n){var t=e.subscribe({next:function(e){if("full"===u)return n();var t=c(o,null==e?void 0:e.$$value$$);(null!=f?f:s)(a.current,t)||(a.current=t,n())}});return function(){t.unsubscribe()}},function(){return e.getValue()},function(){return i});return Object.getOwnPropertySymbols(l).includes(v)?l:r}}e.cervello=function(e,n){var t;void 0===n&&(n={reactiveNestedObjects:!0});var r="function"==typeof e?e():e,o=((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=[]}}}(o,!1),a=l(f,o,{},n.reactiveNestedObjects),v={store:a,reset:function(){a.$value=r},useStore:b(f,a,"full"),useSelector:b(f,a,"slice"),use:function(){return[].slice.call(arguments).forEach(function(e){e({onChange:function(e){f.subscribe({next:function(n){e(a)}})},onPartialChange:function(e,n){var t=c(e,i(o));f.subscribe({next:function(r){var o=i(r),f=c(e,o);s(t,f)||(n(a),t=u(f))}})}})}),this}};return v}});
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e||self).react={},e.react)}(this,function(e,t){var n="$$value$$";function r(e){if(!e||"object"!=typeof e)return e;var t={};return Array.isArray(e)?t=e.map(function(e){return r(e)}):Object.entries(e).forEach(function(e){t[e[0]]=r(e[1])}),t}var u=function(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)},o=function(e){var t;return null!=(t=e.$$value$$)?t:e};function c(e,t){return e.reduce(function(e,n){return e[n]=t[n],e},{})}var i=function(e){return JSON.stringify(e)},a=function(e,t){return i(e)===i(t)};function f(e){return e.charAt(0).toUpperCase()+e.slice(1).toLocaleLowerCase()}"hasOwn"in Object||(Object.hasOwn=Object.call.bind(Object.hasOwnProperty));var s=Symbol.for("nestedPath");function l(e,t,c,i){if("object"!=typeof t)throw new Error("Store must be an object");return new Proxy(t,{get:function(t,r){var a=o(t);if("toJSON"===r)return function(){return a};var f=a[r];if(i&&u(f)&&"symbol"!=typeof r){var v=Object.hasOwn(t,n)?r:a[s]+"."+r,b=c[v];if(b)return b;f[s]=v;var $=l(e,f,c,i);return c[v]=$,$}return f},set:function(t,a,f){var v=Object.hasOwn(t,n);if("$value"===a&&v){var b,$=r(f);return c={},Reflect.set(t,n,$),e.next(((b={}).$$value$$=$,b)),!0}var y=o(t);if(y[a]===f)return!0;if(i&&u(f)&&"symbol"!=typeof a){var p=v?a:y[s]+"."+a,h=r(f);h[s]=p;var d=l(e,h,c,i);Object.keys(c).forEach(function(e){e.startsWith(p)&&delete c[e]}),c[p]=d,y[a]=h}else y[a]=f;return e.next(Object.assign({},e.getValue())),!0},has:function(e,t){return Reflect.has(o(e),t)},ownKeys:function(e){return Reflect.ownKeys(o(e))},getOwnPropertyDescriptor:function(e,t){return Reflect.getOwnPropertyDescriptor(o(e),t)}})}var v=Symbol.for("_isServer");function b(e,n,u){var o,i=Object.assign({},e.getValue().$$value$$,((o={})[v]=!0,o));return function(o,f){var s,l=t.useRef("full"===u?null:c(o,null==(s=e.getValue())?void 0:s.$$value$$)),b=t.useSyncExternalStore(function(t){var n=e.subscribe({next:function(e){if("full"!==u){var n=c(o,null==e?void 0:e.$$value$$);(null!=f?f:a)(l.current,n)||(l.current=r(n),t())}else t()}});return function(){n.unsubscribe()}},function(){return e.getValue()},function(){return i});return Object.getOwnPropertySymbols(b).includes(v)?b:n}}e.cervello=function(e,t){var n,u;void 0===t&&(t={reactiveNestedObjects:!0});var i=t.name,s=t.reactiveNestedObjects,v=void 0===s||s;if(i&&!/^[a-z]+([A-Z][a-z]*)*$/.test(i))throw new Error('[cervello]: options.name must be in camelCase and "'+i+"\" doesn't respect this rule.");var $="function"==typeof e?e():e,y=((n={}).$$value$$=r($),n),p=function(e,t){void 0===t&&(t=!0);var n=[],r=e;return{getValue:function(){return r},next:function(e){r=e,n.forEach(function(t){t.next(e)})},subscribe:function(e){return t&&e.next(r),n.push(e),{unsubscribe:function(){n=n.filter(function(t){return t!==e})}}},unSubscribeAll:function(){n=[]}}}(y,!1),h=l(p,y,{},v),d=((u={})[i?i+"Store":"store"]=h,u[i?"reset"+f(i)+"Store":"reset"]=function(){h.$value=$},u[i?"use"+f(i)+"Store":"useStore"]=b(p,h,"full"),u[i?"use"+f(i)+"Selector":"useSelector"]=b(p,h,"slice"),u.use=function(){return[].slice.call(arguments).forEach(function(e){e({onChange:function(e){p.subscribe({next:function(t){e(h)}})},onPartialChange:function(e,t){var n=c(e,o(y));p.subscribe({next:function(u){var i=o(u),f=c(e,i);a(n,f)||(t(h),n=r(f))}})}})}),this},u);return d}});
2
2
  //# sourceMappingURL=cervello.umd.js.map
@@ -1 +1 @@
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","/* eslint-disable @typescript-eslint/restrict-template-expressions */\n/* eslint-disable @typescript-eslint/no-dynamic-delete */\nimport { deepClone, isObject, okTarget } from '../utils'\nimport { INTERNAL_VALUE_PROP } from './constants'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst nestedPath = Symbol.for('nestedPath')\n\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 = target[prop]\n\n if (shouldProxifyNestedObj && isObject(propertyValue) && typeof prop !== 'symbol') {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[propNestedPath]\n if (cachedValue) return cachedValue\n\n /** Set the nestedPath symbol to keep track of proxied */\n propertyValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, newValue) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newClonedValue = deepClone(newValue)\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newClonedValue)\n store$$.next({ [INTERNAL_VALUE_PROP]: newClonedValue } as unknown as T)\n return true\n }\n\n\n const target = okTarget(t)\n const propValue = target[prop]\n\n /** If new value is the same as the current one */\n if (propValue === newValue) return true\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(newValue) && typeof prop !== 'symbol') {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n const newClonedValue = deepClone(newValue)\n\n newClonedValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, newClonedValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n // Remove nested object props from cache\n // nestedPath: 'a.b.c': remove -> 'a.b.c.d' -> 'a.b.c.d.e'\n Object.keys(proxiedNestedObjectMap).forEach((cachedProxyKey: string) => {\n if (cachedProxyKey.startsWith(propNestedPath)) delete proxiedNestedObjectMap[cachedProxyKey]\n })\n\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n target[prop] = newClonedValue\n } else {\n target[prop] = newValue\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.for('_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 ): T => {\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 as any)?.[INTERNAL_VALUE_PROP])\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","nestedPath","Symbol","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","isObject","propNestedPath","hasOwn","cachedValue","proxied","set","newValue","isRootTarget","_store$$$next","newClonedValue","Reflect","next","_newClonedValue","keys","cachedProxyKey","startsWith","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","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","value","o","observer","push","filter","unSubscribeAll","cervelloStore","reset","$value","useStore","useSelector","use","func","onChange","cb","_","onPartialChange","attrs","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/utils/string.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","\nexport function capitalize (str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1).toLocaleLowerCase()\n}\n\nexport function isCamelCase (str: string): boolean {\n const regex = /^[a-z]+([A-Z][a-z]*)*$/\n\n return regex.test(str)\n}\n","\n/* eslint-disable @typescript-eslint/no-dynamic-delete */\nimport { INTERNAL_VALUE_PROP } from './constants'\nimport { deepClone, isObject, okTarget } from '../utils'\n\nimport type { CacheableSubject } from '../utils/subject'\n\n\n// @ts-expect-error - Object.hasOwn is not defined in older Safari's browsers\n('hasOwn' in Object) || (Object.hasOwn = Object.call.bind(Object.hasOwnProperty))\n\nconst nestedPath = Symbol.for('nestedPath')\n\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 = target[prop]\n\n if (shouldProxifyNestedObj && isObject(propertyValue) && typeof prop !== 'symbol') {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n\n /** Check if cached to return instead of re-create new proxy */\n const cachedValue = proxiedNestedObjectMap[propNestedPath]\n\n if (cachedValue) return cachedValue\n\n /** Set the nestedPath symbol to keep track of proxied */\n propertyValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, propertyValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n\n /** Store in cache the proxiedObject */\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n return proxied\n }\n\n\n return propertyValue\n },\n\n\n\n set (t, prop, newValue) {\n const isRootTarget = Object.hasOwn(t, INTERNAL_VALUE_PROP)\n\n /** Reset store */\n if (prop === '$value' && isRootTarget) {\n const newClonedValue = deepClone(newValue)\n\n proxiedNestedObjectMap = {}\n Reflect.set(t, INTERNAL_VALUE_PROP, newClonedValue)\n store$$.next({ [INTERNAL_VALUE_PROP]: newClonedValue } as unknown as T)\n\n return true\n }\n\n\n const target = okTarget(t)\n const propValue = target[prop]\n\n /** If new value is the same as the current one */\n if (propValue === newValue) return true\n\n /**\n * Override nested proxied object in\n * cache proxying the new value passed in\n */\n if (shouldProxifyNestedObj && isObject(newValue) && typeof prop !== 'symbol') {\n // TODO: check if --- proxiedNestedObjectMap[prop].$value = value --- is possible instead of recreating new nested\n // proxiedNestedObjectMap[prop].$value = value\n\n const propNestedPath = isRootTarget ? prop : `${target[nestedPath]}.${prop}`\n const newClonedValue = deepClone(newValue)\n\n newClonedValue[nestedPath] = propNestedPath\n\n const proxied = proxifyStore(store$$ as any, newClonedValue, proxiedNestedObjectMap, shouldProxifyNestedObj)\n\n // Remove nested object props from cache\n // nestedPath: 'a.b.c': remove -> 'a.b.c.d' -> 'a.b.c.d.e'\n Object.keys(proxiedNestedObjectMap).forEach((cachedProxyKey: string) => {\n if (cachedProxyKey.startsWith(propNestedPath)) delete proxiedNestedObjectMap[cachedProxyKey]\n })\n\n proxiedNestedObjectMap[propNestedPath] = proxied\n\n target[prop] = newClonedValue\n } else {\n target[prop] = newValue\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, useSyncExternalStore } from 'react'\n\nimport { INTERNAL_VALUE_PROP } from './constants'\nimport { contentComparer, deepClone, getPartialObjectFromProperties } from '../utils'\n\nimport type { ObjectFromAttributes, UseSelector, WithoutType } from '../../types/shared'\nimport type { CacheableSubject } from '../utils/subject'\n\n\n\nconst isServerSymbol = Symbol.for('_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 ): T => {\n const prevSlice = useRef< ObjectFromAttributes<T, Attributes> | null >(\n type === 'full'\n ? null\n // To avoid the first render to be always different even\n // if store changed other than selected attributes\n : getPartialObjectFromProperties(selectors, (store$$.getValue() as any)?.[INTERNAL_VALUE_PROP]),\n )\n\n const store = useSyncExternalStore(\n (onStoreChange) => {\n const subscription = store$$.subscribe({\n next: (v) => {\n if (type === 'full') {\n onStoreChange()\n\n return\n }\n\n // Partial store section ------------------------------------------------------------------\n const currentSlice = getPartialObjectFromProperties(selectors, (v as any)?.[INTERNAL_VALUE_PROP])\n\n const compareWithPreviousStore = (isEqualFunction ?? contentComparer as any)\n\n const isEquals = compareWithPreviousStore(prevSlice.current, currentSlice)\n\n if (!isEquals) {\n /**\n * Update previous slice with deepClone to avoid storing direct store$$ value reference.\n * This solve reference/value problems when changing the store object\n * (proxy.set is changing the target object which is 'v' here)\n */\n prevSlice.current = deepClone(currentSlice)\n onStoreChange()\n }\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","\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 capitalize,\n isCamelCase,\n} from '../utils'\n\nimport type { Maybe, UseSelector, WithoutType } from '../../types/shared'\n\n\n\ntype 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\ndeclare type Prettify<T> = {} & {\n [K in keyof T]: T[K];\n}\n\n\n\n\ntype CervelloStore<StoreType, StoreName extends string | undefined = undefined> =\n StoreName extends string\n ? Prettify<{\n // /** Reactive store */\n [K in `${StoreName}Store`]: StoreType\n }\n & {\n /** Hook to react to all changes done to 'store' */\n [K in `use${Capitalize<StoreName>}Store`]: () => StoreType\n }\n & {\n /** Hook to react to all changes done to 'store' */\n [K in `use${Capitalize<StoreName>}Selector`]: UseSelector<StoreType>\n }\n & {\n /** Resets the value to the initial value passed in */\n [K in `reset${Capitalize<StoreName>}Store`]: () => void\n }\n & {\n /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */\n use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType, StoreName>\n }>\n :\n {\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, StoreName>\n }\n\n\nexport type CervelloOptions<StoreName extends string | undefined = undefined> = {\n name?: StoreName\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 - Function which returns the default values for the store\n *\n * @returns \\{ store, useStore, useSelector \\} or `{ exampleStore, useExampleStore, useExampleSelector }` if name is provided in options with 'example' value\n */\nexport function cervello <\nT,\nStoreName extends string | undefined = undefined,\n> (initialValue: () => T, options?: CervelloOptions<StoreName>): Prettify< CervelloStore<Prettify<T & { $value: Maybe<T> }>, StoreName> >\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 \\} or `{ exampleStore, useExampleStore, useExampleSelector }` if name is provided in options with 'example' value\n */\nexport function cervello <\nT extends Record<string, unknown>,\nStoreName extends string | undefined = undefined,\n> (initialValue: T, options?: CervelloOptions<StoreName>): Prettify< CervelloStore<Prettify<T & { $value: Maybe<T> }>, StoreName> >\n\n\n\n/** @internal */\nexport function cervello <T, StoreName extends string | undefined = undefined> (\n initialValue: T | (() => T),\n options: CervelloOptions<StoreName> = { reactiveNestedObjects: true },\n): CervelloStore<T & { $value: Maybe<T> }, StoreName> {\n const { name: optionsName, reactiveNestedObjects = true } = options\n\n if (optionsName && !isCamelCase(optionsName))\n throw new Error(`[cervello]: options.name must be in camelCase and \"${optionsName}\" doesn't respect this rule.`)\n\n\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, reactiveNestedObjects)\n\n const cervelloStore = {\n [optionsName\n ? `${optionsName}Store`\n : 'store'\n ]: proxiedStore,\n\n [optionsName\n ? `reset${capitalize(optionsName)}Store`\n : 'reset'\n ] () {\n (proxiedStore as any).$value = defaultValue\n },\n\n // TO BE SEPARATED IN cervello/react package --------------------------------\n [optionsName\n ? `use${capitalize(optionsName)}Store`\n : 'useStore'\n ]: createStoreSelectorHook<T>(store$$, proxiedStore, 'full'),\n\n [optionsName\n ? `use${capitalize(optionsName)}Selector`\n : 'useSelector'\n ]: 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\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\n if (!isEquals) {\n cb(proxiedStore)\n prevSlice = deepClone(currentSlice)\n }\n },\n })\n },\n })\n })\n\n return this\n },\n } as any\n\n\n\n return cervelloStore\n}\n","\nexport type Noop = () => void\n\n\nexport type Observer<T> = {\n next: (value: T) => void\n}\n\nexport type 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\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","str","charAt","toUpperCase","slice","toLocaleLowerCase","hasOwn","call","bind","hasOwnProperty","nestedPath","Symbol","proxifyStore","store$$","objectToProxify","proxiedNestedObjectMap","shouldProxifyNestedObj","Error","Proxy","get","t","prop","propertyValue","isObject","propNestedPath","cachedValue","proxied","set","newValue","isRootTarget","_store$$$next","newClonedValue","Reflect","next","keys","cachedProxyKey","startsWith","assign","getValue","has","p","ownKeys","getOwnPropertyDescriptor","isServerSymbol","createStoreSelectorHook","proxiedStore","type","_Object$assign","serverInitialValue","selectors","isEqualFunction","_store$$$getValue","prevSlice","useRef","store","useSyncExternalStore","onStoreChange","subscription","subscribe","v","currentSlice","current","unsubscribe","getOwnPropertySymbols","includes","initialValue","options","reactiveNestedObjects","optionsName","name","_options$reactiveNest","test","defaultValue","clonedInitialValue","_clonedInitialValue","createCacheableSubject","getValueOnSubscribe","observerList","value","o","observer","push","filter","unSubscribeAll","cervelloStore","capitalize","$value","_cervelloStore","use","func","onChange","cb","_","onPartialChange","attrs","this"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cervello/react",
3
3
  "type": "module",
4
- "version": "1.2.0",
4
+ "version": "2.0.0",
5
5
  "description": "🀯 Simplest and truly reactive state manager for React",
6
6
  "author": "Chempo",
7
7
  "license": "MIT",
@@ -22,7 +22,10 @@
22
22
  "zustand",
23
23
  "reactive",
24
24
  "observable",
25
- "performance"
25
+ "performance",
26
+ "easy",
27
+ "simple",
28
+ "fast"
26
29
  ],
27
30
  "sideEffects": false,
28
31
  "exports": {
@@ -50,22 +53,18 @@
50
53
  "types"
51
54
  ],
52
55
  "peerDependencies": {
53
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
54
- },
55
- "dependencies": {
56
- "use-sync-external-store": "^1.2.0"
56
+ "react": ">= 18.2.0"
57
57
  },
58
58
  "devDependencies": {
59
- "@testing-library/dom": "^8.17.1",
60
- "@testing-library/react": "^13.3.0",
61
- "@types/react": "18.0.18",
62
- "@types/use-sync-external-store": "^0.0.3",
59
+ "@testing-library/dom": "9.3.3",
60
+ "@testing-library/react": "14.0.0",
61
+ "@types/react": "18.2.33",
63
62
  "microbundle": "0.15.1",
64
63
  "react": "18.2.0",
65
- "typescript": "4.8.2",
66
- "vite": "^3.0.9",
67
- "vitest": "^0.23.1",
68
- "vitest-react": "^0.9.5"
64
+ "typescript": "5.2.2",
65
+ "vite": "4.5.0",
66
+ "vitest": "0.34.6",
67
+ "vitest-react": "0.9.5"
69
68
  },
70
69
  "scripts": {
71
70
  "release": "pnpx bumpp --push=false && npm publish --access public",
package/types/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { cervello } from './lib/store';
2
- export type { CervelloUseFunction as UseFunction, CervelloOptions } from './lib/store';
1
+ export { cervello } from './lib/store';
2
+ export type { CervelloUseFunction as UseFunction, CervelloOptions } from './lib/store';
@@ -1 +1 @@
1
- export declare const INTERNAL_VALUE_PROP = "$$value$$";
1
+ export declare const INTERNAL_VALUE_PROP = "$$value$$";
@@ -1,3 +1,3 @@
1
- import type { UseSelector } from '../../types/shared';
2
- import type { CacheableSubject } from '../utils/subject';
3
- export declare function createStoreSelectorHook<T>(store$$: CacheableSubject<T>, proxiedStore: any, type: 'full' | 'slice'): UseSelector<T>;
1
+ import type { UseSelector } from '../../types/shared';
2
+ import type { CacheableSubject } from '../utils/subject';
3
+ export declare function createStoreSelectorHook<T>(store$$: CacheableSubject<T>, proxiedStore: any, type: 'full' | 'slice'): UseSelector<T>;
@@ -1,2 +1,2 @@
1
- export * from './proxify-store';
2
- export * from './create-store-selector-hook';
1
+ export * from './proxify-store';
2
+ export * from './create-store-selector-hook';
@@ -1,2 +1,2 @@
1
- import type { CacheableSubject } from '../utils/subject';
2
- export declare function proxifyStore<T>(store$$: CacheableSubject<T>, objectToProxify: T, proxiedNestedObjectMap: any, shouldProxifyNestedObj: boolean): 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,43 +1,58 @@
1
- import type { Maybe, UseSelector, WithoutType } from '../../types/shared';
2
- interface CervelloStoreUseParam<StoreType> {
3
- onChange: (cb: (store: StoreType) => void) => void;
4
- onPartialChange: <Attributes extends keyof WithoutType<StoreType, Function>, R extends Exclude<Attributes, '$value'>, ArrayOfAttributes extends Array<R>>(selectors: ArrayOfAttributes, cb: (store: StoreType) => void) => void;
5
- }
6
- /**
7
- * Use function which allows you to listen for changes in the store.
8
- */
9
- export declare type CervelloUseFunction<StoreType> = (param: CervelloStoreUseParam<StoreType>) => void;
10
- interface CervelloStore<StoreType> {
11
- /** Reactive store */
12
- store: StoreType;
13
- /** Hook to react to all changes done to 'store' */
14
- useStore: () => StoreType;
15
- /** Hook to react to changes done to 'store' in all the attributes provided */
16
- useSelector: UseSelector<StoreType>;
17
- /** Resets the value to the initial value passed in */
18
- reset: () => void;
19
- /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */
20
- use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType>;
21
- }
22
- export interface CervelloOptions {
23
- reactiveNestedObjects: boolean;
24
- }
25
- /**
26
- * Creates a store that is reactive and can be used inside and outside of React components.
27
- * @param initialValue - Object with the default values for the store
28
- *
29
- * @returns - \{ store, useStore, useSelector \}
30
- */
31
- export declare function cervello<T>(initialValue: T, options?: CervelloOptions): CervelloStore<T & {
32
- $value: Maybe<T>;
33
- }>;
34
- /**
35
- * Creates a store that is reactive and can be used inside and outside of React components.
36
- * @param initialValue - Function which returns the default values for the store
37
- *
38
- * @returns \{ store, useStore, useSelector \}
39
- */
40
- export declare function cervello<T>(initialValue: () => T, options?: CervelloOptions): CervelloStore<T & {
41
- $value: Maybe<T>;
42
- }>;
43
- export {};
1
+ import type { Maybe, UseSelector, WithoutType } from '../../types/shared';
2
+ type CervelloStoreUseParam<StoreType> = {
3
+ onChange: (cb: (store: StoreType) => void) => void;
4
+ onPartialChange: <Attributes extends keyof WithoutType<StoreType, Function>, R extends Exclude<Attributes, '$value'>, ArrayOfAttributes extends Array<R>>(selectors: ArrayOfAttributes, cb: (store: StoreType) => void) => void;
5
+ };
6
+ /**
7
+ * Use function which allows you to listen for changes in the store.
8
+ */
9
+ export type CervelloUseFunction<StoreType> = (param: CervelloStoreUseParam<StoreType>) => void;
10
+ declare type Prettify<T> = {} & {
11
+ [K in keyof T]: T[K];
12
+ };
13
+ type CervelloStore<StoreType, StoreName extends string | undefined = undefined> = StoreName extends string ? Prettify<{
14
+ [K in `${StoreName}Store`]: StoreType;
15
+ } & {
16
+ [K in `use${Capitalize<StoreName>}Store`]: () => StoreType;
17
+ } & {
18
+ [K in `use${Capitalize<StoreName>}Selector`]: UseSelector<StoreType>;
19
+ } & {
20
+ [K in `reset${Capitalize<StoreName>}Store`]: () => void;
21
+ } & {
22
+ /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */
23
+ use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType, StoreName>;
24
+ }> : {
25
+ /** Reactive store */
26
+ store: StoreType;
27
+ /** Hook to react to all changes done to 'store' */
28
+ useStore: () => StoreType;
29
+ /** Hook to react to changes done to 'store' in all the attributes provided */
30
+ useSelector: UseSelector<StoreType>;
31
+ /** Resets the value to the initial value passed in */
32
+ reset: () => void;
33
+ /** Functions to be attached to changes in a general way (tracking, loggers, ... etc) */
34
+ use: (...functions: Array<(useObj: CervelloStoreUseParam<StoreType>) => void>) => CervelloStore<StoreType, StoreName>;
35
+ };
36
+ export type CervelloOptions<StoreName extends string | undefined = undefined> = {
37
+ name?: StoreName;
38
+ reactiveNestedObjects?: boolean;
39
+ };
40
+ /**
41
+ * Creates a store that is reactive and can be used inside and outside of React components.
42
+ * @param initialValue - Function which returns the default values for the store
43
+ *
44
+ * @returns \{ store, useStore, useSelector \} or `{ exampleStore, useExampleStore, useExampleSelector }` if name is provided in options with 'example' value
45
+ */
46
+ export declare function cervello<T, StoreName extends string | undefined = undefined>(initialValue: () => T, options?: CervelloOptions<StoreName>): Prettify<CervelloStore<Prettify<T & {
47
+ $value: Maybe<T>;
48
+ }>, StoreName>>;
49
+ /**
50
+ * Creates a store that is reactive and can be used inside and outside of React components.
51
+ * @param initialValue - Object with the default values for the store
52
+ *
53
+ * @returns - \{ store, useStore, useSelector \} or `{ exampleStore, useExampleStore, useExampleSelector }` if name is provided in options with 'example' value
54
+ */
55
+ export declare function cervello<T extends Record<string, unknown>, StoreName extends string | undefined = undefined>(initialValue: T, options?: CervelloOptions<StoreName>): Prettify<CervelloStore<Prettify<T & {
56
+ $value: Maybe<T>;
57
+ }>, StoreName>>;
58
+ export {};
@@ -1,2 +1,3 @@
1
- export * from './object';
2
- export * from './subject';
1
+ export * from './object';
2
+ export * from './subject';
3
+ export * from './string';
@@ -1,38 +1,38 @@
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;
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,2 @@
1
+ export declare function capitalize(str: string): string;
2
+ export declare function isCamelCase(str: string): boolean;
@@ -1,13 +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>;
1
+ export type Noop = () => void;
2
+ export type Observer<T> = {
3
+ next: (value: T) => void;
4
+ };
5
+ export type Subscription = {
6
+ unsubscribe: Noop;
7
+ };
8
+ export 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>;
@@ -1,10 +1,10 @@
1
- export declare type WithoutType<T, V, WithNever = {
2
- [K in keyof T]: Exclude<T[K], undefined> extends V ? never : (T[K] extends Record<string, unknown> ? WithoutType<T[K], V> : T[K]);
3
- }> = Pick<WithNever, {
4
- [K in keyof WithNever]: WithNever[K] extends never ? never : K;
5
- }[keyof WithNever]>;
6
- export declare type ObjectFromAttributes<T, Attributes extends Array<keyof WithoutType<T, Function>>> = {
7
- [k in Attributes[number]]: T[k];
8
- };
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) => T;
1
+ export type WithoutType<T, V, WithNever = {
2
+ [K in keyof T]: Exclude<T[K], undefined> extends V ? never : (T[K] extends Record<string, unknown> ? WithoutType<T[K], V> : T[K]);
3
+ }> = Pick<WithNever, {
4
+ [K in keyof WithNever]: WithNever[K] extends never ? never : K;
5
+ }[keyof WithNever]>;
6
+ export type ObjectFromAttributes<T, Attributes extends Array<keyof WithoutType<T, Function>>> = {
7
+ [k in Attributes[number]]: T[k];
8
+ };
9
+ export type Maybe<T> = T | undefined;
10
+ export type UseSelector<T> = <Attributes extends Array<Exclude<keyof WithoutType<T, Function>, '$value'>>>(selectors: Attributes, isEqualFunction?: (previousState: ObjectFromAttributes<T, Attributes>, currentState: ObjectFromAttributes<T, Attributes>) => boolean) => T;