Comparing version 0.6.0-0 to 0.6.0-next.0
# Changelog | ||
All notable changes to this project will be documented in this file. | ||
## 0.6.0-next.0 | ||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
### Minor Changes | ||
## [Unreleased] | ||
- d2eb9b4: **Fixed:** `useStore` now hooks into the store using `useLayoutEffect`, not `useEffect` | ||
- 53fff47: Refreshed all of the package's dependencies and brushed up its test setup. | ||
- 53fff47: Statery now requires React 18 and up! | ||
- **Changed:** The library is now built and bundled using the excellent [microbundle](https://github.com/developit/microbundle). | ||
## [0.5.4] - 2021-03-20 | ||
@@ -13,0 +12,0 @@ |
@@ -55,1 +55,9 @@ /** | ||
export declare const makeStore: <T extends State>(initialState: T) => Store<T>; | ||
/** | ||
* Provides reactive read access to a Statery store. Returns a proxy object that | ||
* provides direct access to the store's state and makes sure that the React component | ||
* it was invoked from automaticaly re-renders when any of the data it uses is updated. | ||
* | ||
* @param store The Statery store to access. | ||
*/ | ||
export declare const useStore: <T extends State>(store: Store<T>) => T; |
@@ -1,2 +0,2 @@ | ||
function t(){return(t=Object.assign||function(t){for(var r=1;r<arguments.length;r++){var e=arguments[r];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])}return t}).apply(this,arguments)}function r(t,r){(null==r||r>t.length)&&(r=t.length);for(var e=0,n=new Array(r);e<r;e++)n[e]=t[e];return n}exports.makeStore=function(e){var n=e,o=new Set;return{get state(){return n},set:function(e){var a=function(t){return Object.keys(t).reduce(function(r,e){return t[e]!==n[e]&&(r[e]=t[e]),r},{})}(e instanceof Function?e(n):e);if(Object.keys(a).length>0){var i=n;n=t({},n,a);for(var u,c=function(t,e){var n;if("undefined"==typeof Symbol||null==t[Symbol.iterator]){if(Array.isArray(t)||(n=function(t,e){if(t){if("string"==typeof t)return r(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?r(t,e):void 0}}(t))){n&&(t=n);var o=0;return function(){return o>=t.length?{done:!0}:{done:!1,value:t[o++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}return(n=t[Symbol.iterator]()).next.bind(n)}(o);!(u=c()).done;)(0,u.value)(a,i)}return n},subscribe:function(t){o.add(t)},unsubscribe:function(t){o.delete(t)}}}; | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react");const t=t=>{const s=e.useRef(null);return s.current||(s.current=t()),s.current};exports.makeStore=e=>{let t=e;const s=new Set;return{get state(){return t},set:e=>{const r=(e=>Object.keys(e).reduce(((s,r)=>(e[r]!==t[r]&&(s[r]=e[r]),s)),{}))(e instanceof Function?e(t):e);if(Object.keys(r).length>0){const e=t;t=Object.assign(Object.assign({},t),r);for(const t of s)t(r,e)}return t},subscribe:e=>{s.add(e)},unsubscribe:e=>{s.delete(e)}}},exports.useStore=s=>{const[,r]=e.useState(0),n=t((()=>new Set));return e.useLayoutEffect((()=>{const e=e=>{Object.keys(e).find((e=>n.has(e)))&&r((e=>e+1))};return s.subscribe(e),()=>{s.unsubscribe(e)}}),[s]),new Proxy({},{get:(e,t)=>(n.add(t),s.state[t])})}; | ||
//# sourceMappingURL=index.js.map |
module.exports = { | ||
verbose: true, | ||
preset: "ts-jest", | ||
roots: ["src", "test"], | ||
testMatch: ["**/__tests__/**/*.+(ts|tsx|js)", "**/?(*.)+(spec|test).+(ts|tsx|js)"], | ||
testMatch: ["**/?(*.)+(spec|test).+(ts|tsx)"], | ||
testPathIgnorePatterns: ["node_modules"], | ||
testEnvironment: "jsdom", | ||
moduleFileExtensions: ["js", "ts", "tsx"], | ||
globals: { | ||
@@ -8,0 +9,0 @@ "ts-jest": { |
@@ -17,22 +17,5 @@ { | ||
"sideEffects": false, | ||
"version": "0.6.0-0", | ||
"src": "src/index.ts", | ||
"version": "0.6.0-next.0", | ||
"main": "dist/index.js", | ||
"module": "dist/index.modern.js", | ||
"unpkg": "dist/index.umd.js", | ||
"exports": { | ||
".": "./dist/index.modern.js", | ||
"./react": "./dist/react.modern.js", | ||
"./preact": "./dist/preact.modern.js" | ||
}, | ||
"typesVersions": { | ||
"*": { | ||
"react": [ | ||
"dist/react" | ||
], | ||
"preact": [ | ||
"dist/preact" | ||
] | ||
} | ||
}, | ||
"module": "dist/index.esm.js", | ||
"types": "dist/index.d.ts", | ||
@@ -45,24 +28,30 @@ "files": [ | ||
"clean": "rimraf dist", | ||
"dev": "microbundle watch src/*.ts --external react,preact", | ||
"build": "microbundle build src/*.ts --external react,preact", | ||
"dev": "yarn clean && rollup -c -w", | ||
"build": "yarn clean && rollup -c", | ||
"test": "jest", | ||
"docs": "typedoc src/index.ts", | ||
"prepublishOnly": "yarn test && yarn build" | ||
"release": "yarn build && yarn test && yarn changeset publish" | ||
}, | ||
"devDependencies": { | ||
"@testing-library/react": "^11.2.2", | ||
"@types/jest": "^26.0.19", | ||
"@types/react": "^17.0.0", | ||
"@types/react-dom": "^17.0.0", | ||
"jest": "^26.6.3", | ||
"microbundle": "^0.13.0", | ||
"preact": "^10.5.13", | ||
"react": "^17.0.1", | ||
"react-dom": "^17.0.1", | ||
"@changesets/cli": "^2.24.1", | ||
"@testing-library/react": "^13.3.0", | ||
"@types/jest": "^28.1.6", | ||
"@types/react": "^18.0.0", | ||
"@types/react-dom": "^18.0.0", | ||
"jest": "^28.1.3", | ||
"jest-environment-jsdom": "^28.1.3", | ||
"react": "^18.1.0", | ||
"react-dom": "^18.1.0", | ||
"rimraf": "^3.0.2", | ||
"ts-jest": "^26.4.4", | ||
"rollup": "^2.35.1", | ||
"rollup-plugin-terser": "^7.0.2", | ||
"rollup-plugin-typescript2": "^0.32.1", | ||
"ts-jest": "^28.0.7", | ||
"tslib": "^2.0.3", | ||
"typedoc": "^0.20.1", | ||
"typedoc": "^0.23.9", | ||
"typescript": "^4.1.3" | ||
}, | ||
"peerDependencies": { | ||
"react": ">=18.0" | ||
} | ||
} |
@@ -0,1 +1,3 @@ | ||
import { useLayoutEffect, useRef, useState } from "react" | ||
/* | ||
@@ -91,6 +93,2 @@ | ||
/** | ||
* Reduces a set of incoming changes to those that actually _are_ changes from the | ||
* current state. | ||
*/ | ||
const getActualChanges = (updates: Partial<T>) => | ||
@@ -134,1 +132,67 @@ Object.keys(updates).reduce<Partial<T>>((changes, prop: keyof Partial<T>) => { | ||
} | ||
/* | ||
▄█ █▄ ▄██████▄ ▄██████▄ ▄█ ▄█▄ ▄████████ | ||
███ ███ ███ ███ ███ ███ ███ ▄███▀ ███ ███ | ||
███ ███ ███ ███ ███ ███ ███▐██▀ ███ █▀ | ||
▄███▄▄▄▄███▄▄ ███ ███ ███ ███ ▄█████▀ ███ | ||
▀▀███▀▀▀▀███▀ ███ ███ ███ ███ ▀▀█████▄ ▀███████████ | ||
███ ███ ███ ███ ███ ███ ███▐██▄ ███ | ||
███ ███ ███ ███ ███ ███ ███ ▀███▄ ▄█ ███ | ||
███ █▀ ▀██████▀ ▀██████▀ ███ ▀█▀ ▄████████▀ | ||
▀ | ||
*/ | ||
/** | ||
* Provides reactive read access to a Statery store. Returns a proxy object that | ||
* provides direct access to the store's state and makes sure that the React component | ||
* it was invoked from automaticaly re-renders when any of the data it uses is updated. | ||
* | ||
* @param store The Statery store to access. | ||
*/ | ||
export const useStore = <T extends State>(store: Store<T>): T => { | ||
/* A cheap version state that we will bump in order to re-render the component. */ | ||
const [, setVersion] = useState(0) | ||
/* A set containing all props that we're interested in. */ | ||
const subscribedProps = useConst(() => new Set<keyof T>()) | ||
/* Subscribe to changes in the store. */ | ||
useLayoutEffect(() => { | ||
const listener: Listener<T> = (updates: Partial<T>) => { | ||
/* If there is at least one prop being updated that we're interested in, | ||
bump our local version. */ | ||
if (Object.keys(updates).find((prop) => subscribedProps.has(prop))) { | ||
setVersion((v) => v + 1) | ||
} | ||
} | ||
/* Mount & unmount the listener */ | ||
store.subscribe(listener) | ||
return () => void store.unsubscribe(listener) | ||
}, [store]) | ||
return new Proxy<Record<any, any>>( | ||
{}, | ||
{ | ||
get: (_, prop: string) => { | ||
/* Add the prop we're interested in to the list of props */ | ||
subscribedProps.add(prop) | ||
/* Return the current value of the property. */ | ||
return store.state[prop] | ||
} | ||
} | ||
) | ||
} | ||
/** | ||
* A tiny helper hook that will initialize a ref with the return value of the | ||
* given constructor function. | ||
*/ | ||
const useConst = <T>(ctor: () => T) => { | ||
const ref = useRef<T>(null!) | ||
if (!ref.current) ref.current = ctor() | ||
return ref.current | ||
} |
{ | ||
"compilerOptions": { | ||
"target": "ESNext", | ||
"module": "ESNext", | ||
"target": "es2015", | ||
"module": "es2015", | ||
"moduleResolution": "node", | ||
"declaration": true, | ||
"strict": true, | ||
"jsx": "react", | ||
"jsx": "react-jsx", | ||
"allowSyntheticDefaultImports": true, | ||
@@ -10,0 +10,0 @@ "esModuleInterop": true |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 2 instances in 1 package
2
228656
1
17
27
589