x-view-model
Version:
A lightweight, type-safe MVVM state management solution for React applications. Features reactive updates, computed properties, and deep path selection with minimal bundle size.
3 lines (2 loc) • 17.8 kB
JavaScript
import{useState as t,useCallback as e,useMemo as n,useEffect as r}from"react";var o=function(t,e){return o=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])},o(t,e)};function s(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function n(){this.constructor=t}o(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}var i=function(){return i=Object.assign||function(t){for(var e,n=1,r=arguments.length;n<r;n++)for(var o in e=arguments[n])Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t},i.apply(this,arguments)};function a(t,e,n,r){return new(n||(n=Promise))((function(o,s){function i(t){try{c(r.next(t))}catch(t){s(t)}}function a(t){try{c(r.throw(t))}catch(t){s(t)}}function c(t){var e;t.done?o(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(i,a)}c((r=r.apply(t,e||[])).next())}))}function c(t,e){var n,r,o,s={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]},i=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return i.next=a(0),i.throw=a(1),i.return=a(2),"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function a(a){return function(c){return function(a){if(n)throw new TypeError("Generator is already executing.");for(;i&&(i=0,a[0]&&(s=0)),s;)try{if(n=1,r&&(o=2&a[0]?r.return:a[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,a[1])).done)return o;switch(r=0,o&&(a=[2&a[0],o.value]),a[0]){case 0:case 1:o=a;break;case 4:return s.label++,{value:a[1],done:!1};case 5:s.label++,r=a[1],a=[0];continue;case 7:a=s.ops.pop(),s.trys.pop();continue;default:if(!(o=s.trys,(o=o.length>0&&o[o.length-1])||6!==a[0]&&2!==a[0])){s=0;continue}if(3===a[0]&&(!o||a[1]>o[0]&&a[1]<o[3])){s.label=a[1];break}if(6===a[0]&&s.label<o[1]){s.label=o[1],o=a;break}if(o&&s.label<o[2]){s.label=o[2],s.ops.push(a);break}o[2]&&s.ops.pop(),s.trys.pop();continue}a=e.call(t,s)}catch(t){a=[6,t],r=0}finally{n=o=0}if(5&a[0])throw a[1];return{value:a[0]?a[1]:void 0,done:!0}}([a,c])}}}"function"==typeof SuppressedError&&SuppressedError;const h="insert",l="update",p="delete",f="reverse",u="shuffle",y=Symbol.for("object-observer-meta-key-0"),d={async:1},b=t=>{if(!t||"object"!=typeof t)return null;const e={},n=[];for(const[r,o]of Object.entries(t))if("path"===r){if("string"!=typeof o||""===o)throw new Error('"path" option, if/when provided, MUST be a non-empty string');e[r]=o}else if("pathsOf"===r){if(t.path)throw new Error('"pathsOf" option MAY NOT be specified together with "path" option');if("string"!=typeof o)throw new Error('"pathsOf" option, if/when provided, MUST be a string (MAY be empty)');e[r]=t.pathsOf.split(".").filter(Boolean)}else if("pathsFrom"===r){if(t.path||t.pathsOf)throw new Error('"pathsFrom" option MAY NOT be specified together with "path"/"pathsOf" option/s');if("string"!=typeof o||""===o)throw new Error('"pathsFrom" option, if/when provided, MUST be a non-empty string');e[r]=o}else n.push(r);if(n.length)throw new Error(`'${n.join(", ")}' is/are not a valid observer option/s`);return e},v=(t,e)=>{const n={};n[y]=e;for(const r in t)n[r]=O(t[r],r,e);return n},w=(t,e)=>{let n=t.length;const r=new Array(n);r[y]=e;for(let o=0;o<n;o++)r[o]=O(t[o],o,e);return r},g=(t,e)=>(t[y]=e,t),m=(t,e)=>{if(null===t)return e;let n=e;if(t.path){const r=t.path;n=e.filter((t=>t.path.join(".")===r))}else if(t.pathsOf){const r=t.pathsOf,o=r.join(".");n=e.filter((t=>(t.path.length===r.length+1||t.path.length===r.length&&(t.type===f||t.type===u))&&t.path.join(".").startsWith(o)))}else if(t.pathsFrom){const r=t.pathsFrom;n=e.filter((t=>t.path.join(".").startsWith(r)))}return n},_=(t,e)=>{try{t(e)}catch(n){console.error(`failed to notify listener ${t} with ${e}`,n)}},j=function(){const t=this.batches;this.batches=[];for(const[e,n]of t)_(e,n)},x=(t,e)=>{let n,r,o,s,i,a,c=t;const h=e.length;do{for(n=c.options.async,r=c.observers,a=r.length;a--;)if([o,s]=r[a],i=m(s,e),i.length)if(n){let t;0===c.batches.length&&queueMicrotask(j.bind(c));for(const e of c.batches)if(e[0]===o){t=e;break}t||(t=[o,[]],c.batches.push(t)),Array.prototype.push.apply(t[1],i)}else _(o,i);const t=c.parent;if(t){for(let t=0;t<h;t++){const n=e[t];e[t]=new K(n.type,[c.ownKey,...n.path],n.value,n.oldValue,n.object)}c=t}else c=null}while(c)},O=(t,e,n)=>"object"!=typeof t||null===t?t:Array.isArray(t)?new T({target:t,ownKey:e,parent:n}).proxy:ArrayBuffer.isView(t)?new $({target:t,ownKey:e,parent:n}).proxy:t instanceof Date?t:new P({target:t,ownKey:e,parent:n}).proxy,A=function(){const t=this[y],e=t.target;let n,r,o;for(e.reverse(),n=0,r=e.length;n<r;n++)if(o=e[n],o&&"object"==typeof o){const t=o[y];t&&(t.ownKey=n)}const s=[new K(f,[],void 0,void 0,this)];return x(t,s),this},M=function(t){const e=this[y],n=e.target;let r,o,s;for(n.sort(t),r=0,o=n.length;r<o;r++)if(s=n[r],s&&"object"==typeof s){const t=s[y];t&&(t.ownKey=r)}const i=[new K(u,[],void 0,void 0,this)];return x(e,i),this},E=function(t,e,n){const r=this[y],o=r.target,s=[],i=o.length,a=o.slice(0);if(e=void 0===e?0:e<0?Math.max(i+e,0):Math.min(e,i),n=void 0===n?i:n<0?Math.max(i+n,0):Math.min(n,i),e<i&&n>e){let i;o.fill(t,e,n);for(let t,c,p=e;p<n;p++)t=o[p],o[p]=O(t,p,r),p in a?(c=a[p],c&&"object"==typeof c&&(i=c[y],i&&(c=i.detach())),s.push(new K(l,[p],o[p],c,this))):s.push(new K(h,[p],o[p],void 0,this));x(r,s)}return this},S=function(t,e,n){const r=this[y],o=r.target,s=o.length;t=t<0?Math.max(s+t,0):t,e=void 0===e?0:e<0?Math.max(s+e,0):Math.min(e,s),n=void 0===n?s:n<0?Math.max(s+n,0):Math.min(n,s);const i=Math.min(n-e,s-t);if(t<s&&t!==e&&i>0){const s=o.slice(0),a=[];o.copyWithin(t,e,n);for(let e,n,c,h=t;h<t+i;h++)e=o[h],e&&"object"==typeof e&&(e=O(e,h,r),o[h]=e),n=s[h],n&&"object"==typeof n&&(c=n[y],c&&(n=c.detach())),"object"!=typeof e&&e===n||a.push(new K(l,[h],e,n,this));x(r,a)}return this},k={pop:function(){const t=this[y],e=t.target,n=e.length-1;let r=e.pop();if(r&&"object"==typeof r){const t=r[y];t&&(r=t.detach())}const o=[new K(p,[n],void 0,r,this)];return x(t,o),r},push:function(){const t=this[y],e=t.target,n=arguments.length,r=new Array(n),o=e.length;for(let e=0;e<n;e++)r[e]=O(arguments[e],o+e,t);const s=Reflect.apply(e.push,e,r),i=[];for(let t=o,n=e.length;t<n;t++)i[t-o]=new K(h,[t],e[t],void 0,this);return x(t,i),s},shift:function(){const t=this[y],e=t.target;let n,r,o,s,i;for(n=e.shift(),n&&"object"==typeof n&&(i=n[y],i&&(n=i.detach())),r=0,o=e.length;r<o;r++)s=e[r],s&&"object"==typeof s&&(i=s[y],i&&(i.ownKey=r));const a=[new K(p,[0],void 0,n,this)];return x(t,a),n},unshift:function(){const t=this[y],e=t.target,n=arguments.length,r=new Array(n);for(let e=0;e<n;e++)r[e]=O(arguments[e],e,t);const o=Reflect.apply(e.unshift,e,r);for(let t,n=0,r=e.length;n<r;n++)if(t=e[n],t&&"object"==typeof t){const e=t[y];e&&(e.ownKey=n)}const s=r.length,i=new Array(s);for(let t=0;t<s;t++)i[t]=new K(h,[t],e[t],void 0,this);return x(t,i),o},reverse:A,sort:M,fill:E,copyWithin:S,splice:function(){const t=this[y],e=t.target,n=arguments.length,r=new Array(n),o=e.length;for(let e=0;e<n;e++)r[e]=O(arguments[e],e,t);const s=0===n?0:r[0]<0?o+r[0]:r[0],i=n<2?o-s:r[1],a=Math.max(n-2,0),c=Reflect.apply(e.splice,e,r),f=e.length;let u,d,b,v;for(let t,n=0;n<f;n++)t=e[n],t&&"object"==typeof t&&(u=t[y],u&&(u.ownKey=n));for(d=0,b=c.length;d<b;d++)v=c[d],v&&"object"==typeof v&&(u=v[y],u&&(c[d]=u.detach()));const w=[];let g;for(g=0;g<i;g++)g<a?w.push(new K(l,[s+g],e[s+g],c[g],this)):w.push(new K(p,[s+g],void 0,c[g],this));for(;g<a;g++)w.push(new K(h,[s+g],e[s+g],void 0,this));return x(t,w),c}},H={reverse:A,sort:M,fill:E,copyWithin:S,set:function(t,e){const n=this[y],r=n.target,o=t.length,s=r.slice(0);e=e||0,r.set(t,e);const i=new Array(o);for(let t=e;t<o+e;t++)i[t-e]=new K(l,[t],r[t],s[t],this);x(n,i)}};class K{constructor(t,e,n,r,o){this.type=t,this.path=e,this.value=n,this.oldValue=r,this.object=o}}class N{constructor(t,e){const{target:n,parent:r,ownKey:o}=t;r&&void 0!==o?(this.parent=r,this.ownKey=o):(this.parent=null,this.ownKey=null);const s=e(n,this);this.observers=[],this.revocable=Proxy.revocable(s,this),this.proxy=this.revocable.proxy,this.target=s,this.options=this.processOptions(t.options),this.options.async&&(this.batches=[])}processOptions(t){if(t){if("object"!=typeof t)throw new Error(`Observable options if/when provided, MAY only be an object, got '${t}'`);const e=Object.keys(t).filter((t=>!(t in d)));if(e.length)throw new Error(`'${e.join(", ")}' is/are not a valid Observable option/s`);return Object.assign({},t)}return{}}detach(){return this.parent=null,this.target}set(t,e,n){let r=t[e];if(n!==r){const o=O(n,e,this);if(t[e]=o,r&&"object"==typeof r){const t=r[y];t&&(r=t.detach())}const s=void 0===r?[new K(h,[e],o,void 0,this.proxy)]:[new K(l,[e],o,r,this.proxy)];x(this,s)}return!0}deleteProperty(t,e){let n=t[e];if(delete t[e],n&&"object"==typeof n){const t=n[y];t&&(n=t.detach())}const r=[new K(p,[e],void 0,n,this.proxy)];return x(this,r),!0}}class P extends N{constructor(t){super(t,v)}}class T extends N{constructor(t){super(t,w)}get(t,e){return k[e]||t[e]}}class $ extends N{constructor(t){super(t,g)}get(t,e){return H[e]||t[e]}}const z=Object.freeze({from:(t,e)=>{if(t&&"object"==typeof t){if(t[y])return t;if(Array.isArray(t))return new T({target:t,ownKey:null,parent:null,options:e}).proxy;if(ArrayBuffer.isView(t))return new $({target:t,ownKey:null,parent:null,options:e}).proxy;if(t instanceof Date)throw new Error(`${t} found to be one of a non-observable types`);return new P({target:t,ownKey:null,parent:null,options:e}).proxy}throw new Error("observable MAY ONLY be created from a non-null object")},isObservable:t=>!(!t||!t[y]),observe:(t,e,n)=>{if(!z.isObservable(t))throw new Error("invalid observable parameter");if("function"!=typeof e)throw new Error(`observer MUST be a function, got '${e}'`);const r=t[y].observers;r.some((t=>t[0]===e))?console.warn("observer may be bound to an observable only once; will NOT rebind"):r.push([e,b(n)])},unobserve:(t,...e)=>{if(!z.isObservable(t))throw new Error("invalid observable parameter");const n=t[y].observers;let r=n.length;if(r)if(e.length)for(;r;){e.indexOf(n[--r][0])>=0&&n.splice(r,1)}else n.splice(0)}});var Z=function(){var t=this;this.on=function(e,n){return t.handlers[e]=t.handlers[e]||[],t.handlers[e].push(n),t},this.off=function(e,n){var r=t.handlers[e];if(r)for(var o=0;o<r.length;o++)r[o]===n&&r.splice(o,1);return t},this.callEmitFromMT=function(){this.func.apply(null,this.args?this.args:[])},this.emit=function(e,n){if(t.handlers[e])for(var r=0;r<t.handlers[e].length;r++)try{queueMicrotask(t.callEmitFromMT.bind({func:t.handlers[e][r],args:n}))}catch(t){console.log(t)}return t},this.clear=function(){t.handlers={}},this.handlers={}},F=function(t){function e(e){var n=t.call(this)||this;return Object.keys(e.property).forEach((function(t){n.on(t,(function(n){try{e.property[t].apply(e.state,[n])}catch(t){console.log(t)}}))})),n}return s(e,t),e}(Z),R=function(t){function e(e,n,r){var o,s,h=this;return(h=t.call(this)||this).middlewares=[],h._sendHistory=[],h._componentName="Unknown",h.watch=function(t){return a(h,void 0,void 0,(function(){var e,n,r=this;return c(this,(function(o){switch(o.label){case 0:return e=performance.now(),[4,this.executeMiddlewares(t,(function(){for(var e,n=function(t){var n=t.path.filter((function(t){return"number"!=typeof t}));if(null===(e=r._options)||void 0===e?void 0:e.deep){var o="";n.forEach((function(e){o+=e+".",r.emit(o.substring(0,o.length-1),[t.object])}))}else{var s=n.join(".");r.emit(s,[t.object])}},o=0,s=t;o<s.length;o++){n(s[o])}}))];case 1:return o.sent(),"development"===process.env.NODE_ENV&&(n=performance.now()-e)>33.34&&console.warn("[x-view-model] Slow state update detected (".concat(n.toFixed(2),"ms)"),t),[2]}}))}))},h._property=e,h._options=n,h._reference=0,h._observable=z.from(i({},h._property),{async:!0}),h._started=!1,h.services=new F(h),h._historyHandler=(null===(o=null==n?void 0:n.history)||void 0===o?void 0:o.handler)||function(){},h._historyMaxSize=(null===(s=null==n?void 0:n.history)||void 0===s?void 0:s.maxSize)||100,h.middlewares=(null==n?void 0:n.middlewares)||[],h.devTools=r,h}return s(e,t),e.prototype.use=function(t){return this.middlewares.push(t),this},e.prototype.executeMiddlewares=function(t,e){return a(this,void 0,void 0,(function(){var n=this;return c(this,(function(r){switch(r.label){case 0:return 0===this.middlewares.length?(e(),[2]):[4,this.middlewares.reduceRight((function(e,r){return function(){return r(t,e,n.state)}}),e)()];case 1:return r.sent(),[2]}}))}))},Object.defineProperty(e.prototype,"state",{get:function(){return this._observable},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"property",{get:function(){return this._property},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"reference",{get:function(){return this._reference},set:function(t){this._reference=t,this._reference>0?this.start():this.stop()},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"name",{get:function(){return this._options&&this._options.name?this._options.name:"unnamed"},enumerable:!1,configurable:!0}),e.prototype.increaseReference=function(){this.reference++},e.prototype.decreaseReference=function(){this.reference--},e.prototype.start=function(){if(!this._started)return z.observe(this._observable,this.watch),console.log(this.name,"started"),this._started=!0,this},e.prototype.stop=function(){if(this._started)return z.unobserve(this._observable),this._observable=z.from(i({},this._property)),this._started=!1,this},e.prototype.pause=function(){if(this._started)return z.unobserve(this._observable),this},e.prototype.restart=function(){return z.unobserve(this._observable),this._observable=z.from(i({},this._property)),z.observe(this._observable,this.watch),console.log(this.name,"started"),this._started=!0,this},e.prototype.snapshot=function(){this.pause();var t=JSON.stringify(this._observable);return this.start(),t},e.prototype.rebase=function(t){var e="string"==typeof t?JSON.parse(t):t;return this._property=i(i({},this._property),e),this},e.prototype.restore=function(t){this.pause();var e="string"==typeof t?JSON.parse(t):t;return this._observable=z.from(i(i({},this._property),e)),this.start(),this},e.prototype.addHistory=function(t){return a(this,void 0,void 0,(function(){return c(this,(function(e){switch(e.label){case 0:return this._historyHandler?[4,Promise.resolve(this._historyHandler(t,this.state))]:[3,2];case 1:e.sent(),e.label=2;case 2:return this._sendHistory.push(t),this._sendHistory.length>this._historyMaxSize&&(this._sendHistory=this._sendHistory.slice(-this._historyMaxSize)),[2]}}))}))},e.prototype.send=function(t,e,n){return void 0===n&&(n=!1),a(this,void 0,void 0,(function(){var r,o,s;return c(this,(function(i){switch(i.label){case 0:if(r={name:t,componentName:this._componentName,payload:e,timestamp:Date.now()},!n)return[3,7];i.label=1;case 1:return i.trys.push([1,4,,6]),[4,this.property[t].apply(this.state,[e])];case 2:return o=i.sent(),r.result=o,[4,this.addHistory(r)];case 3:return i.sent(),[2,o];case 4:return s=i.sent(),r.error=s,[4,this.addHistory(r)];case 5:throw i.sent(),s;case 6:return[3,9];case 7:return this.services.emit(t,[e]),[4,this.addHistory(r)];case 8:return i.sent(),[2,void 0];case 9:return[2]}}))}))},e.prototype.getSendHistory=function(){return this._sendHistory},e.prototype.clearSendHistory=function(){this._sendHistory=[]},e}(Z),U=function(){function t(){this.state={components:new Map}}return t.prototype.components=function(){return this.state.components},t.prototype.registerComponent=function(t,e,n){var r;if(void 0===n&&(n=[]),this.state.components.has(t)){var o=this.state.components.get(t);o&&!o[e]&&(o[e]={enabled:!1,paths:n})}else{var s=((r={})[e]={enabled:!1,paths:n},r);this.state.components.set(t,s)}},t}(),V=new U,Y=function(t,e,n){return{context:new R(t,e),ref:n||void 0}},D=function(){if("development"!==process.env.NODE_ENV)return{name:"Unknown",paths:[]};try{throw new Error}catch(y){if(!(y instanceof Error))return{name:"Unknown",paths:[]};for(var t=y.stack||"",e=t.split("\n"),n="Anonymous",r=[],o=[/at ([A-Z][A-Za-z0-9_$]*) \(/,/at ([A-Z][A-Za-z0-9_$]*)\s/,/\.(jsx|tsx|js|ts):(\d+).*\s([A-Z][A-Za-z0-9_$]*)/],s=2;s<Math.min(e.length,8);s++){for(var i=e[s],a=0,c=o;a<c.length;a++){var h=c[a],l=i.match(h);if(l&&l[1]){var p=i.match(/\((.+?):\d+:\d+\)/);if(p&&p[1]){var f=p[1].replace(/^(file:\/\/\/|\/)[A-Za-z]:\//,"").split(/[\/\\]/).filter(Boolean);f.length>0&&/\.(jsx|tsx|js|ts)$/.test(f[f.length-1])&&f.pop(),r.push.apply(r,f)}n=l[1];break}}if("Anonymous"!==n)break}if("Anonymous"===n){var u=t.match(/\/([A-Z][A-Za-z0-9_$]*)\.(jsx|tsx|js|ts)/);u&&u[1]&&(n=u[1])}return{name:n,paths:r}}},W=function(o,s,i){i||(i=n((function(){return D()}),[])),V.registerComponent(o.context,i.name,i.paths);var a=function(o,s){var i=t(0);i[0];var a=i[1],c=e((function(t){a((function(t){return t+1}))}),[]);return n((function(){s.increaseReference(),Array.isArray(o)?o.forEach((function(t){s.on(t,c)})):s.on(o,c)}),[s]),r((function(){return function(){s.decreaseReference(),Array.isArray(o)?o.forEach((function(t){s.off(t,c)})):s.off(o,c)}}),[s]),s.state}(s,o.context);return[a,o.context.send.bind(Object.assign(o.context,{_componentName:i.name,_componentPaths:i.paths})),o.ref]},B=function(t,e,r){var o=n((function(){return D()}),[]),s=W(t,r,o),i=s[0],a=s[1],c=s[2];return[n((function(){return e(i)}),[i,e]),a,c]},C=function(t,e){var r=n((function(){return D()}),[]),o=W(t,e,r);return[o[0],o[1],o[2]]};export{U as DevToolsHandler,V as devTools,Y as registViewModel,B as useComputedViewModel,C as useMemoizedViewModel,W as useViewModel};
//# sourceMappingURL=index.esm.min.js.map