questro
Version:
A lightweight, modular gamification library for React with unique visual components. Features combo meters, daily challenges, achievement toasts, and progress rings. Add points, badges, quests, leaderboards, levels/XP, streaks, and notifications with zero
2 lines • 7.18 kB
JavaScript
'use strict';var chunkPJU2SQ3K_js=require('./chunk-PJU2SQ3K.js'),G=require('react'),jsxRuntime=require('react/jsx-runtime');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var G__default=/*#__PURE__*/_interopDefault(G);var A={linear:(a,e)=>e*a,exponential:(a,e,o)=>Math.floor(e*Math.pow(o,a-1)),fibonacci:(a,e)=>{if(a<=2)return e;let o=e,s=e;for(let r=3;r<=a;r++){let t=o+s;o=s,s=t;}return s},rpg:(a,e,o)=>Math.floor(e*Math.pow(o,a-1))};function v(a,e,o=100,s=1.5,r){if(a<=1)return 0;if(e==="custom"&&r){let n=0;for(let u=2;u<=a;u++)n+=r(u);return n}let t=A[e];if(!t)throw new Error(`Unknown formula: ${e}`);let l=0;for(let n=2;n<=a;n++)l+=t(n,o,s);return l}function b(a,e,o=100,s=1.5,r,t){if(a<=0)return 1;let l=1,n=v(l+1,e,o,s,r);for(;a>=n;){if(l++,t&&l>=t)return t;n=v(l+1,e,o,s,r);}return l}function R(a,e,o,s=100,r=1.5,t){let l=v(e,o,s,r,t),n=v(e+1,o,s,r,t),u=a-l,c=n-l,m=Math.min(100,Math.floor(u/c*100));return {currentXP:u,xpToLevelUp:c,progress:m}}var L=class{constructor(e,o){this.listeners=new Set;this.config={userId:e.userId,formula:e.formula||"linear",baseXP:e.baseXP||100,scalingFactor:e.scalingFactor||(e.formula==="rpg"?1.1:1.5),customFormula:e.customFormula,onLevelUp:e.onLevelUp,onXPGain:e.onXPGain,maxLevel:e.maxLevel},this.state=o||this.createInitialState();}createInitialState(){return {userId:this.config.userId,totalXP:0,level:1,levelHistory:[],xpHistory:[],lastUpdated:Date.now()}}getLevelData(){let{totalXP:e,level:o}=this.state,{formula:s,baseXP:r,scalingFactor:t,customFormula:l,maxLevel:n}=this.config,u=v(o,s,r,t,l),c=n&&o>=n?u:v(o+1,s,r,t,l),{currentXP:m,xpToLevelUp:f,progress:d}=R(e,o,s,r,t,l);return {level:o,currentXP:m,totalXP:e,xpForCurrentLevel:u,xpForNextLevel:c,xpToLevelUp:f,progress:n&&o>=n?100:d}}addXP(e,o){if(e<=0)throw new Error("XP amount must be positive");let s=this.state.level;this.state.totalXP+=e,this.state.lastUpdated=Date.now();let r=b(this.state.totalXP,this.config.formula,this.config.baseXP,this.config.scalingFactor,this.config.customFormula,this.config.maxLevel),t={id:`xp-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,amount:e,balance:this.state.totalXP,reason:o,timestamp:Date.now(),levelBefore:s,levelAfter:r};return this.state.xpHistory.push(t),r>s&&(this.state.level=r,this.handleLevelUp(s,r)),this.config.onXPGain&&this.config.onXPGain(e,this.state.totalXP),this.notifyListeners(),t}removeXP(e,o){if(e<=0)throw new Error("XP amount must be positive");let s=this.state.level;this.state.totalXP=Math.max(0,this.state.totalXP-e),this.state.lastUpdated=Date.now();let r=b(this.state.totalXP,this.config.formula,this.config.baseXP,this.config.scalingFactor,this.config.customFormula,this.config.maxLevel);this.state.level=r;let t={id:`xp-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,amount:-e,balance:this.state.totalXP,reason:o,timestamp:Date.now(),levelBefore:s,levelAfter:r};return this.state.xpHistory.push(t),this.notifyListeners(),t}setLevel(e){if(e<1)throw new Error("Level must be at least 1");if(this.config.maxLevel&&e>this.config.maxLevel)throw new Error(`Level cannot exceed max level of ${this.config.maxLevel}`);let o=this.state.level;this.state.level=e,this.state.totalXP=v(e,this.config.formula,this.config.baseXP,this.config.scalingFactor,this.config.customFormula),this.state.lastUpdated=Date.now(),e>o&&this.handleLevelUp(o,e),this.notifyListeners();}reset(){this.state=this.createInitialState(),this.notifyListeners();}getXPForLevel(e){return v(e,this.config.formula,this.config.baseXP,this.config.scalingFactor,this.config.customFormula)}getLevelFromXP(e){return b(e,this.config.formula,this.config.baseXP,this.config.scalingFactor,this.config.customFormula,this.config.maxLevel)}getState(){return {...this.state}}getXPHistory(){return [...this.state.xpHistory]}getLevelHistory(){return [...this.state.levelHistory]}subscribe(e){return this.listeners.add(e),()=>this.listeners.delete(e)}handleLevelUp(e,o){let s={previousLevel:e,newLevel:o,totalXP:this.state.totalXP,timestamp:Date.now()};this.state.levelHistory.push(s),this.config.onLevelUp&&this.config.onLevelUp(s);}notifyListeners(){this.listeners.forEach(e=>e());}};var $=G.createContext(null);function Y({children:a,config:e,storage:o}){let s=G.useMemo(()=>o||new chunkPJU2SQ3K_js.a,[o]),r=`questro_levels_${e.userId}`,[t,l]=G.useState(null),[n,u]=G.useState(null),[c,m]=G.useState([]),[f,d]=G.useState([]);G.useEffect(()=>{let i=true;return (async()=>{let I=await s.get(r);if(!i)return;let g=new L(e,I||void 0);l(g),u(g.getLevelData()),m(g.getXPHistory()),d(g.getLevelHistory());})(),()=>{i=false;}},[e,s,r]),G.useEffect(()=>t?t.subscribe(()=>{u(t.getLevelData()),m(t.getXPHistory()),d(t.getLevelHistory()),s.set(r,t.getState());}):void 0,[t,s,r]);let F=G.useCallback((i,h)=>{t?.addXP(i,h);},[t]),U=G.useCallback((i,h)=>{t?.removeXP(i,h);},[t]),S=G.useCallback(i=>{t?.setLevel(i);},[t]),D=G.useCallback(async()=>{t&&(t.reset(),await s.remove(r));},[t,s,r]),C=G.useCallback(i=>t?.getXPForLevel(i)??0,[t]),T=G.useCallback(i=>t?.getLevelFromXP(i)??1,[t]),H=G.useMemo(()=>!t||!n?null:{levelData:n,xpHistory:c,levelHistory:f,addXP:F,removeXP:U,setLevel:S,reset:D,getXPForLevel:C,getLevelFromXP:T},[t,n,c,f,F,U,S,D,C,T]);return H?jsxRuntime.jsx($.Provider,{value:H,children:a}):null}function x(){let a=G__default.default.useContext($);if(!a)throw new Error("useLevels must be used within a LevelsProvider");return a}function te({showXP:a=true,showPercentage:e=false,className:o,children:s}){let{levelData:r}=x();return s?jsxRuntime.jsx(jsxRuntime.Fragment,{children:s({level:r.level,currentXP:r.currentXP,xpToLevelUp:r.xpToLevelUp,progress:r.progress})}):jsxRuntime.jsxs("div",{className:o,"data-component":"level-display",children:[jsxRuntime.jsxs("div",{"data-level":r.level,children:["Level ",r.level]}),a&&jsxRuntime.jsxs("div",{"data-xp":`${r.currentXP}/${r.xpToLevelUp}`,children:[r.currentXP," / ",r.xpToLevelUp," XP"]}),e&&jsxRuntime.jsxs("div",{"data-progress":r.progress,children:[r.progress,"%"]})]})}function ne({height:a="8px",showPercentage:e=true,showXP:o=false,animated:s=true,className:r,fillClassName:t,children:l}){let{levelData:n}=x();return l?jsxRuntime.jsx(jsxRuntime.Fragment,{children:l({progress:n.progress,currentXP:n.currentXP,xpToLevelUp:n.xpToLevelUp,level:n.level})}):jsxRuntime.jsxs("div",{"data-component":"xp-bar",children:[(e||o)&&jsxRuntime.jsxs("div",{"data-xp-info":true,children:[o&&jsxRuntime.jsxs("span",{"data-xp-numbers":true,children:[n.currentXP," / ",n.xpToLevelUp," XP"]}),e&&jsxRuntime.jsxs("span",{"data-xp-percentage":true,children:[n.progress,"%"]})]}),jsxRuntime.jsx("div",{className:r,"data-xp-bar-container":true,style:{height:a,width:"100%",backgroundColor:"#e0e0e0",borderRadius:"4px",overflow:"hidden",position:"relative"},children:jsxRuntime.jsx("div",{className:t,"data-xp-bar-fill":true,"data-progress":n.progress,style:{height:"100%",width:`${n.progress}%`,backgroundColor:"#3b82f6",transition:s?"width 0.5s ease-out":"none",borderRadius:"4px"}})})]})}exports.a=A;exports.b=v;exports.c=b;exports.d=R;exports.e=L;exports.f=Y;exports.g=x;exports.h=te;exports.i=ne;//# sourceMappingURL=chunk-VEK34ZQL.js.map
//# sourceMappingURL=chunk-VEK34ZQL.js.map