├── .gitignore ├── README.md ├── docs ├── .nojekyll ├── assets │ ├── highlight.css │ ├── main.js │ ├── search.js │ ├── style.css │ ├── widgets.png │ └── widgets@2x.png ├── functions │ ├── createCachedResource.html │ ├── createMutation.html │ ├── mutateCachedValue.html │ └── refetchResourceForKey.html ├── index.html ├── interfaces │ ├── CachedResourceOptions.html │ └── CreateMutationOptions.html └── modules.html ├── example └── MyComp.tsx ├── package.json ├── src ├── cache.ts ├── index.ts └── utils.ts ├── test ├── index.test.tsx └── setup.ts ├── tsconfig.json └── vitest.config.ts /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | dist 3 | node_modules 4 | pnpm-lock.yaml 5 | .pnpm-debug.log 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![NPM Version](https://img.shields.io/npm/v/solid-cached-resource) ![npm bundle size](https://img.shields.io/bundlephobia/min/solid-cached-resource) ![NPM License](https://img.shields.io/npm/l/solid-cached-resource) 2 | 3 | # Solid Cached Resource 4 | 5 | Inspired by TanStack Query, with minimal API and footprint, built only for SolidJS. 6 | The (almost) same API as [createResource](https://www.solidjs.com/docs/latest/api#createresource). 7 | Includes `createMutation` for easier mutation state handling. 8 | 9 | [API references](https://yonathan06.github.io/solid-cached-resource/) 10 | 11 | Features: 12 | 13 | - Create resource with the same key in multiple places - fetch once 14 | - Cache results for next component mount, and refresh when wanted 15 | - Mutate local resource by key after a successful remote mutation request 16 | 17 | ## install 18 | 19 | ```sh 20 | pnpm add solid-cached-resource 21 | ``` 22 | 23 | or `npm`/`yarn` 24 | 25 | ## createCachedResource 26 | 27 | Inspired by [useQuery](https://react-query.tanstack.com/guides/queries) just for Solid `createResource` 28 | 29 | ```TypeScript 30 | import { createCachedResource } from "solid-cached-resource"; 31 | 32 | export const createGetUserById = (userId: Accessor) => { 33 | return createCachedResource( 34 | () => ["user", userId()], 35 | async ([, userId]) => { 36 | const response = await fetch(`/users/${userId}`); 37 | return response.json(); 38 | }); 39 | } 40 | 41 | // MyComp.tsx 42 | const [user] = createGetUserById(() => props.userId); 43 | 44 |
{user().name}
45 | 46 | // MyOtherComp.tsx 47 | const [user] = createGetUserById(() => props.userId); 48 | 49 | {user().name} 50 | ``` 51 | 52 | In the case above, if `props.userId` has the same value, the key will be the same, so even though both components are creating the same resource with the same fetcher, only one request will be made to the server. 53 | 54 | ### With options 55 | 56 | `createCachedResource` accepts an optional [options](https://yonathan06.github.io/solid-cached-resource/interfaces/CachedResourceOptions.html) object as its third argument 57 | 58 | ```TypeScript 59 | { 60 | initialValue?: T (default undefined) 61 | refetchOnMount?: boolean (default true) 62 | } 63 | ``` 64 | 65 | ## createMutations 66 | 67 | Inspired by [useMutation](https://react-query.tanstack.com/guides/mutations), with onSuccess hook, and `mutateCachedValue` utility function. 68 | 69 | ```TypeScript 70 | import { 71 | mutateCachedValue, 72 | createMutation, 73 | } from "solid-cached-resource"; 74 | 75 | export const createUpdateUser = (userId: Accessor) => { 76 | return createMutation(async (values) => { 77 | const response = fetch(`user/${userId()}`, { 78 | method: "POST", 79 | body: values, 80 | }); 81 | return await response.json() 82 | }, { 83 | onSuccess: (user) => { 84 | mutateCachedValue(() => ["user", userId()], user); 85 | } 86 | }); 87 | } 88 | ``` 89 | 90 | `mutateCachedValue` will call the resources' `mutate` function with the provided key, so the signals will be updated across your components. 91 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /docs/assets/highlight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --light-hl-0: #000000; 3 | --dark-hl-0: #D4D4D4; 4 | --light-hl-1: #AF00DB; 5 | --dark-hl-1: #C586C0; 6 | --light-hl-2: #001080; 7 | --dark-hl-2: #9CDCFE; 8 | --light-hl-3: #A31515; 9 | --dark-hl-3: #CE9178; 10 | --light-hl-4: #0000FF; 11 | --dark-hl-4: #569CD6; 12 | --light-hl-5: #795E26; 13 | --dark-hl-5: #DCDCAA; 14 | --light-hl-6: #267F99; 15 | --dark-hl-6: #4EC9B0; 16 | --light-hl-7: #0070C1; 17 | --dark-hl-7: #4FC1FF; 18 | --light-hl-8: #008000; 19 | --dark-hl-8: #6A9955; 20 | --light-hl-9: #000000FF; 21 | --dark-hl-9: #D4D4D4; 22 | --light-code-background: #FFFFFF; 23 | --dark-code-background: #1E1E1E; 24 | } 25 | 26 | @media (prefers-color-scheme: light) { :root { 27 | --hl-0: var(--light-hl-0); 28 | --hl-1: var(--light-hl-1); 29 | --hl-2: var(--light-hl-2); 30 | --hl-3: var(--light-hl-3); 31 | --hl-4: var(--light-hl-4); 32 | --hl-5: var(--light-hl-5); 33 | --hl-6: var(--light-hl-6); 34 | --hl-7: var(--light-hl-7); 35 | --hl-8: var(--light-hl-8); 36 | --hl-9: var(--light-hl-9); 37 | --code-background: var(--light-code-background); 38 | } } 39 | 40 | @media (prefers-color-scheme: dark) { :root { 41 | --hl-0: var(--dark-hl-0); 42 | --hl-1: var(--dark-hl-1); 43 | --hl-2: var(--dark-hl-2); 44 | --hl-3: var(--dark-hl-3); 45 | --hl-4: var(--dark-hl-4); 46 | --hl-5: var(--dark-hl-5); 47 | --hl-6: var(--dark-hl-6); 48 | --hl-7: var(--dark-hl-7); 49 | --hl-8: var(--dark-hl-8); 50 | --hl-9: var(--dark-hl-9); 51 | --code-background: var(--dark-code-background); 52 | } } 53 | 54 | :root[data-theme='light'] { 55 | --hl-0: var(--light-hl-0); 56 | --hl-1: var(--light-hl-1); 57 | --hl-2: var(--light-hl-2); 58 | --hl-3: var(--light-hl-3); 59 | --hl-4: var(--light-hl-4); 60 | --hl-5: var(--light-hl-5); 61 | --hl-6: var(--light-hl-6); 62 | --hl-7: var(--light-hl-7); 63 | --hl-8: var(--light-hl-8); 64 | --hl-9: var(--light-hl-9); 65 | --code-background: var(--light-code-background); 66 | } 67 | 68 | :root[data-theme='dark'] { 69 | --hl-0: var(--dark-hl-0); 70 | --hl-1: var(--dark-hl-1); 71 | --hl-2: var(--dark-hl-2); 72 | --hl-3: var(--dark-hl-3); 73 | --hl-4: var(--dark-hl-4); 74 | --hl-5: var(--dark-hl-5); 75 | --hl-6: var(--dark-hl-6); 76 | --hl-7: var(--dark-hl-7); 77 | --hl-8: var(--dark-hl-8); 78 | --hl-9: var(--dark-hl-9); 79 | --code-background: var(--dark-code-background); 80 | } 81 | 82 | .hl-0 { color: var(--hl-0); } 83 | .hl-1 { color: var(--hl-1); } 84 | .hl-2 { color: var(--hl-2); } 85 | .hl-3 { color: var(--hl-3); } 86 | .hl-4 { color: var(--hl-4); } 87 | .hl-5 { color: var(--hl-5); } 88 | .hl-6 { color: var(--hl-6); } 89 | .hl-7 { color: var(--hl-7); } 90 | .hl-8 { color: var(--hl-8); } 91 | .hl-9 { color: var(--hl-9); } 92 | pre, code { background: var(--code-background); } 93 | -------------------------------------------------------------------------------- /docs/assets/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | (()=>{var Qe=Object.create;var ae=Object.defineProperty;var Pe=Object.getOwnPropertyDescriptor;var Ce=Object.getOwnPropertyNames;var Oe=Object.getPrototypeOf,Re=Object.prototype.hasOwnProperty;var _e=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Me=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Ce(e))!Re.call(t,i)&&i!==n&&ae(t,i,{get:()=>e[i],enumerable:!(r=Pe(e,i))||r.enumerable});return t};var De=(t,e,n)=>(n=t!=null?Qe(Oe(t)):{},Me(e||!t||!t.__esModule?ae(n,"default",{value:t,enumerable:!0}):n,t));var de=_e((ce,he)=>{(function(){var t=function(e){var n=new t.Builder;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),n.searchPipeline.add(t.stemmer),e.call(n,n),n.build()};t.version="2.3.9";t.utils={},t.utils.warn=function(e){return function(n){e.console&&console.warn&&console.warn(n)}}(this),t.utils.asString=function(e){return e==null?"":e.toString()},t.utils.clone=function(e){if(e==null)return e;for(var n=Object.create(null),r=Object.keys(e),i=0;i0){var h=t.utils.clone(n)||{};h.position=[a,l],h.index=s.length,s.push(new t.Token(r.slice(a,o),h))}a=o+1}}return s},t.tokenizer.separator=/[\s\-]+/;t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions=Object.create(null),t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn(`Function is not registered with pipeline. This may cause problems when serialising the index. 3 | `,e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(r){var i=t.Pipeline.registeredFunctions[r];if(i)n.add(i);else throw new Error("Cannot load unregistered function: "+r)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(n){t.Pipeline.warnIfFunctionNotRegistered(n),this._stack.push(n)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");r=r+1,this._stack.splice(r,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");this._stack.splice(r,0,n)},t.Pipeline.prototype.remove=function(e){var n=this._stack.indexOf(e);n!=-1&&this._stack.splice(n,1)},t.Pipeline.prototype.run=function(e){for(var n=this._stack.length,r=0;r1&&(oe&&(r=s),o!=e);)i=r-n,s=n+Math.floor(i/2),o=this.elements[s*2];if(o==e||o>e)return s*2;if(ou?h+=2:a==u&&(n+=r[l+1]*i[h+1],l+=2,h+=2);return n},t.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},t.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),n=1,r=0;n0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new t.TokenSet;s.node.edges["*"]=u}if(s.str.length==0&&(u.final=!0),i.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new t.TokenSet;s.node.edges["*"]=l}s.str.length==1&&(l.final=!0),i.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var h=s.str.charAt(0),m=s.str.charAt(1),v;m in s.node.edges?v=s.node.edges[m]:(v=new t.TokenSet,s.node.edges[m]=v),s.str.length==1&&(v.final=!0),i.push({node:v,editsRemaining:s.editsRemaining-1,str:h+s.str.slice(2)})}}}return r},t.TokenSet.fromString=function(e){for(var n=new t.TokenSet,r=n,i=0,s=e.length;i=e;n--){var r=this.uncheckedNodes[n],i=r.child.toString();i in this.minimizedNodes?r.parent.edges[r.char]=this.minimizedNodes[i]:(r.child._str=i,this.minimizedNodes[i]=r.child),this.uncheckedNodes.pop()}};t.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},t.Index.prototype.search=function(e){return this.query(function(n){var r=new t.QueryParser(e,n);r.parse()})},t.Index.prototype.query=function(e){for(var n=new t.Query(this.fields),r=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),u=0;u1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,n){var r=e[this._ref],i=Object.keys(this._fields);this._documents[r]=n||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,n;do e=this.next(),n=e.charCodeAt(0);while(n>47&&n<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var n=e.next();if(n==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(n.charCodeAt(0)==92){e.escapeCharacter();continue}if(n==":")return t.QueryLexer.lexField;if(n=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(n=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(n=="+"&&e.width()===1||n=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(n.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,n){this.lexer=new t.QueryLexer(e),this.query=n,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var n=e.peekLexeme();if(n!=null)switch(n.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expected either a field or a term, found "+n.type;throw n.str.length>=1&&(r+=" with value '"+n.str+"'"),new t.QueryParseError(r,n.start,n.end)}},t.QueryParser.parsePresence=function(e){var n=e.consumeLexeme();if(n!=null){switch(n.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var r="unrecognised presence operator'"+n.str+"'";throw new t.QueryParseError(r,n.start,n.end)}var i=e.peekLexeme();if(i==null){var r="expecting term or field, found nothing";throw new t.QueryParseError(r,n.start,n.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(r,i.start,i.end)}}},t.QueryParser.parseField=function(e){var n=e.consumeLexeme();if(n!=null){if(e.query.allFields.indexOf(n.str)==-1){var r=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+n.str+"', possible fields: "+r;throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.fields=[n.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,n.start,n.end)}switch(s.type){case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseTerm=function(e){var n=e.consumeLexeme();if(n!=null){e.currentClause.term=n.str.toLowerCase(),n.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var r=e.peekLexeme();if(r==null){e.nextClause();return}switch(r.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+r.type+"'";throw new t.QueryParseError(i,r.start,r.end)}}},t.QueryParser.parseEditDistance=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="edit distance must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.editDistance=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="boost must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.boost=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},function(e,n){typeof define=="function"&&define.amd?define(n):typeof ce=="object"?he.exports=n():e.lunr=n()}(this,function(){return t})})()});var le=[];function j(t,e){le.push({selector:e,constructor:t})}var Y=class{constructor(){this.createComponents(document.body)}createComponents(e){le.forEach(n=>{e.querySelectorAll(n.selector).forEach(r=>{r.dataset.hasInstance||(new n.constructor({el:r}),r.dataset.hasInstance=String(!0))})})}};var k=class{constructor(e){this.el=e.el}};var J=class{constructor(){this.listeners={}}addEventListener(e,n){e in this.listeners||(this.listeners[e]=[]),this.listeners[e].push(n)}removeEventListener(e,n){if(!(e in this.listeners))return;let r=this.listeners[e];for(let i=0,s=r.length;i{let n=Date.now();return(...r)=>{n+e-Date.now()<0&&(t(...r),n=Date.now())}};var re=class extends J{constructor(){super();this.scrollTop=0;this.lastY=0;this.width=0;this.height=0;this.showToolbar=!0;this.toolbar=document.querySelector(".tsd-page-toolbar"),this.navigation=document.querySelector(".col-menu"),window.addEventListener("scroll",ne(()=>this.onScroll(),10)),window.addEventListener("resize",ne(()=>this.onResize(),10)),this.searchInput=document.querySelector("#tsd-search input"),this.searchInput&&this.searchInput.addEventListener("focus",()=>{this.hideShowToolbar()}),this.onResize(),this.onScroll()}triggerResize(){let n=new CustomEvent("resize",{detail:{width:this.width,height:this.height}});this.dispatchEvent(n)}onResize(){this.width=window.innerWidth||0,this.height=window.innerHeight||0;let n=new CustomEvent("resize",{detail:{width:this.width,height:this.height}});this.dispatchEvent(n)}onScroll(){this.scrollTop=window.scrollY||0;let n=new CustomEvent("scroll",{detail:{scrollTop:this.scrollTop}});this.dispatchEvent(n),this.hideShowToolbar()}hideShowToolbar(){let n=this.showToolbar;this.showToolbar=this.lastY>=this.scrollTop||this.scrollTop<=0||!!this.searchInput&&this.searchInput===document.activeElement,n!==this.showToolbar&&(this.toolbar.classList.toggle("tsd-page-toolbar--hide"),this.navigation?.classList.toggle("col-menu--hide")),this.lastY=this.scrollTop}},R=re;R.instance=new re;var X=class extends k{constructor(n){super(n);this.anchors=[];this.index=-1;R.instance.addEventListener("resize",()=>this.onResize()),R.instance.addEventListener("scroll",r=>this.onScroll(r)),this.createAnchors()}createAnchors(){let n=window.location.href;n.indexOf("#")!=-1&&(n=n.substring(0,n.indexOf("#"))),this.el.querySelectorAll("a").forEach(r=>{let i=r.href;if(i.indexOf("#")==-1||i.substring(0,n.length)!=n)return;let s=i.substring(i.indexOf("#")+1),o=document.querySelector("a.tsd-anchor[name="+s+"]"),a=r.parentNode;!o||!a||this.anchors.push({link:a,anchor:o,position:0})}),this.onResize()}onResize(){let n;for(let i=0,s=this.anchors.length;ii.position-s.position);let r=new CustomEvent("scroll",{detail:{scrollTop:R.instance.scrollTop}});this.onScroll(r)}onScroll(n){let r=n.detail.scrollTop+5,i=this.anchors,s=i.length-1,o=this.index;for(;o>-1&&i[o].position>r;)o-=1;for(;o-1&&this.anchors[this.index].link.classList.remove("focus"),this.index=o,this.index>-1&&this.anchors[this.index].link.classList.add("focus"))}};var ue=(t,e=100)=>{let n;return(...r)=>{clearTimeout(n),n=setTimeout(()=>t(r),e)}};var me=De(de());function ve(){let t=document.getElementById("tsd-search");if(!t)return;let e=document.getElementById("search-script");t.classList.add("loading"),e&&(e.addEventListener("error",()=>{t.classList.remove("loading"),t.classList.add("failure")}),e.addEventListener("load",()=>{t.classList.remove("loading"),t.classList.add("ready")}),window.searchData&&t.classList.remove("loading"));let n=document.querySelector("#tsd-search input"),r=document.querySelector("#tsd-search .results");if(!n||!r)throw new Error("The input field or the result list wrapper was not found");let i=!1;r.addEventListener("mousedown",()=>i=!0),r.addEventListener("mouseup",()=>{i=!1,t.classList.remove("has-focus")}),n.addEventListener("focus",()=>t.classList.add("has-focus")),n.addEventListener("blur",()=>{i||(i=!1,t.classList.remove("has-focus"))});let s={base:t.dataset.base+"/"};Fe(t,r,n,s)}function Fe(t,e,n,r){n.addEventListener("input",ue(()=>{Ae(t,e,n,r)},200));let i=!1;n.addEventListener("keydown",s=>{i=!0,s.key=="Enter"?Ve(e,n):s.key=="Escape"?n.blur():s.key=="ArrowUp"?fe(e,-1):s.key==="ArrowDown"?fe(e,1):i=!1}),n.addEventListener("keypress",s=>{i&&s.preventDefault()}),document.body.addEventListener("keydown",s=>{s.altKey||s.ctrlKey||s.metaKey||!n.matches(":focus")&&s.key==="/"&&(n.focus(),s.preventDefault())})}function He(t,e){t.index||window.searchData&&(e.classList.remove("loading"),e.classList.add("ready"),t.data=window.searchData,t.index=me.Index.load(window.searchData.index))}function Ae(t,e,n,r){if(He(r,t),!r.index||!r.data)return;e.textContent="";let i=n.value.trim(),s=i?r.index.search(`*${i}*`):[];for(let o=0;oa.score-o.score);for(let o=0,a=Math.min(10,s.length);o${pe(u.parent,i)}.${l}`);let h=document.createElement("li");h.classList.value=u.classes??"";let m=document.createElement("a");m.href=r.base+u.url,m.innerHTML=l,h.append(m),e.appendChild(h)}}function fe(t,e){let n=t.querySelector(".current");if(!n)n=t.querySelector(e==1?"li:first-child":"li:last-child"),n&&n.classList.add("current");else{let r=n;if(e===1)do r=r.nextElementSibling??void 0;while(r instanceof HTMLElement&&r.offsetParent==null);else do r=r.previousElementSibling??void 0;while(r instanceof HTMLElement&&r.offsetParent==null);r&&(n.classList.remove("current"),r.classList.add("current"))}}function Ve(t,e){let n=t.querySelector(".current");if(n||(n=t.querySelector("li:first-child")),n){let r=n.querySelector("a");r&&(window.location.href=r.href),e.blur()}}function pe(t,e){if(e==="")return t;let n=t.toLocaleLowerCase(),r=e.toLocaleLowerCase(),i=[],s=0,o=n.indexOf(r);for(;o!=-1;)i.push(ie(t.substring(s,o)),`${ie(t.substring(o,o+r.length))}`),s=o+r.length,o=n.indexOf(r,s);return i.push(ie(t.substring(s))),i.join("")}var Ne={"&":"&","<":"<",">":">","'":"'",'"':"""};function ie(t){return t.replace(/[&<>"'"]/g,e=>Ne[e])}var F="mousedown",ye="mousemove",B="mouseup",Z={x:0,y:0},ge=!1,se=!1,je=!1,H=!1,xe=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);document.documentElement.classList.add(xe?"is-mobile":"not-mobile");xe&&"ontouchstart"in document.documentElement&&(je=!0,F="touchstart",ye="touchmove",B="touchend");document.addEventListener(F,t=>{se=!0,H=!1;let e=F=="touchstart"?t.targetTouches[0]:t;Z.y=e.pageY||0,Z.x=e.pageX||0});document.addEventListener(ye,t=>{if(!!se&&!H){let e=F=="touchstart"?t.targetTouches[0]:t,n=Z.x-(e.pageX||0),r=Z.y-(e.pageY||0);H=Math.sqrt(n*n+r*r)>10}});document.addEventListener(B,()=>{se=!1});document.addEventListener("click",t=>{ge&&(t.preventDefault(),t.stopImmediatePropagation(),ge=!1)});var K=class extends k{constructor(n){super(n);this.className=this.el.dataset.toggle||"",this.el.addEventListener(B,r=>this.onPointerUp(r)),this.el.addEventListener("click",r=>r.preventDefault()),document.addEventListener(F,r=>this.onDocumentPointerDown(r)),document.addEventListener(B,r=>this.onDocumentPointerUp(r))}setActive(n){if(this.active==n)return;this.active=n,document.documentElement.classList.toggle("has-"+this.className,n),this.el.classList.toggle("active",n);let r=(this.active?"to-has-":"from-has-")+this.className;document.documentElement.classList.add(r),setTimeout(()=>document.documentElement.classList.remove(r),500)}onPointerUp(n){H||(this.setActive(!0),n.preventDefault())}onDocumentPointerDown(n){if(this.active){if(n.target.closest(".col-menu, .tsd-filter-group"))return;this.setActive(!1)}}onDocumentPointerUp(n){if(!H&&this.active&&n.target.closest(".col-menu")){let r=n.target.closest("a");if(r){let i=window.location.href;i.indexOf("#")!=-1&&(i=i.substring(0,i.indexOf("#"))),r.href.substring(0,i.length)==i&&setTimeout(()=>this.setActive(!1),250)}}}};var oe;try{oe=localStorage}catch{oe={getItem(){return null},setItem(){}}}var Q=oe;var Le=document.head.appendChild(document.createElement("style"));Le.dataset.for="filters";var ee=class extends k{constructor(n){super(n);this.key=`filter-${this.el.name}`,this.value=this.el.checked,this.el.addEventListener("change",()=>{this.setLocalStorage(this.el.checked)}),this.setLocalStorage(this.fromLocalStorage()),Le.innerHTML+=`html:not(.${this.key}) .tsd-is-${this.el.name} { display: none; } 4 | `}fromLocalStorage(){let n=Q.getItem(this.key);return n?n==="true":this.el.checked}setLocalStorage(n){Q.setItem(this.key,n.toString()),this.value=n,this.handleValueChange()}handleValueChange(){this.el.checked=this.value,document.documentElement.classList.toggle(this.key,this.value),document.querySelectorAll(".tsd-index-section").forEach(n=>{n.style.display="block";let r=Array.from(n.querySelectorAll(".tsd-index-link")).every(i=>i.offsetParent==null);n.style.display=r?"none":"block"})}};var te=class extends k{constructor(n){super(n);this.calculateHeights(),this.summary=this.el.querySelector(".tsd-accordion-summary"),this.icon=this.summary.querySelector("svg"),this.key=`tsd-accordion-${this.summary.textContent.replace(/\s+/g,"-").toLowerCase()}`,this.setLocalStorage(this.fromLocalStorage(),!0),this.summary.addEventListener("click",r=>this.toggleVisibility(r)),this.icon.style.transform=this.getIconRotation()}getIconRotation(n=this.el.open){return`rotate(${n?0:-90}deg)`}calculateHeights(){let n=this.el.open,{position:r,left:i}=this.el.style;this.el.style.position="fixed",this.el.style.left="-9999px",this.el.open=!0,this.expandedHeight=this.el.offsetHeight+"px",this.el.open=!1,this.collapsedHeight=this.el.offsetHeight+"px",this.el.open=n,this.el.style.height=n?this.expandedHeight:this.collapsedHeight,this.el.style.position=r,this.el.style.left=i}toggleVisibility(n){n.preventDefault(),this.el.style.overflow="hidden",this.el.open?this.collapse():this.expand()}expand(n=!0){this.el.open=!0,this.animate(this.collapsedHeight,this.expandedHeight,{opening:!0,duration:n?300:0})}collapse(n=!0){this.animate(this.expandedHeight,this.collapsedHeight,{opening:!1,duration:n?300:0})}animate(n,r,{opening:i,duration:s=300}){if(this.animation)return;let o={duration:s,easing:"ease"};this.animation=this.el.animate({height:[n,r]},o),this.icon.animate({transform:[this.icon.style.transform||this.getIconRotation(!i),this.getIconRotation(i)]},o).addEventListener("finish",()=>{this.icon.style.transform=this.getIconRotation(i)}),this.animation.addEventListener("finish",()=>this.animationEnd(i))}animationEnd(n){this.el.open=n,this.animation=void 0,this.el.style.height="auto",this.el.style.overflow="visible",this.setLocalStorage(n)}fromLocalStorage(){let n=Q.getItem(this.key);return n?n==="true":this.el.open}setLocalStorage(n,r=!1){this.fromLocalStorage()===n&&!r||(Q.setItem(this.key,n.toString()),this.el.open=n,this.handleValueChange(r))}handleValueChange(n=!1){this.fromLocalStorage()===this.el.open&&!n||(this.fromLocalStorage()?this.expand(!1):this.collapse(!1))}};function be(t){let e=Q.getItem("tsd-theme")||"os";t.value=e,Ee(e),t.addEventListener("change",()=>{Q.setItem("tsd-theme",t.value),Ee(t.value)})}function Ee(t){document.documentElement.dataset.theme=t}ve();j(X,".menu-highlight");j(K,"a[data-toggle]");j(te,".tsd-index-accordion");j(ee,".tsd-filter-item input[type=checkbox]");var Se=document.getElementById("theme");Se&&be(Se);var Be=new Y;Object.defineProperty(window,"app",{value:Be});})(); 5 | /*! 6 | * lunr.Builder 7 | * Copyright (C) 2020 Oliver Nightingale 8 | */ 9 | /*! 10 | * lunr.Index 11 | * Copyright (C) 2020 Oliver Nightingale 12 | */ 13 | /*! 14 | * lunr.Pipeline 15 | * Copyright (C) 2020 Oliver Nightingale 16 | */ 17 | /*! 18 | * lunr.Set 19 | * Copyright (C) 2020 Oliver Nightingale 20 | */ 21 | /*! 22 | * lunr.TokenSet 23 | * Copyright (C) 2020 Oliver Nightingale 24 | */ 25 | /*! 26 | * lunr.Vector 27 | * Copyright (C) 2020 Oliver Nightingale 28 | */ 29 | /*! 30 | * lunr.stemmer 31 | * Copyright (C) 2020 Oliver Nightingale 32 | * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt 33 | */ 34 | /*! 35 | * lunr.stopWordFilter 36 | * Copyright (C) 2020 Oliver Nightingale 37 | */ 38 | /*! 39 | * lunr.tokenizer 40 | * Copyright (C) 2020 Oliver Nightingale 41 | */ 42 | /*! 43 | * lunr.trimmer 44 | * Copyright (C) 2020 Oliver Nightingale 45 | */ 46 | /*! 47 | * lunr.utils 48 | * Copyright (C) 2020 Oliver Nightingale 49 | */ 50 | /** 51 | * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 52 | * Copyright (C) 2020 Oliver Nightingale 53 | * @license MIT 54 | */ 55 | -------------------------------------------------------------------------------- /docs/assets/search.js: -------------------------------------------------------------------------------- 1 | window.searchData = JSON.parse("{\"kinds\":{\"64\":\"Function\",\"256\":\"Interface\",\"1024\":\"Property\",\"65536\":\"Type literal\"},\"rows\":[{\"kind\":64,\"name\":\"createCachedResource\",\"url\":\"functions/createCachedResource.html\",\"classes\":\"tsd-kind-function\"},{\"kind\":64,\"name\":\"mutateCachedValue\",\"url\":\"functions/mutateCachedValue.html\",\"classes\":\"tsd-kind-function\"},{\"kind\":64,\"name\":\"refetchResourceForKey\",\"url\":\"functions/refetchResourceForKey.html\",\"classes\":\"tsd-kind-function\"},{\"kind\":256,\"name\":\"CachedResourceOptions\",\"url\":\"interfaces/CachedResourceOptions.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":1024,\"name\":\"initialValue\",\"url\":\"interfaces/CachedResourceOptions.html#initialValue\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"CachedResourceOptions\"},{\"kind\":1024,\"name\":\"refetchOnMount\",\"url\":\"interfaces/CachedResourceOptions.html#refetchOnMount\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"CachedResourceOptions\"},{\"kind\":256,\"name\":\"CreateMutationOptions\",\"url\":\"interfaces/CreateMutationOptions.html\",\"classes\":\"tsd-kind-interface\"},{\"kind\":1024,\"name\":\"onSuccess\",\"url\":\"interfaces/CreateMutationOptions.html#onSuccess\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"CreateMutationOptions\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"interfaces/CreateMutationOptions.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-interface\",\"parent\":\"CreateMutationOptions\"},{\"kind\":64,\"name\":\"createMutation\",\"url\":\"functions/createMutation.html\",\"classes\":\"tsd-kind-function\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"functions/createMutation.html#createMutation.__type\",\"classes\":\"tsd-kind-type-literal\",\"parent\":\"createMutation.createMutation\"},{\"kind\":1024,\"name\":\"mutateAsync\",\"url\":\"functions/createMutation.html#createMutation.__type.mutateAsync\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"createMutation.createMutation.__type\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"functions/createMutation.html#createMutation.__type.__type-3\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-literal\",\"parent\":\"createMutation.createMutation.__type\"},{\"kind\":1024,\"name\":\"isLoading\",\"url\":\"functions/createMutation.html#createMutation.__type.isLoading\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"createMutation.createMutation.__type\"},{\"kind\":1024,\"name\":\"isSuccess\",\"url\":\"functions/createMutation.html#createMutation.__type.isSuccess\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"createMutation.createMutation.__type\"},{\"kind\":1024,\"name\":\"isError\",\"url\":\"functions/createMutation.html#createMutation.__type.isError\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"createMutation.createMutation.__type\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"functions/createMutation.html#createMutation.__type.__type-1\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-literal\",\"parent\":\"createMutation.createMutation.__type\"},{\"kind\":1024,\"name\":\"error\",\"url\":\"functions/createMutation.html#createMutation.__type.error\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"createMutation.createMutation.__type\"},{\"kind\":1024,\"name\":\"returnedData\",\"url\":\"functions/createMutation.html#createMutation.__type.returnedData\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"createMutation.createMutation.__type\"},{\"kind\":1024,\"name\":\"reset\",\"url\":\"functions/createMutation.html#createMutation.__type.reset\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"createMutation.createMutation.__type\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"functions/createMutation.html#createMutation.__type.__type-5\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-literal\",\"parent\":\"createMutation.createMutation.__type\"}],\"index\":{\"version\":\"2.3.9\",\"fields\":[\"name\",\"comment\"],\"fieldVectors\":[[\"name/0\",[0,26.856]],[\"comment/0\",[]],[\"name/1\",[1,26.856]],[\"comment/1\",[]],[\"name/2\",[2,26.856]],[\"comment/2\",[]],[\"name/3\",[3,26.856]],[\"comment/3\",[]],[\"name/4\",[4,26.856]],[\"comment/4\",[]],[\"name/5\",[5,26.856]],[\"comment/5\",[]],[\"name/6\",[6,26.856]],[\"comment/6\",[]],[\"name/7\",[7,26.856]],[\"comment/7\",[]],[\"name/8\",[8,13.863]],[\"comment/8\",[]],[\"name/9\",[9,26.856]],[\"comment/9\",[]],[\"name/10\",[8,13.863]],[\"comment/10\",[]],[\"name/11\",[10,26.856]],[\"comment/11\",[]],[\"name/12\",[8,13.863]],[\"comment/12\",[]],[\"name/13\",[11,26.856]],[\"comment/13\",[]],[\"name/14\",[12,26.856]],[\"comment/14\",[]],[\"name/15\",[13,26.856]],[\"comment/15\",[]],[\"name/16\",[8,13.863]],[\"comment/16\",[]],[\"name/17\",[14,26.856]],[\"comment/17\",[]],[\"name/18\",[15,26.856]],[\"comment/18\",[]],[\"name/19\",[16,26.856]],[\"comment/19\",[]],[\"name/20\",[8,13.863]],[\"comment/20\",[]]],\"invertedIndex\":[[\"__type\",{\"_index\":8,\"name\":{\"8\":{},\"10\":{},\"12\":{},\"16\":{},\"20\":{}},\"comment\":{}}],[\"cachedresourceoptions\",{\"_index\":3,\"name\":{\"3\":{}},\"comment\":{}}],[\"createcachedresource\",{\"_index\":0,\"name\":{\"0\":{}},\"comment\":{}}],[\"createmutation\",{\"_index\":9,\"name\":{\"9\":{}},\"comment\":{}}],[\"createmutationoptions\",{\"_index\":6,\"name\":{\"6\":{}},\"comment\":{}}],[\"error\",{\"_index\":14,\"name\":{\"17\":{}},\"comment\":{}}],[\"initialvalue\",{\"_index\":4,\"name\":{\"4\":{}},\"comment\":{}}],[\"iserror\",{\"_index\":13,\"name\":{\"15\":{}},\"comment\":{}}],[\"isloading\",{\"_index\":11,\"name\":{\"13\":{}},\"comment\":{}}],[\"issuccess\",{\"_index\":12,\"name\":{\"14\":{}},\"comment\":{}}],[\"mutateasync\",{\"_index\":10,\"name\":{\"11\":{}},\"comment\":{}}],[\"mutatecachedvalue\",{\"_index\":1,\"name\":{\"1\":{}},\"comment\":{}}],[\"onsuccess\",{\"_index\":7,\"name\":{\"7\":{}},\"comment\":{}}],[\"refetchonmount\",{\"_index\":5,\"name\":{\"5\":{}},\"comment\":{}}],[\"refetchresourceforkey\",{\"_index\":2,\"name\":{\"2\":{}},\"comment\":{}}],[\"reset\",{\"_index\":16,\"name\":{\"19\":{}},\"comment\":{}}],[\"returneddata\",{\"_index\":15,\"name\":{\"18\":{}},\"comment\":{}}]],\"pipeline\":[]}}"); -------------------------------------------------------------------------------- /docs/assets/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | /* Light */ 3 | --light-color-background: #f2f4f8; 4 | --light-color-background-secondary: #eff0f1; 5 | --light-color-icon-background: var(--light-color-background); 6 | --light-color-accent: #c5c7c9; 7 | --light-color-text: #222; 8 | --light-color-text-aside: #707070; 9 | --light-color-link: #4da6ff; 10 | --light-color-ts: #db1373; 11 | --light-color-ts-interface: #139d2c; 12 | --light-color-ts-enum: #9c891a; 13 | --light-color-ts-class: #2484e5; 14 | --light-color-ts-function: #572be7; 15 | --light-color-ts-namespace: #b111c9; 16 | --light-color-ts-private: #707070; 17 | --light-color-ts-variable: #4d68ff; 18 | --light-external-icon: url("data:image/svg+xml;utf8,"); 19 | --light-color-scheme: light; 20 | 21 | /* Dark */ 22 | --dark-color-background: #2b2e33; 23 | --dark-color-background-secondary: #1e2024; 24 | --dark-color-icon-background: var(--dark-color-background-secondary); 25 | --dark-color-accent: #9096a2; 26 | --dark-color-text: #f5f5f5; 27 | --dark-color-text-aside: #dddddd; 28 | --dark-color-link: #00aff4; 29 | --dark-color-ts: #ff6492; 30 | --dark-color-ts-interface: #6cff87; 31 | --dark-color-ts-enum: #f4d93e; 32 | --dark-color-ts-class: #61b0ff; 33 | --dark-color-ts-function: #9772ff; 34 | --dark-color-ts-namespace: #e14dff; 35 | --dark-color-ts-private: #e2e2e2; 36 | --dark-color-ts-variable: #4d68ff; 37 | --dark-external-icon: url("data:image/svg+xml;utf8,"); 38 | --dark-color-scheme: dark; 39 | } 40 | 41 | @media (prefers-color-scheme: light) { 42 | :root { 43 | --color-background: var(--light-color-background); 44 | --color-background-secondary: var(--light-color-background-secondary); 45 | --color-icon-background: var(--light-color-icon-background); 46 | --color-accent: var(--light-color-accent); 47 | --color-text: var(--light-color-text); 48 | --color-text-aside: var(--light-color-text-aside); 49 | --color-link: var(--light-color-link); 50 | --color-ts: var(--light-color-ts); 51 | --color-ts-interface: var(--light-color-ts-interface); 52 | --color-ts-enum: var(--light-color-ts-enum); 53 | --color-ts-class: var(--light-color-ts-class); 54 | --color-ts-function: var(--light-color-ts-function); 55 | --color-ts-namespace: var(--light-color-ts-namespace); 56 | --color-ts-private: var(--light-color-ts-private); 57 | --color-ts-variable: var(--light-color-ts-variable); 58 | --external-icon: var(--light-external-icon); 59 | --color-scheme: var(--light-color-scheme); 60 | } 61 | } 62 | 63 | @media (prefers-color-scheme: dark) { 64 | :root { 65 | --color-background: var(--dark-color-background); 66 | --color-background-secondary: var(--dark-color-background-secondary); 67 | --color-icon-background: var(--dark-color-icon-background); 68 | --color-accent: var(--dark-color-accent); 69 | --color-text: var(--dark-color-text); 70 | --color-text-aside: var(--dark-color-text-aside); 71 | --color-link: var(--dark-color-link); 72 | --color-ts: var(--dark-color-ts); 73 | --color-ts-interface: var(--dark-color-ts-interface); 74 | --color-ts-enum: var(--dark-color-ts-enum); 75 | --color-ts-class: var(--dark-color-ts-class); 76 | --color-ts-function: var(--dark-color-ts-function); 77 | --color-ts-namespace: var(--dark-color-ts-namespace); 78 | --color-ts-private: var(--dark-color-ts-private); 79 | --color-ts-variable: var(--dark-color-ts-variable); 80 | --external-icon: var(--dark-external-icon); 81 | --color-scheme: var(--dark-color-scheme); 82 | } 83 | } 84 | 85 | html { 86 | color-scheme: var(--color-scheme); 87 | } 88 | 89 | body { 90 | margin: 0; 91 | } 92 | 93 | :root[data-theme="light"] { 94 | --color-background: var(--light-color-background); 95 | --color-background-secondary: var(--light-color-background-secondary); 96 | --color-icon-background: var(--light-color-icon-background); 97 | --color-accent: var(--light-color-accent); 98 | --color-text: var(--light-color-text); 99 | --color-text-aside: var(--light-color-text-aside); 100 | --color-link: var(--light-color-link); 101 | --color-ts: var(--light-color-ts); 102 | --color-ts-interface: var(--light-color-ts-interface); 103 | --color-ts-enum: var(--light-color-ts-enum); 104 | --color-ts-class: var(--light-color-ts-class); 105 | --color-ts-function: var(--light-color-ts-function); 106 | --color-ts-namespace: var(--light-color-ts-namespace); 107 | --color-ts-private: var(--light-color-ts-private); 108 | --color-ts-variable: var(--light-color-ts-variable); 109 | --external-icon: var(--light-external-icon); 110 | --color-scheme: var(--light-color-scheme); 111 | } 112 | 113 | :root[data-theme="dark"] { 114 | --color-background: var(--dark-color-background); 115 | --color-background-secondary: var(--dark-color-background-secondary); 116 | --color-icon-background: var(--dark-color-icon-background); 117 | --color-accent: var(--dark-color-accent); 118 | --color-text: var(--dark-color-text); 119 | --color-text-aside: var(--dark-color-text-aside); 120 | --color-link: var(--dark-color-link); 121 | --color-ts: var(--dark-color-ts); 122 | --color-ts-interface: var(--dark-color-ts-interface); 123 | --color-ts-enum: var(--dark-color-ts-enum); 124 | --color-ts-class: var(--dark-color-ts-class); 125 | --color-ts-function: var(--dark-color-ts-function); 126 | --color-ts-namespace: var(--dark-color-ts-namespace); 127 | --color-ts-private: var(--dark-color-ts-private); 128 | --color-ts-variable: var(--dark-color-ts-variable); 129 | --external-icon: var(--dark-external-icon); 130 | --color-scheme: var(--dark-color-scheme); 131 | } 132 | 133 | h1, 134 | h2, 135 | h3, 136 | h4, 137 | h5, 138 | h6 { 139 | line-height: 1.2; 140 | } 141 | 142 | h1 { 143 | font-size: 1.875rem; 144 | margin: 0.67rem 0; 145 | } 146 | 147 | h2 { 148 | font-size: 1.5rem; 149 | margin: 0.83rem 0; 150 | } 151 | 152 | h3 { 153 | font-size: 1.25rem; 154 | margin: 1rem 0; 155 | } 156 | 157 | h4 { 158 | font-size: 1.05rem; 159 | margin: 1.33rem 0; 160 | } 161 | 162 | h5 { 163 | font-size: 1rem; 164 | margin: 1.5rem 0; 165 | } 166 | 167 | h6 { 168 | font-size: 0.875rem; 169 | margin: 2.33rem 0; 170 | } 171 | 172 | .uppercase { 173 | text-transform: uppercase; 174 | } 175 | 176 | pre { 177 | white-space: pre; 178 | white-space: pre-wrap; 179 | word-wrap: break-word; 180 | } 181 | 182 | dl, 183 | menu, 184 | ol, 185 | ul { 186 | margin: 1em 0; 187 | } 188 | 189 | dd { 190 | margin: 0 0 0 40px; 191 | } 192 | 193 | .container { 194 | max-width: 1600px; 195 | padding: 0 2rem; 196 | } 197 | 198 | @media (min-width: 640px) { 199 | .container { 200 | padding: 0 4rem; 201 | } 202 | } 203 | @media (min-width: 1200px) { 204 | .container { 205 | padding: 0 8rem; 206 | } 207 | } 208 | @media (min-width: 1600px) { 209 | .container { 210 | padding: 0 12rem; 211 | } 212 | } 213 | 214 | /* Footer */ 215 | .tsd-generator { 216 | border-top: 1px solid var(--color-accent); 217 | padding-top: 1rem; 218 | padding-bottom: 1rem; 219 | max-height: 3.5rem; 220 | } 221 | 222 | .tsd-generator > p { 223 | margin-top: 0; 224 | margin-bottom: 0; 225 | padding: 0 1rem; 226 | } 227 | 228 | .container-main { 229 | display: flex; 230 | justify-content: space-between; 231 | position: relative; 232 | margin: 0 auto; 233 | } 234 | 235 | .col-4, 236 | .col-8 { 237 | box-sizing: border-box; 238 | float: left; 239 | padding: 2rem 1rem; 240 | } 241 | 242 | .col-4 { 243 | flex: 0 0 25%; 244 | } 245 | .col-8 { 246 | flex: 1 0; 247 | flex-wrap: wrap; 248 | padding-left: 0; 249 | } 250 | 251 | @keyframes fade-in { 252 | from { 253 | opacity: 0; 254 | } 255 | to { 256 | opacity: 1; 257 | } 258 | } 259 | @keyframes fade-out { 260 | from { 261 | opacity: 1; 262 | visibility: visible; 263 | } 264 | to { 265 | opacity: 0; 266 | } 267 | } 268 | @keyframes fade-in-delayed { 269 | 0% { 270 | opacity: 0; 271 | } 272 | 33% { 273 | opacity: 0; 274 | } 275 | 100% { 276 | opacity: 1; 277 | } 278 | } 279 | @keyframes fade-out-delayed { 280 | 0% { 281 | opacity: 1; 282 | visibility: visible; 283 | } 284 | 66% { 285 | opacity: 0; 286 | } 287 | 100% { 288 | opacity: 0; 289 | } 290 | } 291 | @keyframes shift-to-left { 292 | from { 293 | transform: translate(0, 0); 294 | } 295 | to { 296 | transform: translate(-25%, 0); 297 | } 298 | } 299 | @keyframes unshift-to-left { 300 | from { 301 | transform: translate(-25%, 0); 302 | } 303 | to { 304 | transform: translate(0, 0); 305 | } 306 | } 307 | @keyframes pop-in-from-right { 308 | from { 309 | transform: translate(100%, 0); 310 | } 311 | to { 312 | transform: translate(0, 0); 313 | } 314 | } 315 | @keyframes pop-out-to-right { 316 | from { 317 | transform: translate(0, 0); 318 | visibility: visible; 319 | } 320 | to { 321 | transform: translate(100%, 0); 322 | } 323 | } 324 | body { 325 | background: var(--color-background); 326 | font-family: "Segoe UI", sans-serif; 327 | font-size: 16px; 328 | color: var(--color-text); 329 | } 330 | 331 | a { 332 | color: var(--color-link); 333 | text-decoration: none; 334 | } 335 | a:hover { 336 | text-decoration: underline; 337 | } 338 | a.external[target="_blank"] { 339 | background-image: var(--external-icon); 340 | background-position: top 3px right; 341 | background-repeat: no-repeat; 342 | padding-right: 13px; 343 | } 344 | 345 | code, 346 | pre { 347 | font-family: Menlo, Monaco, Consolas, "Courier New", monospace; 348 | padding: 0.2em; 349 | margin: 0; 350 | font-size: 0.875rem; 351 | border-radius: 0.8em; 352 | } 353 | 354 | pre { 355 | padding: 10px; 356 | border: 0.1em solid var(--color-accent); 357 | } 358 | pre code { 359 | padding: 0; 360 | font-size: 100%; 361 | } 362 | 363 | blockquote { 364 | margin: 1em 0; 365 | padding-left: 1em; 366 | border-left: 4px solid gray; 367 | } 368 | 369 | .tsd-typography { 370 | line-height: 1.333em; 371 | } 372 | .tsd-typography ul { 373 | list-style: square; 374 | padding: 0 0 0 20px; 375 | margin: 0; 376 | } 377 | .tsd-typography h4, 378 | .tsd-typography .tsd-index-panel h3, 379 | .tsd-index-panel .tsd-typography h3, 380 | .tsd-typography h5, 381 | .tsd-typography h6 { 382 | font-size: 1em; 383 | margin: 0; 384 | } 385 | .tsd-typography h5, 386 | .tsd-typography h6 { 387 | font-weight: normal; 388 | } 389 | .tsd-typography p, 390 | .tsd-typography ul, 391 | .tsd-typography ol { 392 | margin: 1em 0; 393 | } 394 | 395 | @media (max-width: 1024px) { 396 | html .col-content { 397 | float: none; 398 | max-width: 100%; 399 | width: 100%; 400 | padding-top: 3rem; 401 | } 402 | html .col-menu { 403 | position: fixed !important; 404 | overflow-y: auto; 405 | -webkit-overflow-scrolling: touch; 406 | z-index: 1024; 407 | top: 0 !important; 408 | bottom: 0 !important; 409 | left: auto !important; 410 | right: 0 !important; 411 | padding: 1.5rem 1.5rem 0 0; 412 | max-width: 25rem; 413 | visibility: hidden; 414 | background-color: var(--color-background); 415 | transform: translate(100%, 0); 416 | } 417 | html .col-menu > *:last-child { 418 | padding-bottom: 20px; 419 | } 420 | html .overlay { 421 | content: ""; 422 | display: block; 423 | position: fixed; 424 | z-index: 1023; 425 | top: 0; 426 | left: 0; 427 | right: 0; 428 | bottom: 0; 429 | background-color: rgba(0, 0, 0, 0.75); 430 | visibility: hidden; 431 | } 432 | 433 | .to-has-menu .overlay { 434 | animation: fade-in 0.4s; 435 | } 436 | 437 | .to-has-menu :is(header, footer, .col-content) { 438 | animation: shift-to-left 0.4s; 439 | } 440 | 441 | .to-has-menu .col-menu { 442 | animation: pop-in-from-right 0.4s; 443 | } 444 | 445 | .from-has-menu .overlay { 446 | animation: fade-out 0.4s; 447 | } 448 | 449 | .from-has-menu :is(header, footer, .col-content) { 450 | animation: unshift-to-left 0.4s; 451 | } 452 | 453 | .from-has-menu .col-menu { 454 | animation: pop-out-to-right 0.4s; 455 | } 456 | 457 | .has-menu body { 458 | overflow: hidden; 459 | } 460 | .has-menu .overlay { 461 | visibility: visible; 462 | } 463 | .has-menu :is(header, footer, .col-content) { 464 | transform: translate(-25%, 0); 465 | } 466 | .has-menu .col-menu { 467 | visibility: visible; 468 | transform: translate(0, 0); 469 | display: grid; 470 | align-items: center; 471 | grid-template-rows: auto 1fr; 472 | grid-gap: 1.5rem; 473 | max-height: 100vh; 474 | padding: 1rem 2rem; 475 | } 476 | .has-menu .tsd-navigation { 477 | max-height: 100%; 478 | } 479 | } 480 | 481 | .tsd-breadcrumb { 482 | margin: 0; 483 | padding: 0; 484 | color: var(--color-text-aside); 485 | } 486 | .tsd-breadcrumb a { 487 | color: var(--color-text-aside); 488 | text-decoration: none; 489 | } 490 | .tsd-breadcrumb a:hover { 491 | text-decoration: underline; 492 | } 493 | .tsd-breadcrumb li { 494 | display: inline; 495 | } 496 | .tsd-breadcrumb li:after { 497 | content: " / "; 498 | } 499 | 500 | .tsd-comment-tags { 501 | display: flex; 502 | flex-direction: column; 503 | } 504 | dl.tsd-comment-tag-group { 505 | display: flex; 506 | align-items: center; 507 | overflow: hidden; 508 | margin: 0.5em 0; 509 | } 510 | dl.tsd-comment-tag-group dt { 511 | display: flex; 512 | margin-right: 0.5em; 513 | font-size: 0.875em; 514 | font-weight: normal; 515 | } 516 | dl.tsd-comment-tag-group dd { 517 | margin: 0; 518 | } 519 | code.tsd-tag { 520 | padding: 0.25em 0.4em; 521 | border: 0.1em solid var(--color-accent); 522 | margin-right: 0.25em; 523 | font-size: 70%; 524 | } 525 | h1 code.tsd-tag:first-of-type { 526 | margin-left: 0.25em; 527 | } 528 | 529 | dl.tsd-comment-tag-group dd:before, 530 | dl.tsd-comment-tag-group dd:after { 531 | content: " "; 532 | } 533 | dl.tsd-comment-tag-group dd pre, 534 | dl.tsd-comment-tag-group dd:after { 535 | clear: both; 536 | } 537 | dl.tsd-comment-tag-group p { 538 | margin: 0; 539 | } 540 | 541 | .tsd-panel.tsd-comment .lead { 542 | font-size: 1.1em; 543 | line-height: 1.333em; 544 | margin-bottom: 2em; 545 | } 546 | .tsd-panel.tsd-comment .lead:last-child { 547 | margin-bottom: 0; 548 | } 549 | 550 | .tsd-filter-visibility h4 { 551 | font-size: 1rem; 552 | padding-top: 0.75rem; 553 | padding-bottom: 0.5rem; 554 | margin: 0; 555 | } 556 | .tsd-filter-item:not(:last-child) { 557 | margin-bottom: 0.5rem; 558 | } 559 | .tsd-filter-input { 560 | display: flex; 561 | width: fit-content; 562 | width: -moz-fit-content; 563 | align-items: center; 564 | user-select: none; 565 | -webkit-user-select: none; 566 | -moz-user-select: none; 567 | -ms-user-select: none; 568 | cursor: pointer; 569 | } 570 | .tsd-filter-input input[type="checkbox"] { 571 | cursor: pointer; 572 | position: absolute; 573 | width: 1.5em; 574 | height: 1.5em; 575 | opacity: 0; 576 | } 577 | .tsd-filter-input input[type="checkbox"]:disabled { 578 | pointer-events: none; 579 | } 580 | .tsd-filter-input svg { 581 | cursor: pointer; 582 | width: 1.5em; 583 | height: 1.5em; 584 | margin-right: 0.5em; 585 | border-radius: 0.33em; 586 | /* Leaving this at full opacity breaks event listeners on Firefox. 587 | Don't remove unless you know what you're doing. */ 588 | opacity: 0.99; 589 | } 590 | .tsd-filter-input input[type="checkbox"]:focus + svg { 591 | transform: scale(0.95); 592 | } 593 | .tsd-filter-input input[type="checkbox"]:focus:not(:focus-visible) + svg { 594 | transform: scale(1); 595 | } 596 | .tsd-checkbox-background { 597 | fill: var(--color-accent); 598 | } 599 | input[type="checkbox"]:checked ~ svg .tsd-checkbox-checkmark { 600 | stroke: var(--color-text); 601 | } 602 | .tsd-filter-input input:disabled ~ svg > .tsd-checkbox-background { 603 | fill: var(--color-background); 604 | stroke: var(--color-accent); 605 | stroke-width: 0.25rem; 606 | } 607 | .tsd-filter-input input:disabled ~ svg > .tsd-checkbox-checkmark { 608 | stroke: var(--color-accent); 609 | } 610 | 611 | .tsd-theme-toggle { 612 | padding-top: 0.75rem; 613 | } 614 | .tsd-theme-toggle > h4 { 615 | display: inline; 616 | vertical-align: middle; 617 | margin-right: 0.75rem; 618 | } 619 | 620 | .tsd-hierarchy { 621 | list-style: square; 622 | margin: 0; 623 | } 624 | .tsd-hierarchy .target { 625 | font-weight: bold; 626 | } 627 | 628 | .tsd-panel-group.tsd-index-group { 629 | margin-bottom: 0; 630 | } 631 | .tsd-index-panel .tsd-index-list { 632 | list-style: none; 633 | line-height: 1.333em; 634 | margin: 0; 635 | padding: 0.25rem 0 0 0; 636 | overflow: hidden; 637 | display: grid; 638 | grid-template-columns: repeat(3, 1fr); 639 | column-gap: 1rem; 640 | grid-template-rows: auto; 641 | } 642 | @media (max-width: 1024px) { 643 | .tsd-index-panel .tsd-index-list { 644 | grid-template-columns: repeat(2, 1fr); 645 | } 646 | } 647 | @media (max-width: 768px) { 648 | .tsd-index-panel .tsd-index-list { 649 | grid-template-columns: repeat(1, 1fr); 650 | } 651 | } 652 | .tsd-index-panel .tsd-index-list li { 653 | -webkit-page-break-inside: avoid; 654 | -moz-page-break-inside: avoid; 655 | -ms-page-break-inside: avoid; 656 | -o-page-break-inside: avoid; 657 | page-break-inside: avoid; 658 | } 659 | .tsd-index-panel a, 660 | .tsd-index-panel a.tsd-parent-kind-module { 661 | color: var(--color-ts); 662 | } 663 | .tsd-index-panel a.tsd-parent-kind-interface { 664 | color: var(--color-ts-interface); 665 | } 666 | .tsd-index-panel a.tsd-parent-kind-enum { 667 | color: var(--color-ts-enum); 668 | } 669 | .tsd-index-panel a.tsd-parent-kind-class { 670 | color: var(--color-ts-class); 671 | } 672 | .tsd-index-panel a.tsd-kind-module { 673 | color: var(--color-ts-namespace); 674 | } 675 | .tsd-index-panel a.tsd-kind-interface { 676 | color: var(--color-ts-interface); 677 | } 678 | .tsd-index-panel a.tsd-kind-enum { 679 | color: var(--color-ts-enum); 680 | } 681 | .tsd-index-panel a.tsd-kind-class { 682 | color: var(--color-ts-class); 683 | } 684 | .tsd-index-panel a.tsd-kind-function { 685 | color: var(--color-ts-function); 686 | } 687 | .tsd-index-panel a.tsd-kind-namespace { 688 | color: var(--color-ts-namespace); 689 | } 690 | .tsd-index-panel a.tsd-kind-variable { 691 | color: var(--color-ts-variable); 692 | } 693 | .tsd-index-panel a.tsd-is-private { 694 | color: var(--color-ts-private); 695 | } 696 | 697 | .tsd-flag { 698 | display: inline-block; 699 | padding: 0.25em 0.4em; 700 | border-radius: 4px; 701 | color: var(--color-comment-tag-text); 702 | background-color: var(--color-comment-tag); 703 | text-indent: 0; 704 | font-size: 75%; 705 | line-height: 1; 706 | font-weight: normal; 707 | } 708 | 709 | .tsd-anchor { 710 | position: absolute; 711 | top: -100px; 712 | } 713 | 714 | .tsd-member { 715 | position: relative; 716 | } 717 | .tsd-member .tsd-anchor + h3 { 718 | display: flex; 719 | align-items: center; 720 | margin-top: 0; 721 | margin-bottom: 0; 722 | border-bottom: none; 723 | } 724 | .tsd-member [data-tsd-kind] { 725 | color: var(--color-ts); 726 | } 727 | .tsd-member [data-tsd-kind="Interface"] { 728 | color: var(--color-ts-interface); 729 | } 730 | .tsd-member [data-tsd-kind="Enum"] { 731 | color: var(--color-ts-enum); 732 | } 733 | .tsd-member [data-tsd-kind="Class"] { 734 | color: var(--color-ts-class); 735 | } 736 | .tsd-member [data-tsd-kind="Private"] { 737 | color: var(--color-ts-private); 738 | } 739 | 740 | .tsd-navigation a { 741 | display: block; 742 | margin: 0.4rem 0; 743 | border-left: 2px solid transparent; 744 | color: var(--color-text); 745 | text-decoration: none; 746 | transition: border-left-color 0.1s; 747 | } 748 | .tsd-navigation a:hover { 749 | text-decoration: underline; 750 | } 751 | .tsd-navigation ul { 752 | margin: 0; 753 | padding: 0; 754 | list-style: none; 755 | } 756 | .tsd-navigation li { 757 | padding: 0; 758 | } 759 | 760 | .tsd-navigation.primary .tsd-accordion-details > ul { 761 | margin-top: 0.75rem; 762 | } 763 | .tsd-navigation.primary a { 764 | padding: 0.75rem 0.5rem; 765 | margin: 0; 766 | } 767 | .tsd-navigation.primary ul li a { 768 | margin-left: 0.5rem; 769 | } 770 | .tsd-navigation.primary ul li li a { 771 | margin-left: 1.5rem; 772 | } 773 | .tsd-navigation.primary ul li li li a { 774 | margin-left: 2.5rem; 775 | } 776 | .tsd-navigation.primary ul li li li li a { 777 | margin-left: 3.5rem; 778 | } 779 | .tsd-navigation.primary ul li li li li li a { 780 | margin-left: 4.5rem; 781 | } 782 | .tsd-navigation.primary ul li li li li li li a { 783 | margin-left: 5.5rem; 784 | } 785 | .tsd-navigation.primary li.current > a { 786 | border-left: 0.15rem var(--color-text) solid; 787 | } 788 | .tsd-navigation.primary li.selected > a { 789 | font-weight: bold; 790 | border-left: 0.2rem var(--color-text) solid; 791 | } 792 | .tsd-navigation.primary ul li a:hover { 793 | border-left: 0.2rem var(--color-text-aside) solid; 794 | } 795 | .tsd-navigation.primary li.globals + li > span, 796 | .tsd-navigation.primary li.globals + li > a { 797 | padding-top: 20px; 798 | } 799 | 800 | .tsd-navigation.secondary.tsd-navigation--toolbar-hide { 801 | max-height: calc(100vh - 1rem); 802 | top: 0.5rem; 803 | } 804 | .tsd-navigation.secondary > ul { 805 | display: inline; 806 | padding-right: 0.5rem; 807 | transition: opacity 0.2s; 808 | } 809 | .tsd-navigation.secondary ul li a { 810 | padding-left: 0; 811 | } 812 | .tsd-navigation.secondary ul li li a { 813 | padding-left: 1.1rem; 814 | } 815 | .tsd-navigation.secondary ul li li li a { 816 | padding-left: 2.2rem; 817 | } 818 | .tsd-navigation.secondary ul li li li li a { 819 | padding-left: 3.3rem; 820 | } 821 | .tsd-navigation.secondary ul li li li li li a { 822 | padding-left: 4.4rem; 823 | } 824 | .tsd-navigation.secondary ul li li li li li li a { 825 | padding-left: 5.5rem; 826 | } 827 | 828 | a.tsd-index-link { 829 | margin: 0.25rem 0; 830 | font-size: 1rem; 831 | line-height: 1.25rem; 832 | display: inline-flex; 833 | align-items: center; 834 | } 835 | .tsd-accordion-summary > h1, 836 | .tsd-accordion-summary > h2, 837 | .tsd-accordion-summary > h3, 838 | .tsd-accordion-summary > h4, 839 | .tsd-accordion-summary > h5 { 840 | display: inline-flex; 841 | align-items: center; 842 | vertical-align: middle; 843 | margin-bottom: 0; 844 | user-select: none; 845 | -moz-user-select: none; 846 | -webkit-user-select: none; 847 | -ms-user-select: none; 848 | } 849 | .tsd-accordion-summary { 850 | display: block; 851 | cursor: pointer; 852 | } 853 | .tsd-accordion-summary > * { 854 | margin-top: 0; 855 | margin-bottom: 0; 856 | padding-top: 0; 857 | padding-bottom: 0; 858 | } 859 | .tsd-accordion-summary::-webkit-details-marker { 860 | display: none; 861 | } 862 | .tsd-index-accordion .tsd-accordion-summary svg { 863 | margin-right: 0.25rem; 864 | } 865 | .tsd-index-content > :not(:first-child) { 866 | margin-top: 0.75rem; 867 | } 868 | .tsd-index-heading { 869 | margin-top: 1.5rem; 870 | margin-bottom: 0.75rem; 871 | } 872 | 873 | .tsd-kind-icon { 874 | margin-right: 0.5rem; 875 | width: 1.25rem; 876 | height: 1.25rem; 877 | min-width: 1.25rem; 878 | min-height: 1.25rem; 879 | } 880 | .tsd-kind-icon path { 881 | transform-origin: center; 882 | transform: scale(1.1); 883 | } 884 | .tsd-signature > .tsd-kind-icon { 885 | margin-right: 0.8rem; 886 | } 887 | 888 | @media (min-width: 1024px) { 889 | .col-content { 890 | margin: 2rem auto; 891 | } 892 | 893 | .menu-sticky-wrap { 894 | position: sticky; 895 | height: calc(100vh - 2rem); 896 | top: 4rem; 897 | right: 0; 898 | padding: 0 1.5rem; 899 | padding-top: 1rem; 900 | margin-top: 3rem; 901 | transition: 0.3s ease-in-out; 902 | transition-property: top, padding-top, padding, height; 903 | overflow-y: auto; 904 | } 905 | .col-menu { 906 | border-left: 1px solid var(--color-accent); 907 | } 908 | .col-menu--hide { 909 | top: 1rem; 910 | } 911 | .col-menu .tsd-navigation:not(:last-child) { 912 | padding-bottom: 1.75rem; 913 | } 914 | } 915 | 916 | .tsd-panel { 917 | margin-bottom: 2.5rem; 918 | } 919 | .tsd-panel.tsd-member { 920 | margin-bottom: 4rem; 921 | } 922 | .tsd-panel:empty { 923 | display: none; 924 | } 925 | .tsd-panel > h1, 926 | .tsd-panel > h2, 927 | .tsd-panel > h3 { 928 | margin: 1.5rem -1.5rem 0.75rem -1.5rem; 929 | padding: 0 1.5rem 0.75rem 1.5rem; 930 | } 931 | .tsd-panel > h1.tsd-before-signature, 932 | .tsd-panel > h2.tsd-before-signature, 933 | .tsd-panel > h3.tsd-before-signature { 934 | margin-bottom: 0; 935 | border-bottom: none; 936 | } 937 | 938 | .tsd-panel-group { 939 | margin: 4rem 0; 940 | } 941 | .tsd-panel-group.tsd-index-group { 942 | margin: 2rem 0; 943 | } 944 | .tsd-panel-group.tsd-index-group details { 945 | margin: 4rem 0; 946 | } 947 | 948 | #tsd-search { 949 | transition: background-color 0.2s; 950 | } 951 | #tsd-search .title { 952 | position: relative; 953 | z-index: 2; 954 | } 955 | #tsd-search .field { 956 | position: absolute; 957 | left: 0; 958 | top: 0; 959 | right: 2.5rem; 960 | height: 100%; 961 | } 962 | #tsd-search .field input { 963 | box-sizing: border-box; 964 | position: relative; 965 | top: -50px; 966 | z-index: 1; 967 | width: 100%; 968 | padding: 0 10px; 969 | opacity: 0; 970 | outline: 0; 971 | border: 0; 972 | background: transparent; 973 | color: var(--color-text); 974 | } 975 | #tsd-search .field label { 976 | position: absolute; 977 | overflow: hidden; 978 | right: -40px; 979 | } 980 | #tsd-search .field input, 981 | #tsd-search .title { 982 | transition: opacity 0.2s; 983 | } 984 | #tsd-search .results { 985 | position: absolute; 986 | visibility: hidden; 987 | top: 40px; 988 | width: 100%; 989 | margin: 0; 990 | padding: 0; 991 | list-style: none; 992 | box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); 993 | } 994 | #tsd-search .results li { 995 | padding: 0 10px; 996 | background-color: var(--color-background); 997 | } 998 | #tsd-search .results li:nth-child(even) { 999 | background-color: var(--color-background-secondary); 1000 | } 1001 | #tsd-search .results li.state { 1002 | display: none; 1003 | } 1004 | #tsd-search .results li.current, 1005 | #tsd-search .results li:hover { 1006 | background-color: var(--color-accent); 1007 | } 1008 | #tsd-search .results a { 1009 | display: block; 1010 | } 1011 | #tsd-search .results a:before { 1012 | top: 10px; 1013 | } 1014 | #tsd-search .results span.parent { 1015 | color: var(--color-text-aside); 1016 | font-weight: normal; 1017 | } 1018 | #tsd-search.has-focus { 1019 | background-color: var(--color-accent); 1020 | } 1021 | #tsd-search.has-focus .field input { 1022 | top: 0; 1023 | opacity: 1; 1024 | } 1025 | #tsd-search.has-focus .title { 1026 | z-index: 0; 1027 | opacity: 0; 1028 | } 1029 | #tsd-search.has-focus .results { 1030 | visibility: visible; 1031 | } 1032 | #tsd-search.loading .results li.state.loading { 1033 | display: block; 1034 | } 1035 | #tsd-search.failure .results li.state.failure { 1036 | display: block; 1037 | } 1038 | 1039 | .tsd-signature { 1040 | margin: 0 0 1rem 0; 1041 | padding: 1rem 0.5rem; 1042 | border: 1px solid var(--color-accent); 1043 | font-family: Menlo, Monaco, Consolas, "Courier New", monospace; 1044 | font-size: 14px; 1045 | overflow-x: auto; 1046 | } 1047 | 1048 | .tsd-signature-symbol { 1049 | color: var(--color-text-aside); 1050 | font-weight: normal; 1051 | } 1052 | 1053 | .tsd-signature-type { 1054 | font-style: italic; 1055 | font-weight: normal; 1056 | } 1057 | 1058 | .tsd-signatures { 1059 | padding: 0; 1060 | margin: 0 0 1em 0; 1061 | list-style-type: none; 1062 | } 1063 | .tsd-signatures .tsd-signature { 1064 | margin: 0; 1065 | border-color: var(--color-accent); 1066 | border-width: 1px 0; 1067 | transition: background-color 0.1s; 1068 | } 1069 | .tsd-description .tsd-signatures .tsd-signature { 1070 | border-width: 1px; 1071 | } 1072 | 1073 | ul.tsd-parameter-list, 1074 | ul.tsd-type-parameter-list { 1075 | list-style: square; 1076 | margin: 0; 1077 | padding-left: 20px; 1078 | } 1079 | ul.tsd-parameter-list > li.tsd-parameter-signature, 1080 | ul.tsd-type-parameter-list > li.tsd-parameter-signature { 1081 | list-style: none; 1082 | margin-left: -20px; 1083 | } 1084 | ul.tsd-parameter-list h5, 1085 | ul.tsd-type-parameter-list h5 { 1086 | font-size: 16px; 1087 | margin: 1em 0 0.5em 0; 1088 | } 1089 | .tsd-sources { 1090 | margin-top: 1rem; 1091 | font-size: 0.875em; 1092 | } 1093 | .tsd-sources a { 1094 | color: var(--color-text-aside); 1095 | text-decoration: underline; 1096 | } 1097 | .tsd-sources ul { 1098 | list-style: none; 1099 | padding: 0; 1100 | } 1101 | 1102 | .tsd-page-toolbar { 1103 | position: fixed; 1104 | z-index: 1; 1105 | top: 0; 1106 | left: 0; 1107 | width: 100%; 1108 | color: var(--color-text); 1109 | background: var(--color-background-secondary); 1110 | border-bottom: 1px var(--color-accent) solid; 1111 | transition: transform 0.3s ease-in-out; 1112 | } 1113 | .tsd-page-toolbar a { 1114 | color: var(--color-text); 1115 | text-decoration: none; 1116 | } 1117 | .tsd-page-toolbar a.title { 1118 | font-weight: bold; 1119 | } 1120 | .tsd-page-toolbar a.title:hover { 1121 | text-decoration: underline; 1122 | } 1123 | .tsd-page-toolbar .tsd-toolbar-contents { 1124 | display: flex; 1125 | justify-content: space-between; 1126 | height: 2.5rem; 1127 | } 1128 | .tsd-page-toolbar .table-cell { 1129 | position: relative; 1130 | white-space: nowrap; 1131 | line-height: 40px; 1132 | } 1133 | .tsd-page-toolbar .table-cell:first-child { 1134 | width: 100%; 1135 | } 1136 | 1137 | .tsd-page-toolbar--hide { 1138 | transform: translateY(-100%); 1139 | } 1140 | 1141 | .tsd-widget { 1142 | display: inline-block; 1143 | overflow: hidden; 1144 | opacity: 0.8; 1145 | height: 40px; 1146 | transition: opacity 0.1s, background-color 0.2s; 1147 | vertical-align: bottom; 1148 | cursor: pointer; 1149 | } 1150 | .tsd-widget:hover { 1151 | opacity: 0.9; 1152 | } 1153 | .tsd-widget.active { 1154 | opacity: 1; 1155 | background-color: var(--color-accent); 1156 | } 1157 | .tsd-widget.no-caption { 1158 | width: 40px; 1159 | } 1160 | .tsd-widget.no-caption:before { 1161 | margin: 0; 1162 | } 1163 | 1164 | .tsd-widget.options, 1165 | .tsd-widget.menu { 1166 | display: none; 1167 | } 1168 | @media (max-width: 1024px) { 1169 | .tsd-widget.options, 1170 | .tsd-widget.menu { 1171 | display: inline-block; 1172 | } 1173 | } 1174 | input[type="checkbox"] + .tsd-widget:before { 1175 | background-position: -120px 0; 1176 | } 1177 | input[type="checkbox"]:checked + .tsd-widget:before { 1178 | background-position: -160px 0; 1179 | } 1180 | 1181 | img { 1182 | max-width: 100%; 1183 | } 1184 | 1185 | .tsd-anchor-icon { 1186 | display: inline-flex; 1187 | align-items: center; 1188 | margin-left: 0.5rem; 1189 | vertical-align: middle; 1190 | color: var(--color-text); 1191 | } 1192 | 1193 | .tsd-anchor-icon svg { 1194 | width: 1em; 1195 | height: 1em; 1196 | visibility: hidden; 1197 | } 1198 | 1199 | .tsd-anchor-link:hover > .tsd-anchor-icon svg { 1200 | visibility: visible; 1201 | } 1202 | 1203 | .deprecated { 1204 | text-decoration: line-through; 1205 | } 1206 | 1207 | * { 1208 | scrollbar-width: thin; 1209 | scrollbar-color: var(--color-accent) var(--color-icon-background); 1210 | } 1211 | 1212 | *::-webkit-scrollbar { 1213 | width: 0.75rem; 1214 | } 1215 | 1216 | *::-webkit-scrollbar-track { 1217 | background: var(--color-icon-background); 1218 | } 1219 | 1220 | *::-webkit-scrollbar-thumb { 1221 | background-color: var(--color-accent); 1222 | border-radius: 999rem; 1223 | border: 0.25rem solid var(--color-icon-background); 1224 | } 1225 | -------------------------------------------------------------------------------- /docs/assets/widgets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonathan06/solid-cached-resource/f5280c9af4f78aac9725307281f887134393befe/docs/assets/widgets.png -------------------------------------------------------------------------------- /docs/assets/widgets@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yonathan06/solid-cached-resource/f5280c9af4f78aac9725307281f887134393befe/docs/assets/widgets@2x.png -------------------------------------------------------------------------------- /docs/functions/createCachedResource.html: -------------------------------------------------------------------------------- 1 | createCachedResource | solid-cached-resource
2 |
3 | 8 |
9 |
10 |
11 |
12 | 15 |

Function createCachedResource

16 |
17 |
    18 | 19 |
  • 20 |

    Create a cached resource

    21 |
    const [user, { refetch, mutate }] = createCachedResource(() => ["user", props.id], async ([, userId]) => {
    // ...fetch data
    }); 22 |
    23 | 24 |

    Description

    https://yonathan06.github.io/solid-cached-resource/modules.html#createCachedResource

    25 |
    26 |
    27 |

    Type Parameters

    28 |
      29 |
    • 30 |

      T

    • 31 |
    • 32 |

      S = any

    33 |
    34 |

    Parameters

    35 |
      36 |
    • 37 |
      source: ResourceSource<S>
      38 |

      reactive data function to toggle the request - key is derived for the value (parsed to string)

      39 |
    • 40 |
    • 41 |
      fetcher: ResourceFetcher<S, T>
      42 |

      function that receives the source (or true) and an accessor for the last or initial value and returns a value or a Promise with the value

      43 |
    • 44 |
    • 45 |
      Optional options: CachedResourceOptions<T>
      46 |

      optional object with the initialValue and refetchOnMount flag (defaults to true)

      47 |
    48 |

    Returns ResourceReturn<undefined | T, undefined | { deferStream?: boolean; initialValue?: undefined; name?: string; onHydrated?: (<S, T>(k: S, info: ResourceFetcherInfo<T>) => void) }, undefined | T>

49 |
78 |
79 |

Generated using TypeDoc

80 |
-------------------------------------------------------------------------------- /docs/functions/createMutation.html: -------------------------------------------------------------------------------- 1 | createMutation | solid-cached-resource
2 |
3 | 8 |
9 |
10 |
11 |
12 | 15 |

Function createMutation

16 |
17 |
    18 | 19 |
  • 20 |

    Create mutation

    21 |
    const { mutateAsync, isLoading } = createMutation(async (values) => {
    // ...fetch data
    }); 22 |
    23 | 24 |

    Description

    https://yonathan06.github.io/solid-cached-resource/modules.html#createMutation

    25 |
    26 |
    27 |

    Type Parameters

    28 |
      29 |
    • 30 |

      T = unknown

    • 31 |
    • 32 |

      R = unknown

    33 |
    34 |

    Parameters

    35 |
      36 |
    • 37 |
      fn: ((args: T) => Promise<R>)
      38 |
        39 |
      • 40 |
          41 |
        • (args: T): Promise<R>
        • 42 |
        • 43 |
          44 |

          Parameters

          45 |
            46 |
          • 47 |
            args: T
          48 |

          Returns Promise<R>

    • 49 |
    • 50 |
      Optional options: CreateMutationOptions<R>
      51 |

      optional object with the onSuccess hook

      52 |
    53 |

    Returns { error: Accessor<unknown>; isError: (() => boolean); isLoading: Accessor<boolean>; isSuccess: Accessor<boolean>; mutateAsync: ((args: T) => Promise<R>); reset: (() => void); returnedData: Accessor<undefined | R> }

    54 |
      55 |
    • 56 |
      error: Accessor<unknown>
    • 57 |
    • 58 |
      isError: (() => boolean)
      59 |
        60 |
      • 61 |
          62 |
        • (): boolean
        • 63 |
        • 64 |

          Returns boolean

    • 65 |
    • 66 |
      isLoading: Accessor<boolean>
    • 67 |
    • 68 |
      isSuccess: Accessor<boolean>
    • 69 |
    • 70 |
      mutateAsync: ((args: T) => Promise<R>)
      71 |
        72 |
      • 73 |
          74 |
        • (args: T): Promise<R>
        • 75 |
        • 76 |
          77 |

          Parameters

          78 |
            79 |
          • 80 |
            args: T
          81 |

          Returns Promise<R>

    • 82 |
    • 83 |
      reset: (() => void)
      84 |
        85 |
      • 86 |
          87 |
        • (): void
        • 88 |
        • 89 |

          Returns void

    • 90 |
    • 91 |
      returnedData: Accessor<undefined | R>
92 |
121 |
122 |

Generated using TypeDoc

123 |
-------------------------------------------------------------------------------- /docs/functions/mutateCachedValue.html: -------------------------------------------------------------------------------- 1 | mutateCachedValue | solid-cached-resource
2 |
3 | 8 |
9 |
10 |
11 |
12 | 15 |

Function mutateCachedValue

16 |
17 |
    18 | 19 |
  • 20 |

    Mutated cached value

    21 |
    mutateCachedValue(() => ["user", props.id], (prev) => {
    return {
    ...prev,
    ...newUserData,
    }
    }) 22 |
    23 |

    Will trigger the mutate function on all resources that has the same key

    24 | 25 |

    Description

    https://yonathan06.github.io/solid-cached-resource/modules.html#mutateCachedValue

    26 |
    27 |
    28 |

    Type Parameters

    29 |
      30 |
    • 31 |

      S

    • 32 |
    • 33 |

      T = any

    34 |
    35 |

    Parameters

    36 |
      37 |
    • 38 |
      source: S
      39 |

      reactive data function to toggle the request - key is derived for the value (parsed to string)

      40 |
    • 41 |
    • 42 |
      value: T | ((prev: T) => T)
      43 |

      The new value for the given key. Can be any data, or a function that provides the previous cached data

      44 |
    45 |

    Returns void

46 |
75 |
76 |

Generated using TypeDoc

77 |
-------------------------------------------------------------------------------- /docs/functions/refetchResourceForKey.html: -------------------------------------------------------------------------------- 1 | refetchResourceForKey | solid-cached-resource
2 |
3 | 8 |
9 |
10 |
11 |
12 | 15 |

Function refetchResourceForKey

16 |
17 |
    18 | 19 |
  • 20 |

    Refetch resources for key

    21 |
    refetchResourceForKey(() => ["user", props.id])
    22 | 
    23 |

    Will trigger the refresh function on all resources that has the same key

    24 |
    25 |
    26 |

    Type Parameters

    27 |
      28 |
    • 29 |

      S

    30 |
    31 |

    Parameters

    32 |
      33 |
    • 34 |
      source: S
      35 |

      reactive data function to toggle the request - key is derived for the value (parsed to string)

      36 |
    37 |

    Returns void

38 |
67 |
68 |

Generated using TypeDoc

69 |
-------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | solid-cached-resource
2 |
3 | 8 |
9 |
10 |
11 |
12 |

solid-cached-resource

13 |
14 | 15 |

Solid Cached Resource

16 |
17 |

Create a solid resource attached to a cached state by a unique key. 18 | Heavily inspired by react-query, but for solid's createResource 19 | Works fluently with Solid, by keeping the same API as createResource, the resource source (the first function parameter signal) is being converted to a string key.

20 |

API references

21 |

Features:

22 |
    23 |
  • Create resource with the same key in multiple places - fetch once
  • 24 |
  • Cache results for next component mount, and refresh when wanted
  • 25 |
  • Mutate local resource by key after a successful remote mutation request
  • 26 |
27 | 28 | 29 |

install

30 |
31 |
pnpm add solid-cached-resource
32 | 
33 |

or npm/yarn

34 | 35 | 36 |

createCachedResource

37 |
38 |

Inspired by useQuery just for Solid createResource

39 |
import { createCachedResource } from "solid-cached-resource";

export const createGetUserById = (userId: Accessor<string>) => {
return createCachedResource(
() => ["user", userId()],
async ([, userId]) => {
const response = fetch(`/users/${userId}`);
return await response.json();
});
}

// MyComp.tsx
const [user] = createGetUserById(props.userId);

<div>{user().name}</div>

// MyOtherComp.tsx
const [user] = createGetUserById(props.userId);

<span>{user().name}</span> 40 |
41 |

In the case above, if props.userId has the same value, the key will be the same, so even though both components are creating the same resource with the same fetcher, only one request will be made to the server.

42 | 43 | 44 |

With options

45 |
46 |

createCachedResource accepts an optional options object as its third argument

47 |
{
initialValue?: T (default undefined)
refetchOnMount?: boolean (default true)
} 48 |
49 | 50 | 51 |

createMutations

52 |
53 |

Inspired by useMutation, with onSuccess hook, and mutateCachedValue utility function.

54 |
import {
mutateCachedValue,
createMutation,
} from "solid-cached-resource";

export const createUpdateUser = (userId: Accessor<string>) => {
return createMutation(async (values) => {
const response = fetch(`user/${userId()}`, {
method: "POST",
body: values,
});
return await response.json()
}, {
onSuccess: (user) => {
mutateCachedValue(() => ["user", userId()], user);
}
});
} 55 |
56 |

mutateCachedValue will call the resources' mutate function with the provided key, so the signals will be updated across your components.

57 |
58 |
87 |
88 |

Generated using TypeDoc

89 |
-------------------------------------------------------------------------------- /docs/interfaces/CachedResourceOptions.html: -------------------------------------------------------------------------------- 1 | CachedResourceOptions | solid-cached-resource
2 |
3 | 8 |
9 |
10 |
11 |
12 | 15 |

Interface CachedResourceOptions<T>

16 |
17 |

Type Parameters

18 |
    19 |
  • 20 |

    T

21 |
22 |

Hierarchy

23 |
    24 |
  • CachedResourceOptions
25 |
26 |
27 |
28 | 29 |
30 |
31 |

Properties

32 |
35 |
36 |

Properties

37 |
38 | 39 |
initialValue?: T
42 |
43 | 44 |
refetchOnMount?: boolean
47 |
74 |
75 |

Generated using TypeDoc

76 |
-------------------------------------------------------------------------------- /docs/interfaces/CreateMutationOptions.html: -------------------------------------------------------------------------------- 1 | CreateMutationOptions | solid-cached-resource
2 |
3 | 8 |
9 |
10 |
11 |
12 | 15 |

Interface CreateMutationOptions<R>

16 |
17 |

Type Parameters

18 |
    19 |
  • 20 |

    R

21 |
22 |

Hierarchy

23 |
    24 |
  • CreateMutationOptions
25 |
26 |
27 |
28 | 29 |
30 |
31 |

Properties

32 |
onSuccess 33 |
34 |
35 |

Properties

36 |
37 | 38 |
onSuccess?: ((value: R) => any)
39 |
40 |

Type declaration

41 |
    42 |
  • 43 |
      44 |
    • (value: R): any
    • 45 |
    • 46 |
      47 |

      Parameters

      48 |
        49 |
      • 50 |
        value: R
      51 |

      Returns any

54 |
80 |
81 |

Generated using TypeDoc

82 |
-------------------------------------------------------------------------------- /docs/modules.html: -------------------------------------------------------------------------------- 1 | solid-cached-resource
2 |
3 | 8 |
9 |
10 |
11 |
12 |

solid-cached-resource

13 |
14 |
15 |

Index

16 |
17 |

Interfaces

18 |
21 |
22 |

Functions

23 |
28 |
57 |
58 |

Generated using TypeDoc

59 |
-------------------------------------------------------------------------------- /example/MyComp.tsx: -------------------------------------------------------------------------------- 1 | import { For } from "solid-js"; 2 | import { Suspense } from "solid-js"; 3 | import { 4 | createCachedResource, 5 | createMutation, 6 | mutateCachedValue, 7 | } from "../"; 8 | 9 | interface User { 10 | id: string; 11 | firstName: string; 12 | lastName: string; 13 | photoURL: string; 14 | } 15 | 16 | const userKey = "users"; 17 | const useGetUsers = () => { 18 | return createCachedResource(userKey, async () => { 19 | const response = await fetch("https://myapi.com/users"); 20 | return (await response.json()) as User[]; 21 | }); 22 | }; 23 | 24 | const useAddUser = () => { 25 | return createMutation( 26 | async (userData: User) => { 27 | const response = await fetch("https://myapi.com/users", { 28 | method: "POST", 29 | body: JSON.stringify(userData), 30 | headers: { 31 | "Content-Type": "application/json", 32 | }, 33 | }); 34 | return (await response.json()) as User; 35 | }, 36 | { 37 | onSuccess: (user) => { 38 | mutateCachedValue(userKey, (users: User[]) => [...users, user]); 39 | }, 40 | } 41 | ); 42 | }; 43 | 44 | const MyComp = () => { 45 | const [users] = useGetUsers(); 46 | return ( 47 | 48 | {(user) =>
{user.firstName}
}
49 |
50 | ); 51 | }; 52 | export default MyComp; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solid-cached-resource", 3 | "version": "0.5.6", 4 | "description": "Create a solid resource attached to a cached state by a unique key", 5 | "info": "Heavily inspired by react-query, but for solid's createResource. Works fluently with Solid, by keeping the same API as createResource, the resource source (the first function parameter signal) is being converted to a string key.", 6 | "author": "Yonatan Bendahan", 7 | "main": "dist/index.js", 8 | "module": "./dist/index.js", 9 | "type": "module", 10 | "exports": { 11 | ".": { 12 | "import": "./dist/index.js", 13 | "types": "./dist/index.d.ts" 14 | } 15 | }, 16 | "scripts": { 17 | "build": "tsc", 18 | "createDocs": "typedoc src/index.ts", 19 | "test": "vitest" 20 | }, 21 | "homepage": "https://github.com/yonathan06/solid-cached-resource", 22 | "contributors": [ 23 | { 24 | "name": "Yonatan Bendahan", 25 | "email": "yonatan.bendahan@gmail.com" 26 | } 27 | ], 28 | "license": "MIT", 29 | "devDependencies": { 30 | "@solidjs/testing-library": "^0.7.0", 31 | "@testing-library/jest-dom": "^5.16.5", 32 | "jsdom": "^21.1.1", 33 | "solid-js": "^1.7.3", 34 | "typedoc": "^0.23.7", 35 | "typescript": "^4.7.4", 36 | "vite-plugin-solid": "^2.7.0", 37 | "vitest": "^0.30.1" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/cache.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ResourceActions, 3 | ResourceSource, 4 | } from "solid-js/types/reactive/signal"; 5 | import { isPlainObject, stringyValue } from "./utils.js"; 6 | 7 | type Resolve = (value: T) => void; 8 | type Reject = (reason?: any) => void; 9 | 10 | interface StoreField { 11 | cachedValue?: T; 12 | isFetching: boolean; 13 | awaiters: { resolve: Resolve; reject: Reject }[]; 14 | resourceActions: ResourceActions[]; 15 | } 16 | 17 | interface Store { 18 | [key: string]: StoreField; 19 | } 20 | 21 | export const store: Store = {}; 22 | 23 | export function initializeStoreFieldIfEmpty(key: string) { 24 | if (!store[key]) { 25 | store[key] = { 26 | isFetching: false, 27 | awaiters: [], 28 | resourceActions: [], 29 | }; 30 | } 31 | } 32 | 33 | export function getCachedValue(key: string) { 34 | return store[key]?.cachedValue; 35 | } 36 | 37 | export function setCachedValue(key: string, value: T) { 38 | initializeStoreFieldIfEmpty(key); 39 | store[key].cachedValue = value; 40 | } 41 | 42 | export function getKeyForSource(source: ResourceSource): string { 43 | const value = typeof source === "function" ? (source as Function)() : source; 44 | if (value === false || value === null || value === undefined) return value; 45 | // Taken from https://github.com/tannerlinsley/react-query 46 | const key: string = isPlainObject(value) ? stringyValue(value) : value + ""; 47 | return key; 48 | } 49 | 50 | export async function unifyFetcherForKey( 51 | key: string, 52 | fetcher: () => Promise | T, 53 | avoidFetchIfCached = false 54 | ): Promise { 55 | const cachedValue = getCachedValue(key); 56 | if (cachedValue && avoidFetchIfCached) return cachedValue; 57 | if (store[key].isFetching) { 58 | let resolve: Resolve, reject: Reject; 59 | const awaiterPromise = new Promise((res, rej) => { 60 | resolve = res; 61 | reject = rej; 62 | store[key].awaiters.push({ resolve, reject }); 63 | }); 64 | return awaiterPromise as Promise; 65 | } 66 | store[key].isFetching = true; 67 | try { 68 | const value = await fetcher(); 69 | setCachedValue(key, value); 70 | for (let { resolve } of store[key].awaiters) { 71 | resolve(value); 72 | } 73 | for (let { mutate } of store[key].resourceActions) { 74 | mutate(value as never); 75 | } 76 | return value; 77 | } catch (e) { 78 | for (let { reject } of store[key].awaiters) { 79 | reject(e); 80 | } 81 | for (let { mutate } of store[key].resourceActions) { 82 | mutate(undefined); 83 | } 84 | throw e; 85 | } finally { 86 | store[key].isFetching = false; 87 | store[key].awaiters = []; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createResource, 3 | onCleanup, 4 | createMemo, 5 | createEffect, 6 | createSignal, 7 | batch, 8 | } from "solid-js"; 9 | import type { 10 | ResourceSource, 11 | ResourceFetcher, 12 | } from "solid-js/types/reactive/signal"; 13 | import { 14 | unifyFetcherForKey, 15 | getKeyForSource, 16 | initializeStoreFieldIfEmpty, 17 | store, 18 | getCachedValue, 19 | setCachedValue, 20 | } from "./cache.js"; 21 | 22 | export interface CachedResourceOptions { 23 | initialValue?: T; 24 | refetchOnMount?: boolean; 25 | } 26 | 27 | function getDefaultOptions() { 28 | return { 29 | refetchOnMount: true, 30 | }; 31 | } 32 | 33 | /** 34 | * Create a cached resource 35 | * ```typescript 36 | * const [user, { refetch, mutate }] = createCachedResource(() => ["user", props.id], async ([, userId]) => { 37 | * // ...fetch data 38 | * }); 39 | * ``` 40 | * @param source - reactive data function to toggle the request - key is derived for the value (parsed to string) 41 | * @param fetcher - function that receives the source (or true) and an accessor for the last or initial value and returns a value or a Promise with the value 42 | * @param options - optional object with the initialValue and refetchOnMount flag (defaults to true) 43 | * 44 | * @description https://yonathan06.github.io/solid-cached-resource/modules.html#createCachedResource 45 | */ 46 | export function createCachedResource( 47 | source: ResourceSource, 48 | fetcher: ResourceFetcher, 49 | options?: CachedResourceOptions 50 | ) { 51 | const key = createMemo(() => getKeyForSource(source)); 52 | options = { 53 | ...getDefaultOptions(), 54 | ...(options || {}), 55 | }; 56 | const resource = createResource( 57 | source, 58 | async (sourceValues, info) => { 59 | const keyString = key(); 60 | initializeStoreFieldIfEmpty(keyString); 61 | if ( 62 | options?.initialValue && 63 | !info.refetching && 64 | !getCachedValue(keyString) 65 | ) { 66 | setCachedValue(keyString, options.initialValue); 67 | return options.initialValue; 68 | } 69 | return unifyFetcherForKey( 70 | keyString, 71 | () => fetcher(sourceValues, info), 72 | !options!.refetchOnMount 73 | ); 74 | }, 75 | { initialValue: getCachedValue(key()) } 76 | ); 77 | createEffect(() => { 78 | const keyString = key(); 79 | if (keyString) { 80 | initializeStoreFieldIfEmpty(keyString); 81 | store[keyString].resourceActions.push(resource[1]); 82 | const mutatorIndex = store[keyString].resourceActions.length - 1; 83 | onCleanup(() => { 84 | store[keyString]?.resourceActions?.splice(mutatorIndex, 1); 85 | }); 86 | } 87 | }); 88 | return resource; 89 | } 90 | 91 | export interface CreateMutationOptions { 92 | onSuccess?: (value: R) => any; 93 | } 94 | 95 | /** 96 | * Create mutation 97 | * ```typescript 98 | * const { mutateAsync, isLoading } = createMutation(async (values) => { 99 | * // ...fetch data 100 | * }); 101 | * ``` 102 | * @param mutateFunction - function to be called when mutateAsync is called 103 | * @param options - optional object with the onSuccess hook 104 | * 105 | * @description https://yonathan06.github.io/solid-cached-resource/modules.html#createMutation 106 | */ 107 | export const createMutation = ( 108 | fn: (args: T) => Promise, 109 | options?: CreateMutationOptions 110 | ) => { 111 | const [isLoading, setIsLoading] = createSignal(false); 112 | const [isSuccess, setIsisSuccess] = createSignal(false); 113 | const [error, setError] = createSignal(); 114 | const isError = () => !!error(); 115 | const [returnedData, setReturnedData] = createSignal(); 116 | const mutateAsync: typeof fn = async (...args) => { 117 | setIsLoading(true); 118 | try { 119 | const response: R = await fn(...args); 120 | batch(() => { 121 | setIsLoading(false); 122 | setReturnedData(() => response); 123 | setIsisSuccess(true); 124 | options?.onSuccess?.(response); 125 | }); 126 | return response; 127 | } catch (e) { 128 | batch(() => { 129 | setIsisSuccess(false); 130 | setIsLoading(false); 131 | setError(e); 132 | }); 133 | throw e; 134 | } 135 | }; 136 | const reset = () => { 137 | batch(() => { 138 | setIsisSuccess(false); 139 | setIsLoading(false); 140 | setError(null); 141 | setReturnedData(undefined); 142 | }); 143 | }; 144 | return { 145 | mutateAsync, 146 | isLoading, 147 | isSuccess, 148 | isError, 149 | error, 150 | returnedData, 151 | reset, 152 | }; 153 | }; 154 | 155 | /** 156 | * Mutated cached value 157 | * ```typescript 158 | * mutateCachedValue(() => ["user", props.id], (prev) => { 159 | * return { 160 | * ...prev, 161 | * ...newUserData, 162 | * } 163 | * }) 164 | * ``` 165 | * Will trigger the `mutate` function on all resources that has the same key 166 | * 167 | * @param source - reactive data function to toggle the request - key is derived for the value (parsed to string) 168 | * @param value - The new value for the given key. Can be any data, or a function that provides the previous cached data 169 | * 170 | * @description https://yonathan06.github.io/solid-cached-resource/modules.html#mutateCachedValue 171 | */ 172 | export function mutateCachedValue( 173 | source: S, 174 | value: T | ((prev: T) => T) 175 | ) { 176 | const key = getKeyForSource(source); 177 | initializeStoreFieldIfEmpty(key); 178 | store[key].cachedValue = 179 | typeof value === "function" 180 | ? (value as Function)(store[key].cachedValue) 181 | : value; 182 | batch(() => { 183 | for (let { mutate } of store[key].resourceActions) { 184 | mutate(() => store[key].cachedValue); 185 | } 186 | }); 187 | } 188 | 189 | /** 190 | * 191 | * Refetch resources for key 192 | * ```typescript 193 | * refetchResourceForKey(() => ["user", props.id]) 194 | * ``` 195 | * 196 | * Will trigger the `refresh` function on all resources that has the same key 197 | * @param source - reactive data function to toggle the request - key is derived for the value (parsed to string) 198 | */ 199 | export function refetchResourceForKey(source: S) { 200 | const key = getKeyForSource(source); 201 | const actions = store[key].resourceActions; 202 | for (const action of actions) { 203 | action.refetch(); 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | function hasObjectPrototype(o: any): boolean { 2 | return Object.prototype.toString.call(o) === "[object Object]"; 3 | } 4 | 5 | // Copied from: https://github.com/jonschlinkert/is-plain-object 6 | export function isPlainObject(o: any): o is Object { 7 | if (!hasObjectPrototype(o)) { 8 | return false; 9 | } 10 | 11 | // If has modified constructor 12 | const ctor = o.constructor; 13 | if (typeof ctor === "undefined") { 14 | return true; 15 | } 16 | 17 | // If has modified prototype 18 | const prot = ctor.prototype; 19 | if (!hasObjectPrototype(prot)) { 20 | return false; 21 | } 22 | 23 | // If constructor does not have an Object-specific method 24 | if (!prot.hasOwnProperty("isPrototypeOf")) { 25 | return false; 26 | } 27 | 28 | // Most likely a plain Object 29 | return true; 30 | } 31 | 32 | export function stringyValue(value: any) { 33 | return JSON.stringify(value, (_, val) => 34 | isPlainObject(val) 35 | ? Object.keys(val) 36 | .sort() 37 | .reduce((result, key) => { 38 | result[key] = val[key]; 39 | return result; 40 | }, {} as any) 41 | : val 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /test/index.test.tsx: -------------------------------------------------------------------------------- 1 | import { describe, it, afterEach, expect } from "vitest"; 2 | import { createCachedResource } from "../src/index"; 3 | import { Component, createEffect } from "solid-js"; 4 | import { For } from "solid-js/web"; 5 | import { cleanup, render, screen } from "@solidjs/testing-library"; 6 | import { setTimeout } from 'node:timers/promises'; 7 | 8 | const MockData = [{ id: 1, name: "test" }]; 9 | 10 | const MyComp: Component = () => { 11 | const [data] = createCachedResource(["key"], async () => { 12 | return MockData; 13 | }); 14 | return ( 15 |
16 | {(item) =>
{item.name}
}
17 |
18 | ); 19 | }; 20 | 21 | describe("Test lib", () => { 22 | afterEach(cleanup); 23 | 24 | it("Should render", async () => { 25 | render(() => ); 26 | await setTimeout(0); 27 | for (const d of MockData) { 28 | const div = screen.getByTestId(d.id); 29 | expect(div).toBeTruthy(); 30 | expect(div.textContent).equals(d.name); 31 | } 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/setup.ts: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom"; 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "ESNext", 4 | "target": "ESNext", 5 | "outDir": "./dist", 6 | "declaration": true, 7 | "moduleResolution": "node", 8 | "allowSyntheticDefaultImports": true, 9 | "esModuleInterop": true, 10 | "strict": true, 11 | "strictNullChecks": true, 12 | "jsx": "preserve", 13 | "jsxImportSource": "solid-js", 14 | "skipLibCheck": true, 15 | "isolatedModules": true, 16 | "resolveJsonModule": true 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import solid from "vite-plugin-solid"; 2 | import { defineConfig } from "vitest/config"; 3 | 4 | export default defineConfig({ 5 | plugins: [solid()], 6 | test: { 7 | deps: { 8 | registerNodeLoader: true, 9 | inline: [/solid-js/], 10 | }, 11 | environment: "jsdom", 12 | globals: true, 13 | setupFiles: ['node_modules/@testing-library/jest-dom/extend-expect', './test/setup.ts'], 14 | transformMode: { web: [/\.[jt]sx?$/] }, 15 | }, 16 | resolve: { 17 | conditions: ["development", "browser"], 18 | }, 19 | }); 20 | --------------------------------------------------------------------------------