Comparing version 0.0.4 to 0.0.5
@@ -61,4 +61,8 @@ var __defProp = Object.defineProperty; | ||
const update = (lens, updater) => (s) => { | ||
const a = lens.get(s); | ||
return lens.set(s, updater(a)); | ||
const prev = lens.get(s); | ||
const next = updater(prev); | ||
if (Object.is(prev, next)) { | ||
return s; | ||
} | ||
return lens.set(s, updater(prev)); | ||
}; | ||
@@ -77,3 +81,7 @@ const externalStore = (initialState) => { | ||
update(updater) { | ||
state = updater(state); | ||
const next = updater(state); | ||
if (Object.is(next, state)) { | ||
return; | ||
} | ||
state = next; | ||
listeners.forEach((fn) => fn()); | ||
@@ -238,18 +246,31 @@ } | ||
const useSyncExternalStoreWithLens = (store, lens, shouldUpdate = true) => { | ||
const prevRef = React.useRef(NOTHING$1); | ||
const shouldUpdateFn = React.useMemo(() => shouldUpdateToFunction(shouldUpdate), [shouldUpdate]); | ||
const prevStateRef = React.useRef(NOTHING$1); | ||
const prevShouldUpdateRef = React.useRef(shouldUpdate); | ||
const shouldUpdateFnRef = React.useRef(NOTHING$1); | ||
if (prevShouldUpdateRef.current !== shouldUpdate) { | ||
shouldUpdateFnRef.current = NOTHING$1; | ||
} | ||
prevShouldUpdateRef.current = shouldUpdate; | ||
const getSnapshot = () => { | ||
const prev = prevRef.current; | ||
const prev = prevStateRef.current; | ||
const next = lens.get(store.getSnapshot()); | ||
if (Object.is(prev, next)) { | ||
return prev; | ||
} | ||
if (prev === NOTHING$1) { | ||
return next; | ||
} | ||
if (shouldUpdateFnRef.current === NOTHING$1) { | ||
shouldUpdateFnRef.current = shouldUpdateToFunction(shouldUpdate); | ||
} | ||
const shouldUpdateFn = shouldUpdateFnRef.current; | ||
if (shouldUpdateFn(prev, next)) { | ||
return next; | ||
} else { | ||
return prev; | ||
} | ||
return prev; | ||
}; | ||
const state = React.useSyncExternalStore(store.subscribe, getSnapshot); | ||
const state = React.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot); | ||
const setState = React.useCallback((updater) => store.update(update(lens, updater)), [store]); | ||
prevRef.current = state; | ||
prevStateRef.current = state; | ||
return [state, setState]; | ||
@@ -277,3 +298,3 @@ }; | ||
} | ||
let store = storeRef.current; | ||
const store = storeRef.current; | ||
React.useEffect(() => { | ||
@@ -308,7 +329,3 @@ if (store.getSnapshot() !== props.value) { | ||
}; | ||
var index = { | ||
stateful, | ||
stateless | ||
}; | ||
export { index as default }; | ||
export { stateful, stateless }; | ||
//# sourceMappingURL=concave.es.js.map |
@@ -1,2 +0,2 @@ | ||
var J=Object.defineProperty,W=Object.defineProperties;var Y=Object.getOwnPropertyDescriptors;var b=Object.getOwnPropertySymbols;var j=Object.prototype.hasOwnProperty,q=Object.prototype.propertyIsEnumerable;var A=(f,a,u)=>a in f?J(f,a,{enumerable:!0,configurable:!0,writable:!0,value:u}):f[a]=u,S=(f,a)=>{for(var u in a||(a={}))j.call(a,u)&&A(f,u,a[u]);if(b)for(var u of b(a))q.call(a,u)&&A(f,u,a[u]);return f},R=(f,a)=>W(f,Y(a));(function(f,a){typeof exports=="object"&&typeof module!="undefined"?module.exports=a(require("react")):typeof define=="function"&&define.amd?define(["react"],a):(f=typeof globalThis!="undefined"?globalThis:f||self,f.Concave=a(f.React))})(this,function(f){"use strict";function a(e){return e&&typeof e=="object"&&"default"in e?e:{default:e}}var u=a(f);const P=e=>Object.prototype.toString.call(e)==="[object Object]",N=e=>JSON.parse(JSON.stringify(e)),V=e=>P(e)?S({},e):Array.isArray(e)?[...e]:N(e),_=Object.freeze({get(e){return e},set(e,r){return r}}),h=()=>_,T=(e,r,n)=>({get(o){const t=e.get(o);return r(t)},set(o,t){const s=e.get(o);return e.set(o,n(s,t))}}),D=(e,r)=>T(e,n=>n[r],(n,o)=>{const t=V(n);return t[r]=o,t}),I=(e,r)=>n=>{const o=e.get(n);return e.set(n,r(o))},v=e=>{const r=new Set;let n=e;return{subscribe(o){return r.add(o),()=>r.delete(o)},getSnapshot(){return n},update(o){n=o(n),r.forEach(t=>t())}}},p=Symbol(),C=Symbol(),d=Symbol();let K=0;const $=()=>`$$ProxyLens(${K++})`,F=e=>Array.isArray(e)||P(e),H=(e,r)=>{const n=e.createUse(e.lens);return o=>{const[t,s]=n(o);return[O(t,r),s]}},O=(e,r)=>{if(!F(e))return e;if(Reflect.has(e,p))return Reflect.get(e,p);let n;const o=new Proxy(e,{get(t,s){if(s===p)return o;if(s==="toJSON")return n!=null||(n=()=>t),n;if(s==="toLens")return r[C];const c=t[s],l=r[s];return O(c,l)},ownKeys(t){return[...Reflect.ownKeys(t),d]},getOwnPropertyDescriptor(t,s){if(s===d)throw new Error("Cannot copy a ProxyValue into a new value");return Object.getOwnPropertyDescriptor(t,s)},set(){throw new Error("Cannot set property on ProxyValue")},deleteProperty(){throw new Error("Cannot delete property on ProxyValue")}});return Object.defineProperty(e,p,{value:o,enumerable:!1}),o},x=e=>{const r={};let n,o,t;const s=new Proxy({},{get(c,l){if(l==="$key")return t!=null||(t=$()),t;if(l===C)return o!=null||(o=()=>s),o;if(l==="use")return n!=null||(n=H(e,s)),n;if(r[l]===void 0){const i=R(S({},e),{lens:D(e.lens,l)}),y=x(i);r[l]=y}return r[l]},ownKeys(){return[d]},getOwnPropertyDescriptor(c,l){if(l===d)throw new Error("Cannot copy a ProxyLens into a new value")},set(){throw new Error("Cannot set property on ProxyLens")},deleteProperty(){throw new Error("Cannot delete property on ProxyLens")}});return s},g=e=>{if(typeof e=="boolean")return(r,n)=>e?r!==n:!1;if(typeof e=="function")return e;if(Array.isArray(e)){const r=Object.fromEntries(e.map(n=>[n,!0]));return g(r)}return(r,n)=>{let o=!1,t=!1,s,c;if(Array.isArray(r)?(o=!0,s=r):s=[r],Array.isArray(n)?(t=!0,c=n):c=[n],t!==o||s.length!==c.length)return!0;for(let l=0;l<s.length;l++){const i=s[l],y=c[l];for(const w in e)if(g(e[w])(i[w],y[w]))return!0}return!1}},E=Symbol(),m=(e,r,n=!0)=>{const o=u.default.useRef(E),t=u.default.useMemo(()=>g(n),[n]),s=()=>{const i=o.current,y=r.get(e.getSnapshot());return i===E||t(i,y)?y:i},c=u.default.useSyncExternalStore(e.subscribe,s),l=u.default.useCallback(i=>e.update(I(r,i)),[e]);return o.current=c,[c,l]},L=Symbol();var G={stateful:e=>{const r=v(e);return[x({lens:h(),createUse:t=>s=>m(r,t,s)}),{get current(){return r.getSnapshot()},set current(t){r.update(()=>t)}}]},stateless:()=>{const e=u.default.createContext(L);e.displayName="Lens(ExternalStoreContext)";const r=t=>s=>{const c=u.default.useContext(e);if(c===L)throw new Error("Cannot call `lens.use()` in a component outside of <LensProvider />");return m(c,t,s)},n=x({lens:h(),createUse:r}),o=t=>{const s=u.default.useRef();s.current||(s.current=v(t.value));let c=s.current;return u.default.useEffect(()=>{c.getSnapshot()!==t.value&&c.update(()=>t.value)},[t.value]),u.default.useEffect(()=>c.subscribe(()=>t.onChange(c.getSnapshot())),[t.onChange]),u.default.createElement(e.Provider,{value:c},t.children)};return o.displayName="Lens(Provider)",[n,o]}};return G}); | ||
var W=Object.defineProperty,Y=Object.defineProperties;var q=Object.getOwnPropertyDescriptors;var A=Object.getOwnPropertySymbols;var z=Object.prototype.hasOwnProperty,X=Object.prototype.propertyIsEnumerable;var R=(c,f,l)=>f in c?W(c,f,{enumerable:!0,configurable:!0,writable:!0,value:l}):c[f]=l,O=(c,f)=>{for(var l in f||(f={}))z.call(f,l)&&R(c,l,f[l]);if(A)for(var l of A(f))X.call(f,l)&&R(c,l,f[l]);return c},N=(c,f)=>Y(c,q(f));(function(c,f){typeof exports=="object"&&typeof module!="undefined"?f(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],f):(c=typeof globalThis!="undefined"?globalThis:c||self,f(c.Concave={},c.React))})(this,function(c,f){"use strict";function l(e){return e&&typeof e=="object"&&"default"in e?e:{default:e}}var i=l(f);const h=e=>Object.prototype.toString.call(e)==="[object Object]",_=e=>JSON.parse(JSON.stringify(e)),T=e=>h(e)?O({},e):Array.isArray(e)?[...e]:_(e),V=Object.freeze({get(e){return e},set(e,n){return n}}),v=()=>V,j=(e,n,r)=>({get(s){const t=e.get(s);return n(t)},set(s,t){const o=e.get(s);return e.set(s,r(o,t))}}),F=(e,n)=>j(e,r=>r[n],(r,s)=>{const t=T(r);return t[n]=s,t}),D=(e,n)=>r=>{const s=e.get(r),t=n(s);return Object.is(s,t)?r:e.set(r,n(s))},b=e=>{const n=new Set;let r=e;return{subscribe(s){return n.add(s),()=>n.delete(s)},getSnapshot(){return r},update(s){const t=s(r);Object.is(t,r)||(r=t,n.forEach(o=>o()))}}},g=Symbol(),C=Symbol(),S=Symbol();let I=0;const K=()=>`$$ProxyLens(${I++})`,$=e=>Array.isArray(e)||h(e),H=(e,n)=>{const r=e.createUse(e.lens);return s=>{const[t,o]=r(s);return[E(t,n),o]}},E=(e,n)=>{if(!$(e))return e;if(Reflect.has(e,g))return Reflect.get(e,g);let r;const s=new Proxy(e,{get(t,o){if(o===g)return s;if(o==="toJSON")return r!=null||(r=()=>t),r;if(o==="toLens")return n[C];const u=t[o],a=n[o];return E(u,a)},ownKeys(t){return[...Reflect.ownKeys(t),S]},getOwnPropertyDescriptor(t,o){if(o===S)throw new Error("Cannot copy a ProxyValue into a new value");return Object.getOwnPropertyDescriptor(t,o)},set(){throw new Error("Cannot set property on ProxyValue")},deleteProperty(){throw new Error("Cannot delete property on ProxyValue")}});return Object.defineProperty(e,g,{value:s,enumerable:!1}),s},w=e=>{const n={};let r,s,t;const o=new Proxy({},{get(u,a){if(a==="$key")return t!=null||(t=K()),t;if(a===C)return s!=null||(s=()=>o),s;if(a==="use")return r!=null||(r=H(e,o)),r;if(n[a]===void 0){const x=N(O({},e),{lens:F(e.lens,a)}),y=w(x);n[a]=y}return n[a]},ownKeys(){return[S]},getOwnPropertyDescriptor(u,a){if(a===S)throw new Error("Cannot copy a ProxyLens into a new value")},set(){throw new Error("Cannot set property on ProxyLens")},deleteProperty(){throw new Error("Cannot delete property on ProxyLens")}});return o},P=e=>{if(typeof e=="boolean")return(n,r)=>e?n!==r:!1;if(typeof e=="function")return e;if(Array.isArray(e)){const n=Object.fromEntries(e.map(r=>[r,!0]));return P(n)}return(n,r)=>{let s=!1,t=!1,o,u;if(Array.isArray(n)?(s=!0,o=n):o=[n],Array.isArray(r)?(t=!0,u=r):u=[r],t!==s||o.length!==u.length)return!0;for(let a=0;a<o.length;a++){const x=o[a],y=u[a];for(const p in e)if(P(e[p])(x[p],y[p]))return!0}return!1}},d=Symbol(),L=(e,n,r=!0)=>{const s=i.default.useRef(d),t=i.default.useRef(r),o=i.default.useRef(d);t.current!==r&&(o.current=d),t.current=r;const u=()=>{const y=s.current,p=n.get(e.getSnapshot());return Object.is(y,p)?y:y===d||(o.current===d&&(o.current=P(r)),o.current(y,p))?p:y},a=i.default.useSyncExternalStore(e.subscribe,u,u),x=i.default.useCallback(y=>e.update(D(n,y)),[e]);return s.current=a,[a,x]},m=Symbol(),G=()=>{const e=i.default.createContext(m);e.displayName="Lens(ExternalStoreContext)";const n=t=>o=>{const u=i.default.useContext(e);if(u===m)throw new Error("Cannot call `lens.use()` in a component outside of <LensProvider />");return L(u,t,o)},r=w({lens:v(),createUse:n}),s=t=>{const o=i.default.useRef();o.current||(o.current=b(t.value));const u=o.current;return i.default.useEffect(()=>{u.getSnapshot()!==t.value&&u.update(()=>t.value)},[t.value]),i.default.useEffect(()=>u.subscribe(()=>t.onChange(u.getSnapshot())),[t.onChange]),i.default.createElement(e.Provider,{value:u},t.children)};return s.displayName="Lens(Provider)",[r,s]},J=e=>{const n=b(e);return[w({lens:v(),createUse:t=>o=>L(n,t,o)}),{get current(){return n.getSnapshot()},set current(t){n.update(()=>t)}}]};c.stateful=J,c.stateless=G,Object.defineProperty(c,"__esModule",{value:!0}),c[Symbol.toStringTag]="Module"}); | ||
//# sourceMappingURL=concave.umd.js.map |
declare type Listener = () => void; | ||
declare type Unsubscribe = () => void; | ||
declare type Updater<A> = (a: A) => A; | ||
export declare type ExternalStore<S> = { | ||
subscribe(onStoreChange: Listener): Unsubscribe; | ||
getSnapshot(): S; | ||
update(updater: (state: S) => S): void; | ||
update(updater: Updater<S>): void; | ||
}; | ||
export declare const externalStore: <S>(initialState: S) => ExternalStore<S>; | ||
export declare const externalStore: <S extends {}>(initialState: S) => ExternalStore<S>; | ||
export {}; |
@@ -1,11 +0,3 @@ | ||
/// <reference types="react" /> | ||
import { ProxyLens } from "./proxy-lens"; | ||
export { stateless, stateful } from "./react"; | ||
export declare type Lens<A> = Omit<ProxyLens<A>, symbol>; | ||
declare const _default: { | ||
stateful: <S>(initialState: S) => readonly [ProxyLens<S>, import("react").MutableRefObject<S>]; | ||
stateless: <S_1>() => readonly [ProxyLens<S_1>, import("react").FunctionComponent<{ | ||
value: S_1; | ||
onChange(next: S_1): void; | ||
}>]; | ||
}; | ||
export default _default; |
@@ -6,5 +6,5 @@ declare type ShouldUpdateBoolean = boolean; | ||
}; | ||
declare type ShouldUpdateFunction<A> = (prev: A, next: A) => boolean; | ||
export declare type ShouldUpdateFunction<A> = (prev: A, next: A) => boolean; | ||
export declare type ShouldUpdate<A> = ShouldUpdateBoolean | ShouldUpdateFunction<A> | ShouldUpdateArray<A> | ShouldUpdateObject<A>; | ||
export declare const shouldUpdateToFunction: <A>(shouldUpdate: ShouldUpdate<A>) => ShouldUpdateFunction<A>; | ||
export {}; |
{ | ||
"name": "concave", | ||
"version": "0.0.4", | ||
"description": "Basic lensing for React", | ||
"version": "0.0.5", | ||
"description": "A Lens-like interface for state management in React", | ||
"main": "dist/concave.umd.js", | ||
@@ -6,0 +6,0 @@ "module": "dist/concave.es.js", |
@@ -1,7 +0,42 @@ | ||
# Lenses in React | ||
# 🧐 Concave | ||
Uses TypeScript and [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) to dynamically construct a lens-like interface for your application state. | ||
A Lens-like interface for state management in React. | ||
## Overview | ||
## Introduction to Lenses for React developers | ||
## Installation | ||
## API | ||
### `stateful<S>(initialState: S): [Lens<S>, MutableRefObject<S>]` | ||
### `stateless<S>(): [Lens<S>, LensProvider<S>]` | ||
### `LensProvider<S>` | ||
### `Lens<A>` | ||
A stateless [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) around `A` | ||
#### `Lens<A>.use(shouldUpdate? ShouldUpdate<A>): [ProxyValue<A>, UpdateFn<A>]` | ||
#### `Lens<A>.$key` | ||
## Examples | ||
## Testing | ||
## Performance tips | ||
1. Use shouldUpdate. | ||
2. If do use a shouldUpdate argument for the lens, you can either memoize it with `React.useMemo` or `React.useCallback` or store it outside | ||
of the component. | ||
## Example | ||
Uses TypeScript and [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) to dynamically construct a lens-like interface for your application state. | ||
You can construct a lens/React Provider by just providing the shape of your application state | ||
@@ -12,6 +47,6 @@ | ||
import Concave from "concave"; | ||
import { stateless } from "concave"; | ||
import type { State } from "./application-state"; | ||
export const [lens, LensProvider] = Concave.stateless<State>(); | ||
export const [lens, LensProvider] = stateless<State>(); | ||
``` | ||
@@ -18,0 +53,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
30766
452
109