wavedash-react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Adrien Guéret
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,215 @@
1
+ # wavedash-react
2
+
3
+ A React library for integrating Wavedash into your React-based game.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install wavedash-react
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ Wrap your app with the `WavedashProvider` to enable Wavedash features:
14
+
15
+ ```tsx
16
+ import { WavedashProvider } from "wavedash-react";
17
+
18
+ export function App() {
19
+ return (
20
+ <WavedashProvider
21
+ config={{
22
+ debug: true,
23
+ }}
24
+ >
25
+ <YourGame />
26
+ </WavedashProvider>
27
+ );
28
+ }
29
+ ```
30
+
31
+ ## Core Hooks
32
+
33
+ ### useWavedash
34
+
35
+ Access the Wavedash context to check if your game is running inside Wavedash:
36
+
37
+ ```tsx
38
+ import { useWavedash } from "wavedash-react";
39
+
40
+ export function GameComponent() {
41
+ const { isRunningInWavedash, wavedash } = useWavedash();
42
+
43
+ if (!isRunningInWavedash) {
44
+ return <p>Not running in Wavedash environment</p>;
45
+ }
46
+
47
+ return <p>Running in Wavedash!</p>;
48
+ }
49
+ ```
50
+
51
+ You can access the [native Wavedash SDK](https://docs.wavedash.com/sdk/functions) via `wavedash` object.
52
+
53
+ ### useCurrentUser
54
+
55
+ Get the current logged-in user:
56
+
57
+ ```tsx
58
+ import { useCurrentUser } from "wavedash-react";
59
+
60
+ export function UserProfile() {
61
+ const user = useCurrentUser();
62
+
63
+ return user ? <p>Welcome, {user.username}!</p> : <p>Not logged in</p>;
64
+ }
65
+ ```
66
+
67
+ ### UserAvatar
68
+
69
+ A React component for displaying a user's avatar:
70
+
71
+ ```tsx
72
+ import { UserAvatar } from "wavedash-react";
73
+
74
+ export function Avatar() {
75
+ return <UserAvatar size={64} />;
76
+ }
77
+
78
+ export function OtherPlayerAvatar() {
79
+ return <UserAvatar userId="specific_userid_here" size={64} />;
80
+ }
81
+ ```
82
+
83
+ ## Leaderboards
84
+
85
+ Three hooks handle different leaderboard scenarios:
86
+
87
+ #### useLeaderboardEntries
88
+
89
+ Fetch a range of leaderboard entries:
90
+
91
+ ```tsx
92
+ import { useLeaderboardEntries } from "wavedash-react";
93
+
94
+ export function TopPlayers() {
95
+ const { isLoading, entries } = useLeaderboardEntries("main-leaderboard", {
96
+ start: 0,
97
+ count: 10,
98
+ });
99
+
100
+ if (isLoading) return <p>Loading...</p>;
101
+
102
+ return (
103
+ <ul>
104
+ {entries.map((entry) => (
105
+ <li key={entry.userId}>
106
+ {entry.username}: {entry.score} pts
107
+ </li>
108
+ ))}
109
+ </ul>
110
+ );
111
+ }
112
+ ```
113
+
114
+ #### useLeaderboardCurrentUserEntries
115
+
116
+ Fetch the current user's leaderboard entries:
117
+
118
+ ```tsx
119
+ import { useLeaderboardCurrentUserEntries } from "wavedash-react";
120
+
121
+ export function MyStats() {
122
+ const { isLoading, entries } =
123
+ useLeaderboardCurrentUserEntries("main-leaderboard");
124
+
125
+ return (
126
+ <div>{entries.length > 0 && <p>Your rank: {entries[0].globalRank}</p>}</div>
127
+ );
128
+ }
129
+ ```
130
+
131
+ #### useLeaderboardEntriesAroundCurrentUser
132
+
133
+ Fetch entries around the current user (ahead and behind):
134
+
135
+ ```tsx
136
+ import { useLeaderboardEntriesAroundCurrentUser } from "wavedash-react";
137
+
138
+ export function NearbyPlayers() {
139
+ const { isLoading, entries } = useLeaderboardEntriesAroundCurrentUser(
140
+ "main-leaderboard",
141
+ { countAhead: 5, countBehind: 5 },
142
+ );
143
+
144
+ return <div>{entries.length} players nearby</div>;
145
+ }
146
+ ```
147
+
148
+ ### Submitting a score
149
+
150
+ Use the `useLeaderboard` hook to access the `submitScore` method:
151
+
152
+ ```tsx
153
+ import { useLeaderboard } from "wavedash-react";
154
+
155
+ export function GameOver({ finalScore }: { finalScore: number }) {
156
+ const { submitScore } = useLeaderboard("main-leaderboard");
157
+
158
+ const handleSubmitScore = async () => {
159
+ const response = await submitScore(finalScore);
160
+ const { globalRank = null } = response ?? {};
161
+
162
+ if (globalRank !== null) {
163
+ alert(`Your rank: #${globalRank}`);
164
+ }
165
+ };
166
+
167
+ return <button onClick={handleSubmitScore}>Submit Score</button>;
168
+ }
169
+ ```
170
+
171
+ The `submitScore` method accepts:
172
+
173
+ - `score` (required): The score value to submit
174
+ - `keepBest` (optional): Whether to keep only the best score (default: true)
175
+ - `ugcId` (optional): User-generated content ID for additional context
176
+
177
+ Returns the player's global rank after submission, or `null` if submission failed.
178
+
179
+ ## Stats
180
+
181
+ Track custom game stats:
182
+
183
+ ```tsx
184
+ import { useStat } from "wavedash-react";
185
+
186
+ export function StatsDisplay() {
187
+ const [stat, setStat] = useStat("player-kills");
188
+
189
+ return (
190
+ <div>
191
+ <p>Kills: {stat}</p>
192
+ <button onClick={() => setStat(stat + 1)}>Increment</button>
193
+ </div>
194
+ );
195
+ }
196
+ ```
197
+
198
+ ## Achievements
199
+
200
+ Display and unlock achievements:
201
+
202
+ ```tsx
203
+ import { useAchievement } from "wavedash-react";
204
+
205
+ export function AchievementHandler() {
206
+ const [achievement, unlockAchievement] = useAchievement("first-kill");
207
+
208
+ return (
209
+ <div>
210
+ <p>Status: {achievement?.unlocked ? "Unlocked" : "Locked"}</p>
211
+ <button onClick={() => unlockAchievement()}>Unlock</button>
212
+ </div>
213
+ );
214
+ }
215
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1,278 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ useAchievement: () => useAchievement,
24
+ useLeaderboard: () => useLeaderboard,
25
+ useLeaderboardCurrentUserEntries: () => useLeaderboardCurrentUserEntries,
26
+ useLeaderboardEntries: () => useLeaderboardEntries,
27
+ useLeaderboardEntriesAroundCurrentUser: () => useLeaderboardEntriesAroundCurrentUser,
28
+ useStat: () => useStat,
29
+ useWavedash: () => useWavedash
30
+ });
31
+ module.exports = __toCommonJS(index_exports);
32
+
33
+ // src/useAchievement.ts
34
+ var import_react2 = require("react");
35
+
36
+ // src/WavedashProvider.tsx
37
+ var import_react = require("react");
38
+ var import_jsx_runtime = require("react/jsx-runtime");
39
+ var WavedashContext = (0, import_react.createContext)({
40
+ isRunningInWavedash: false,
41
+ wavedash: null
42
+ });
43
+ function useWavedash() {
44
+ return (0, import_react.useContext)(WavedashContext);
45
+ }
46
+
47
+ // src/useAchievement.ts
48
+ function useAchievement(achievementName) {
49
+ const { isRunningInWavedash, wavedash } = useWavedash();
50
+ const [isUnlocked, setIsUnlocked] = (0, import_react2.useState)(null);
51
+ (0, import_react2.useEffect)(() => {
52
+ if (!isRunningInWavedash || isUnlocked !== null) {
53
+ return;
54
+ }
55
+ wavedash.requestStats().then(() => {
56
+ const value = wavedash.getAchievement(achievementName);
57
+ setIsUnlocked(value);
58
+ });
59
+ }, [isRunningInWavedash, wavedash, achievementName, isUnlocked]);
60
+ const unlock = (0, import_react2.useCallback)(
61
+ (storeNow = true) => {
62
+ if (!isRunningInWavedash) {
63
+ return false;
64
+ }
65
+ const response = wavedash.setAchievement(achievementName, storeNow);
66
+ if (response) {
67
+ setIsUnlocked(true);
68
+ }
69
+ return response;
70
+ },
71
+ [isRunningInWavedash, wavedash, achievementName]
72
+ );
73
+ return [isUnlocked, unlock];
74
+ }
75
+
76
+ // src/useLeaderboards.ts
77
+ var import_react3 = require("react");
78
+ function useLeaderboard(leaderboardName, leaderboardOptions) {
79
+ const [leaderboard, setLeaderboard] = (0, import_react3.useState)(null);
80
+ const [isLoading, setIsLoading] = (0, import_react3.useState)(true);
81
+ const { isRunningInWavedash, wavedash } = useWavedash();
82
+ const { sortOrder, displayType } = leaderboardOptions ?? {};
83
+ (0, import_react3.useEffect)(() => {
84
+ if (!isRunningInWavedash) {
85
+ setIsLoading(false);
86
+ return;
87
+ }
88
+ setIsLoading(true);
89
+ wavedash.getOrCreateLeaderboard(
90
+ leaderboardName,
91
+ sortOrder ?? wavedash.LeaderboardSortOrder.DESC,
92
+ displayType ?? wavedash.LeaderboardDisplayType.NUMERIC
93
+ ).then((result) => {
94
+ if (result.success) {
95
+ setLeaderboard(result.data);
96
+ }
97
+ }).finally(() => {
98
+ setIsLoading(false);
99
+ });
100
+ }, [isRunningInWavedash, wavedash, leaderboardName, sortOrder, displayType]);
101
+ const leaderboardId = leaderboard?.id;
102
+ const submitScore = (0, import_react3.useCallback)(
103
+ async (score, keepBest = true, ugcId) => {
104
+ if (!isRunningInWavedash || !leaderboardId) {
105
+ return null;
106
+ }
107
+ const response = await wavedash.uploadLeaderboardScore(
108
+ leaderboardId,
109
+ score,
110
+ keepBest,
111
+ ugcId
112
+ );
113
+ return response.success ? response.data : null;
114
+ },
115
+ [isRunningInWavedash, leaderboardId, wavedash]
116
+ );
117
+ const getEntryCount = (0, import_react3.useCallback)(() => {
118
+ if (!isRunningInWavedash || !leaderboardId) {
119
+ return -1;
120
+ }
121
+ return wavedash.getLeaderboardEntryCount(leaderboardId);
122
+ }, [isRunningInWavedash, leaderboardId, wavedash]);
123
+ const getEntries = (0, import_react3.useCallback)(
124
+ async (start, count, friendsOnly) => {
125
+ if (!isRunningInWavedash || !leaderboardId) {
126
+ return [];
127
+ }
128
+ const response = await wavedash.listLeaderboardEntries(
129
+ leaderboardId,
130
+ start,
131
+ count,
132
+ friendsOnly
133
+ );
134
+ return response.success ? response.data : [];
135
+ },
136
+ [isRunningInWavedash, leaderboardId, wavedash]
137
+ );
138
+ const getEntriesAroundCurrentUser = (0, import_react3.useCallback)(
139
+ async (countAhead, countBehind, friendsOnly) => {
140
+ if (!isRunningInWavedash || !leaderboardId) {
141
+ return [];
142
+ }
143
+ const response = await wavedash.listLeaderboardEntriesAroundUser(
144
+ leaderboardId,
145
+ countAhead,
146
+ countBehind,
147
+ friendsOnly
148
+ );
149
+ return response.success ? response.data : [];
150
+ },
151
+ [isRunningInWavedash, leaderboardId, wavedash]
152
+ );
153
+ const getCurrentUserEntries = (0, import_react3.useCallback)(async () => {
154
+ if (!isRunningInWavedash || !leaderboardId) {
155
+ return [];
156
+ }
157
+ const response = await wavedash.getMyLeaderboardEntries(leaderboardId);
158
+ return response.success ? response.data : [];
159
+ }, [isRunningInWavedash, leaderboardId, wavedash]);
160
+ return {
161
+ isLoading,
162
+ leaderboard,
163
+ submitScore,
164
+ getEntryCount,
165
+ getEntries,
166
+ getEntriesAroundCurrentUser,
167
+ getCurrentUserEntries
168
+ };
169
+ }
170
+ function useLeaderboardEntries(leaderboardName, leaderboardEntriesOptions, leaderboardOptions) {
171
+ const { isLoading: isLeaderboardLoading, getEntries } = useLeaderboard(
172
+ leaderboardName,
173
+ leaderboardOptions
174
+ );
175
+ const [entries, setEntries] = (0, import_react3.useState)([]);
176
+ const [areEntriesLoading, setAreEntriesLoading] = (0, import_react3.useState)(true);
177
+ const { start, count, friendsOnly } = leaderboardEntriesOptions;
178
+ (0, import_react3.useEffect)(() => {
179
+ if (isLeaderboardLoading) {
180
+ return;
181
+ }
182
+ setAreEntriesLoading(true);
183
+ getEntries(start, count, friendsOnly).then(setEntries).finally(() => {
184
+ setAreEntriesLoading(false);
185
+ });
186
+ }, [isLeaderboardLoading, getEntries, start, count, friendsOnly]);
187
+ const isLoading = isLeaderboardLoading || areEntriesLoading;
188
+ return {
189
+ isLoading,
190
+ entries
191
+ };
192
+ }
193
+ function useLeaderboardCurrentUserEntries(leaderboardName, leaderboardOptions) {
194
+ const { isLoading: isLeaderboardLoading, getCurrentUserEntries } = useLeaderboard(leaderboardName, leaderboardOptions);
195
+ const [entries, setEntries] = (0, import_react3.useState)([]);
196
+ const [areEntriesLoading, setAreEntriesLoading] = (0, import_react3.useState)(true);
197
+ (0, import_react3.useEffect)(() => {
198
+ if (isLeaderboardLoading) {
199
+ return;
200
+ }
201
+ setAreEntriesLoading(true);
202
+ getCurrentUserEntries().then(setEntries).finally(() => {
203
+ setAreEntriesLoading(false);
204
+ });
205
+ }, [isLeaderboardLoading, getCurrentUserEntries]);
206
+ const isLoading = isLeaderboardLoading || areEntriesLoading;
207
+ return {
208
+ isLoading,
209
+ entries
210
+ };
211
+ }
212
+ function useLeaderboardEntriesAroundCurrentUser(leaderboardName, leaderboardEntriesOptions, leaderboardOptions) {
213
+ const { isLoading: isLeaderboardLoading, getEntriesAroundCurrentUser } = useLeaderboard(leaderboardName, leaderboardOptions);
214
+ const [entries, setEntries] = (0, import_react3.useState)([]);
215
+ const [areEntriesLoading, setAreEntriesLoading] = (0, import_react3.useState)(true);
216
+ const { countAhead, countBehind, friendsOnly } = leaderboardEntriesOptions;
217
+ (0, import_react3.useEffect)(() => {
218
+ if (isLeaderboardLoading) {
219
+ return;
220
+ }
221
+ setAreEntriesLoading(true);
222
+ getEntriesAroundCurrentUser(countAhead, countBehind, friendsOnly).then(setEntries).finally(() => {
223
+ setAreEntriesLoading(false);
224
+ });
225
+ }, [
226
+ isLeaderboardLoading,
227
+ getEntriesAroundCurrentUser,
228
+ countAhead,
229
+ countBehind,
230
+ friendsOnly
231
+ ]);
232
+ const isLoading = isLeaderboardLoading || areEntriesLoading;
233
+ return {
234
+ isLoading,
235
+ entries
236
+ };
237
+ }
238
+
239
+ // src/useStat.ts
240
+ var import_react4 = require("react");
241
+ function useStat(statName) {
242
+ const { isRunningInWavedash, wavedash } = useWavedash();
243
+ const [statValue, setStatValue] = (0, import_react4.useState)(null);
244
+ (0, import_react4.useEffect)(() => {
245
+ if (!isRunningInWavedash || statValue !== null) {
246
+ return;
247
+ }
248
+ wavedash.requestStats().then(() => {
249
+ const value = wavedash.getStat(statName);
250
+ setStatValue(value);
251
+ });
252
+ }, [isRunningInWavedash, wavedash, statName, statValue]);
253
+ const set = (0, import_react4.useCallback)(
254
+ (newValue, storeNow = true) => {
255
+ if (!isRunningInWavedash) {
256
+ return false;
257
+ }
258
+ const response = wavedash.setStat(statName, newValue, storeNow);
259
+ if (response) {
260
+ setStatValue(newValue);
261
+ }
262
+ return response;
263
+ },
264
+ [isRunningInWavedash, wavedash, statName]
265
+ );
266
+ return [statValue, set];
267
+ }
268
+ // Annotate the CommonJS export names for ESM import in node:
269
+ 0 && (module.exports = {
270
+ useAchievement,
271
+ useLeaderboard,
272
+ useLeaderboardCurrentUserEntries,
273
+ useLeaderboardEntries,
274
+ useLeaderboardEntriesAroundCurrentUser,
275
+ useStat,
276
+ useWavedash
277
+ });
278
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/useAchievement.ts","../src/WavedashProvider.tsx","../src/useLeaderboards.ts","../src/useStat.ts"],"sourcesContent":["export * from \"./useAchievement\";\r\nexport * from \"./useCurrentUser\";\r\nexport * from \"./useLeaderboards\";\r\nexport * from \"./useStat\";\r\nexport * from \"./UserAvatar\";\r\nexport * from \"./WavedashProvider\";\r\n","import { useCallback, useState, useEffect } from \"react\";\r\n\r\nimport { useWavedash } from \"./WavedashProvider\";\r\n\r\nexport type UseAchievementReturnValue = [\r\n boolean | null,\r\n unlock: (storeNow?: boolean) => boolean,\r\n];\r\n\r\nexport function useAchievement(\r\n achievementName: string,\r\n): UseAchievementReturnValue {\r\n const { isRunningInWavedash, wavedash } = useWavedash();\r\n\r\n const [isUnlocked, setIsUnlocked] = useState<boolean | null>(null);\r\n\r\n useEffect(() => {\r\n if (!isRunningInWavedash || isUnlocked !== null) {\r\n return;\r\n }\r\n\r\n wavedash.requestStats().then(() => {\r\n const value = wavedash.getAchievement(achievementName);\r\n setIsUnlocked(value);\r\n });\r\n }, [isRunningInWavedash, wavedash, achievementName, isUnlocked]);\r\n\r\n const unlock = useCallback(\r\n (storeNow: boolean = true): boolean => {\r\n if (!isRunningInWavedash) {\r\n return false;\r\n }\r\n\r\n const response = wavedash.setAchievement(achievementName, storeNow);\r\n\r\n if (response) {\r\n setIsUnlocked(true);\r\n }\r\n\r\n return response;\r\n },\r\n [isRunningInWavedash, wavedash, achievementName],\r\n );\r\n\r\n return [isUnlocked, unlock];\r\n}\r\n","import {\r\n type ReactNode,\r\n createContext,\r\n useContext,\r\n useEffect,\r\n useMemo,\r\n useCallback,\r\n useState,\r\n} from \"react\";\r\nimport type { WavedashSDK, WavedashConfig } from \"@wvdsh/sdk-js\";\r\n\r\nexport type WavedashContextValue =\r\n | {\r\n isRunningInWavedash: true;\r\n wavedash: WavedashSDK;\r\n }\r\n | {\r\n isRunningInWavedash: false;\r\n wavedash?: null;\r\n };\r\n\r\nconst WavedashContext = createContext<WavedashContextValue>({\r\n isRunningInWavedash: false,\r\n wavedash: null,\r\n});\r\n\r\nexport type WavedashProviderProps = {\r\n children: ReactNode;\r\n preload?: Partial<Record<\"audio\" | \"image\" | \"video\", string[]>>;\r\n config?: WavedashConfig;\r\n};\r\n\r\nexport default function WavedashProvider({\r\n children,\r\n preload,\r\n config,\r\n}: WavedashProviderProps) {\r\n const [isInit, setIsInit] = useState(false);\r\n\r\n const contextValue: WavedashContextValue = useMemo(\r\n () =>\r\n typeof window !== \"undefined\" && window.Wavedash\r\n ? {\r\n isRunningInWavedash: true,\r\n wavedash: window.Wavedash,\r\n }\r\n : {\r\n isRunningInWavedash: false,\r\n wavedash: null,\r\n },\r\n [],\r\n );\r\n\r\n const init = useCallback(() => {\r\n setIsInit(true);\r\n\r\n if (isInit || !contextValue.isRunningInWavedash) {\r\n return;\r\n }\r\n\r\n contextValue.wavedash.updateLoadProgressZeroToOne(1);\r\n contextValue.wavedash.init(config);\r\n }, [contextValue, config, isInit, preload]);\r\n\r\n useEffect(() => {\r\n if (isInit || !contextValue.isRunningInWavedash) {\r\n return;\r\n }\r\n\r\n const { audio = [], image = [], video = [] } = preload ?? {};\r\n const totalCount = audio.length + image.length + video.length;\r\n let loadedCount = 0;\r\n\r\n if (totalCount === 0) {\r\n init();\r\n return;\r\n }\r\n\r\n const handleAssetLoad = () => {\r\n loadedCount += 1;\r\n contextValue.wavedash.updateLoadProgressZeroToOne(\r\n loadedCount / totalCount,\r\n );\r\n if (loadedCount === totalCount) {\r\n init();\r\n }\r\n };\r\n\r\n audio.forEach((src) => {\r\n const audioElement = new Audio(src);\r\n audioElement.addEventListener(\"canplaythrough\", handleAssetLoad, {\r\n once: true,\r\n });\r\n audioElement.addEventListener(\"error\", handleAssetLoad, { once: true });\r\n });\r\n\r\n image.forEach((src) => {\r\n const img = new Image();\r\n img.src = src;\r\n img.addEventListener(\"load\", handleAssetLoad, { once: true });\r\n img.addEventListener(\"error\", handleAssetLoad, { once: true });\r\n });\r\n\r\n video.forEach((src) => {\r\n const videoElement = document.createElement(\"video\");\r\n videoElement.src = src;\r\n videoElement.addEventListener(\"canplaythrough\", handleAssetLoad, {\r\n once: true,\r\n });\r\n videoElement.addEventListener(\"error\", handleAssetLoad, { once: true });\r\n });\r\n }, [isInit, preload, contextValue]);\r\n\r\n return (\r\n <WavedashContext.Provider value={contextValue}>\r\n {isInit ? children : null}\r\n </WavedashContext.Provider>\r\n );\r\n}\r\n\r\nexport function useWavedash(): WavedashContextValue {\r\n return useContext(WavedashContext);\r\n}\r\n","import { useState, useEffect, useCallback } from \"react\";\r\nimport type {\r\n Leaderboard,\r\n LeaderboardSortOrder,\r\n LeaderboardDisplayType,\r\n Id,\r\n LeaderboardEntries,\r\n UpsertedLeaderboardEntry,\r\n} from \"@wvdsh/sdk-js\";\r\n\r\nimport { useWavedash } from \"./WavedashProvider\";\r\n\r\nexport type UseLeaderBoardReturnValue = {\r\n isLoading: boolean;\r\n leaderboard: Leaderboard | null;\r\n submitScore: (\r\n score: number,\r\n keepBest?: boolean,\r\n ugcId?: Id<\"userGeneratedContent\">,\r\n ) => Promise<UpsertedLeaderboardEntry | null>;\r\n getEntryCount: () => number;\r\n getEntries: (\r\n start: number,\r\n count: number,\r\n friendsOnly?: boolean,\r\n ) => Promise<LeaderboardEntries>;\r\n getEntriesAroundCurrentUser: (\r\n countAhead: number,\r\n countBehind: number,\r\n friendsOnly?: boolean,\r\n ) => Promise<LeaderboardEntries>;\r\n getCurrentUserEntries: () => Promise<LeaderboardEntries>;\r\n};\r\n\r\nexport type LeaderboardOptions = {\r\n sortOrder?: LeaderboardSortOrder;\r\n displayType?: LeaderboardDisplayType;\r\n};\r\n\r\nexport function useLeaderboard(\r\n leaderboardName: string,\r\n leaderboardOptions?: LeaderboardOptions,\r\n): UseLeaderBoardReturnValue {\r\n const [leaderboard, setLeaderboard] = useState<Leaderboard | null>(null);\r\n const [isLoading, setIsLoading] = useState(true);\r\n const { isRunningInWavedash, wavedash } = useWavedash();\r\n\r\n const { sortOrder, displayType } = leaderboardOptions ?? {};\r\n\r\n useEffect(() => {\r\n if (!isRunningInWavedash) {\r\n setIsLoading(false);\r\n return;\r\n }\r\n\r\n setIsLoading(true);\r\n\r\n wavedash\r\n .getOrCreateLeaderboard(\r\n leaderboardName,\r\n sortOrder ?? wavedash.LeaderboardSortOrder.DESC,\r\n displayType ?? wavedash.LeaderboardDisplayType.NUMERIC,\r\n )\r\n .then((result) => {\r\n if (result.success) {\r\n setLeaderboard(result.data);\r\n }\r\n })\r\n .finally(() => {\r\n setIsLoading(false);\r\n });\r\n }, [isRunningInWavedash, wavedash, leaderboardName, sortOrder, displayType]);\r\n\r\n const leaderboardId = leaderboard?.id;\r\n\r\n const submitScore = useCallback(\r\n async (\r\n score: number,\r\n keepBest: boolean = true,\r\n ugcId?: Id<\"userGeneratedContent\">,\r\n ): Promise<UpsertedLeaderboardEntry | null> => {\r\n if (!isRunningInWavedash || !leaderboardId) {\r\n return null;\r\n }\r\n\r\n const response = await wavedash.uploadLeaderboardScore(\r\n leaderboardId,\r\n score,\r\n keepBest,\r\n ugcId,\r\n );\r\n\r\n return response.success ? response.data : null;\r\n },\r\n [isRunningInWavedash, leaderboardId, wavedash],\r\n );\r\n\r\n const getEntryCount = useCallback((): number => {\r\n if (!isRunningInWavedash || !leaderboardId) {\r\n return -1;\r\n }\r\n\r\n return wavedash.getLeaderboardEntryCount(leaderboardId);\r\n }, [isRunningInWavedash, leaderboardId, wavedash]);\r\n\r\n const getEntries = useCallback(\r\n async (\r\n start: number,\r\n count: number,\r\n friendsOnly?: boolean,\r\n ): Promise<LeaderboardEntries> => {\r\n if (!isRunningInWavedash || !leaderboardId) {\r\n return [];\r\n }\r\n\r\n const response = await wavedash.listLeaderboardEntries(\r\n leaderboardId,\r\n start,\r\n count,\r\n friendsOnly,\r\n );\r\n\r\n return response.success ? response.data : [];\r\n },\r\n [isRunningInWavedash, leaderboardId, wavedash],\r\n );\r\n\r\n const getEntriesAroundCurrentUser = useCallback(\r\n async (\r\n countAhead: number,\r\n countBehind: number,\r\n friendsOnly?: boolean,\r\n ): Promise<LeaderboardEntries> => {\r\n if (!isRunningInWavedash || !leaderboardId) {\r\n return [];\r\n }\r\n\r\n const response = await wavedash.listLeaderboardEntriesAroundUser(\r\n leaderboardId,\r\n countAhead,\r\n countBehind,\r\n friendsOnly,\r\n );\r\n\r\n return response.success ? response.data : [];\r\n },\r\n [isRunningInWavedash, leaderboardId, wavedash],\r\n );\r\n\r\n const getCurrentUserEntries =\r\n useCallback(async (): Promise<LeaderboardEntries> => {\r\n if (!isRunningInWavedash || !leaderboardId) {\r\n return [];\r\n }\r\n\r\n const response = await wavedash.getMyLeaderboardEntries(leaderboardId);\r\n return response.success ? response.data : [];\r\n }, [isRunningInWavedash, leaderboardId, wavedash]);\r\n\r\n return {\r\n isLoading,\r\n leaderboard,\r\n submitScore,\r\n getEntryCount,\r\n getEntries,\r\n getEntriesAroundCurrentUser,\r\n getCurrentUserEntries,\r\n };\r\n}\r\n\r\nexport type LeaderboardAllEntriesOptions = {\r\n start: number;\r\n count: number;\r\n friendsOnly?: boolean;\r\n};\r\n\r\nexport type LeaderboardAroundCurrentUserEntriesOptions = {\r\n countAhead: number;\r\n countBehind: number;\r\n friendsOnly?: boolean;\r\n};\r\n\r\nexport function useLeaderboardEntries(\r\n leaderboardName: string,\r\n leaderboardEntriesOptions: LeaderboardAllEntriesOptions,\r\n leaderboardOptions?: LeaderboardOptions,\r\n): { isLoading: boolean; entries: LeaderboardEntries } {\r\n const { isLoading: isLeaderboardLoading, getEntries } = useLeaderboard(\r\n leaderboardName,\r\n leaderboardOptions,\r\n );\r\n const [entries, setEntries] = useState<LeaderboardEntries>([]);\r\n\r\n const [areEntriesLoading, setAreEntriesLoading] = useState(true);\r\n\r\n const { start, count, friendsOnly } = leaderboardEntriesOptions;\r\n\r\n useEffect(() => {\r\n if (isLeaderboardLoading) {\r\n return;\r\n }\r\n\r\n setAreEntriesLoading(true);\r\n\r\n getEntries(start, count, friendsOnly)\r\n .then(setEntries)\r\n .finally(() => {\r\n setAreEntriesLoading(false);\r\n });\r\n }, [isLeaderboardLoading, getEntries, start, count, friendsOnly]);\r\n\r\n const isLoading = isLeaderboardLoading || areEntriesLoading;\r\n\r\n return {\r\n isLoading,\r\n entries,\r\n };\r\n}\r\n\r\nexport function useLeaderboardCurrentUserEntries(\r\n leaderboardName: string,\r\n leaderboardOptions?: LeaderboardOptions,\r\n): { isLoading: boolean; entries: LeaderboardEntries } {\r\n const { isLoading: isLeaderboardLoading, getCurrentUserEntries } =\r\n useLeaderboard(leaderboardName, leaderboardOptions);\r\n const [entries, setEntries] = useState<LeaderboardEntries>([]);\r\n const [areEntriesLoading, setAreEntriesLoading] = useState(true);\r\n\r\n useEffect(() => {\r\n if (isLeaderboardLoading) {\r\n return;\r\n }\r\n\r\n setAreEntriesLoading(true);\r\n getCurrentUserEntries()\r\n .then(setEntries)\r\n .finally(() => {\r\n setAreEntriesLoading(false);\r\n });\r\n }, [isLeaderboardLoading, getCurrentUserEntries]);\r\n\r\n const isLoading = isLeaderboardLoading || areEntriesLoading;\r\n\r\n return {\r\n isLoading,\r\n entries,\r\n };\r\n}\r\n\r\nexport function useLeaderboardEntriesAroundCurrentUser(\r\n leaderboardName: string,\r\n leaderboardEntriesOptions: LeaderboardAroundCurrentUserEntriesOptions,\r\n leaderboardOptions?: LeaderboardOptions,\r\n): { isLoading: boolean; entries: LeaderboardEntries } {\r\n const { isLoading: isLeaderboardLoading, getEntriesAroundCurrentUser } =\r\n useLeaderboard(leaderboardName, leaderboardOptions);\r\n const [entries, setEntries] = useState<LeaderboardEntries>([]);\r\n const [areEntriesLoading, setAreEntriesLoading] = useState(true);\r\n\r\n const { countAhead, countBehind, friendsOnly } = leaderboardEntriesOptions;\r\n\r\n useEffect(() => {\r\n if (isLeaderboardLoading) {\r\n return;\r\n }\r\n\r\n setAreEntriesLoading(true);\r\n getEntriesAroundCurrentUser(countAhead, countBehind, friendsOnly)\r\n .then(setEntries)\r\n .finally(() => {\r\n setAreEntriesLoading(false);\r\n });\r\n }, [\r\n isLeaderboardLoading,\r\n getEntriesAroundCurrentUser,\r\n countAhead,\r\n countBehind,\r\n friendsOnly,\r\n ]);\r\n\r\n const isLoading = isLeaderboardLoading || areEntriesLoading;\r\n\r\n return {\r\n isLoading,\r\n entries,\r\n };\r\n}\r\n","import { useCallback, useState, useEffect } from \"react\";\r\n\r\nimport { useWavedash } from \"./WavedashProvider\";\r\n\r\nexport type UseStatReturnValue = [\r\n number | null,\r\n (newValue: number, storeNow?: boolean) => boolean,\r\n];\r\n\r\nexport function useStat(statName: string): UseStatReturnValue {\r\n const { isRunningInWavedash, wavedash } = useWavedash();\r\n\r\n const [statValue, setStatValue] = useState<number | null>(null);\r\n\r\n useEffect(() => {\r\n if (!isRunningInWavedash || statValue !== null) {\r\n return;\r\n }\r\n\r\n wavedash.requestStats().then(() => {\r\n const value = wavedash.getStat(statName);\r\n setStatValue(value);\r\n });\r\n }, [isRunningInWavedash, wavedash, statName, statValue]);\r\n\r\n const set = useCallback(\r\n (newValue: number, storeNow: boolean = true): boolean => {\r\n if (!isRunningInWavedash) {\r\n return false;\r\n }\r\n\r\n const response = wavedash.setStat(statName, newValue, storeNow);\r\n\r\n if (response) {\r\n setStatValue(newValue);\r\n }\r\n\r\n return response;\r\n },\r\n [isRunningInWavedash, wavedash, statName],\r\n );\r\n\r\n return [statValue, set];\r\n}\r\n"],"mappings":"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","names":["import_react","import_react","import_react"]}
@@ -0,0 +1,73 @@
1
+ import { LeaderboardSortOrder, LeaderboardDisplayType, Leaderboard, Id, UpsertedLeaderboardEntry, LeaderboardEntries, WavedashSDK, WavedashConfig } from '@wvdsh/sdk-js';
2
+ import { ReactNode } from 'react';
3
+
4
+ type UseAchievementReturnValue = [
5
+ boolean | null,
6
+ unlock: (storeNow?: boolean) => boolean
7
+ ];
8
+ declare function useAchievement(achievementName: string): UseAchievementReturnValue;
9
+
10
+ type UseLeaderBoardReturnValue = {
11
+ isLoading: boolean;
12
+ leaderboard: Leaderboard | null;
13
+ submitScore: (score: number, keepBest?: boolean, ugcId?: Id<"userGeneratedContent">) => Promise<UpsertedLeaderboardEntry | null>;
14
+ getEntryCount: () => number;
15
+ getEntries: (start: number, count: number, friendsOnly?: boolean) => Promise<LeaderboardEntries>;
16
+ getEntriesAroundCurrentUser: (countAhead: number, countBehind: number, friendsOnly?: boolean) => Promise<LeaderboardEntries>;
17
+ getCurrentUserEntries: () => Promise<LeaderboardEntries>;
18
+ };
19
+ type LeaderboardOptions = {
20
+ sortOrder?: LeaderboardSortOrder;
21
+ displayType?: LeaderboardDisplayType;
22
+ };
23
+ declare function useLeaderboard(leaderboardName: string, leaderboardOptions?: LeaderboardOptions): UseLeaderBoardReturnValue;
24
+ type LeaderboardAllEntriesOptions = {
25
+ start: number;
26
+ count: number;
27
+ friendsOnly?: boolean;
28
+ };
29
+ type LeaderboardAroundCurrentUserEntriesOptions = {
30
+ countAhead: number;
31
+ countBehind: number;
32
+ friendsOnly?: boolean;
33
+ };
34
+ declare function useLeaderboardEntries(leaderboardName: string, leaderboardEntriesOptions: LeaderboardAllEntriesOptions, leaderboardOptions?: LeaderboardOptions): {
35
+ isLoading: boolean;
36
+ entries: LeaderboardEntries;
37
+ };
38
+ declare function useLeaderboardCurrentUserEntries(leaderboardName: string, leaderboardOptions?: LeaderboardOptions): {
39
+ isLoading: boolean;
40
+ entries: LeaderboardEntries;
41
+ };
42
+ declare function useLeaderboardEntriesAroundCurrentUser(leaderboardName: string, leaderboardEntriesOptions: LeaderboardAroundCurrentUserEntriesOptions, leaderboardOptions?: LeaderboardOptions): {
43
+ isLoading: boolean;
44
+ entries: LeaderboardEntries;
45
+ };
46
+
47
+ type UseStatReturnValue = [
48
+ number | null,
49
+ (newValue: number, storeNow?: boolean) => boolean
50
+ ];
51
+ declare function useStat(statName: string): UseStatReturnValue;
52
+
53
+ type UserAvatarProps = {
54
+ userId?: Id<"users">;
55
+ size?: number;
56
+ defaultAvatar?: ReactNode;
57
+ };
58
+
59
+ type WavedashContextValue = {
60
+ isRunningInWavedash: true;
61
+ wavedash: WavedashSDK;
62
+ } | {
63
+ isRunningInWavedash: false;
64
+ wavedash?: null;
65
+ };
66
+ type WavedashProviderProps = {
67
+ children: ReactNode;
68
+ preload?: Partial<Record<"audio" | "image" | "video", string[]>>;
69
+ config?: WavedashConfig;
70
+ };
71
+ declare function useWavedash(): WavedashContextValue;
72
+
73
+ export { type LeaderboardAllEntriesOptions, type LeaderboardAroundCurrentUserEntriesOptions, type LeaderboardOptions, type UseAchievementReturnValue, type UseLeaderBoardReturnValue, type UseStatReturnValue, type UserAvatarProps, type WavedashContextValue, type WavedashProviderProps, useAchievement, useLeaderboard, useLeaderboardCurrentUserEntries, useLeaderboardEntries, useLeaderboardEntriesAroundCurrentUser, useStat, useWavedash };
@@ -0,0 +1,73 @@
1
+ import { LeaderboardSortOrder, LeaderboardDisplayType, Leaderboard, Id, UpsertedLeaderboardEntry, LeaderboardEntries, WavedashSDK, WavedashConfig } from '@wvdsh/sdk-js';
2
+ import { ReactNode } from 'react';
3
+
4
+ type UseAchievementReturnValue = [
5
+ boolean | null,
6
+ unlock: (storeNow?: boolean) => boolean
7
+ ];
8
+ declare function useAchievement(achievementName: string): UseAchievementReturnValue;
9
+
10
+ type UseLeaderBoardReturnValue = {
11
+ isLoading: boolean;
12
+ leaderboard: Leaderboard | null;
13
+ submitScore: (score: number, keepBest?: boolean, ugcId?: Id<"userGeneratedContent">) => Promise<UpsertedLeaderboardEntry | null>;
14
+ getEntryCount: () => number;
15
+ getEntries: (start: number, count: number, friendsOnly?: boolean) => Promise<LeaderboardEntries>;
16
+ getEntriesAroundCurrentUser: (countAhead: number, countBehind: number, friendsOnly?: boolean) => Promise<LeaderboardEntries>;
17
+ getCurrentUserEntries: () => Promise<LeaderboardEntries>;
18
+ };
19
+ type LeaderboardOptions = {
20
+ sortOrder?: LeaderboardSortOrder;
21
+ displayType?: LeaderboardDisplayType;
22
+ };
23
+ declare function useLeaderboard(leaderboardName: string, leaderboardOptions?: LeaderboardOptions): UseLeaderBoardReturnValue;
24
+ type LeaderboardAllEntriesOptions = {
25
+ start: number;
26
+ count: number;
27
+ friendsOnly?: boolean;
28
+ };
29
+ type LeaderboardAroundCurrentUserEntriesOptions = {
30
+ countAhead: number;
31
+ countBehind: number;
32
+ friendsOnly?: boolean;
33
+ };
34
+ declare function useLeaderboardEntries(leaderboardName: string, leaderboardEntriesOptions: LeaderboardAllEntriesOptions, leaderboardOptions?: LeaderboardOptions): {
35
+ isLoading: boolean;
36
+ entries: LeaderboardEntries;
37
+ };
38
+ declare function useLeaderboardCurrentUserEntries(leaderboardName: string, leaderboardOptions?: LeaderboardOptions): {
39
+ isLoading: boolean;
40
+ entries: LeaderboardEntries;
41
+ };
42
+ declare function useLeaderboardEntriesAroundCurrentUser(leaderboardName: string, leaderboardEntriesOptions: LeaderboardAroundCurrentUserEntriesOptions, leaderboardOptions?: LeaderboardOptions): {
43
+ isLoading: boolean;
44
+ entries: LeaderboardEntries;
45
+ };
46
+
47
+ type UseStatReturnValue = [
48
+ number | null,
49
+ (newValue: number, storeNow?: boolean) => boolean
50
+ ];
51
+ declare function useStat(statName: string): UseStatReturnValue;
52
+
53
+ type UserAvatarProps = {
54
+ userId?: Id<"users">;
55
+ size?: number;
56
+ defaultAvatar?: ReactNode;
57
+ };
58
+
59
+ type WavedashContextValue = {
60
+ isRunningInWavedash: true;
61
+ wavedash: WavedashSDK;
62
+ } | {
63
+ isRunningInWavedash: false;
64
+ wavedash?: null;
65
+ };
66
+ type WavedashProviderProps = {
67
+ children: ReactNode;
68
+ preload?: Partial<Record<"audio" | "image" | "video", string[]>>;
69
+ config?: WavedashConfig;
70
+ };
71
+ declare function useWavedash(): WavedashContextValue;
72
+
73
+ export { type LeaderboardAllEntriesOptions, type LeaderboardAroundCurrentUserEntriesOptions, type LeaderboardOptions, type UseAchievementReturnValue, type UseLeaderBoardReturnValue, type UseStatReturnValue, type UserAvatarProps, type WavedashContextValue, type WavedashProviderProps, useAchievement, useLeaderboard, useLeaderboardCurrentUserEntries, useLeaderboardEntries, useLeaderboardEntriesAroundCurrentUser, useStat, useWavedash };
package/dist/index.js ADDED
@@ -0,0 +1,252 @@
1
+ // src/useAchievement.ts
2
+ import { useCallback as useCallback2, useState as useState2, useEffect as useEffect2 } from "react";
3
+
4
+ // src/WavedashProvider.tsx
5
+ import {
6
+ createContext,
7
+ useContext,
8
+ useEffect,
9
+ useMemo,
10
+ useCallback,
11
+ useState
12
+ } from "react";
13
+ import { jsx } from "react/jsx-runtime";
14
+ var WavedashContext = createContext({
15
+ isRunningInWavedash: false,
16
+ wavedash: null
17
+ });
18
+ function useWavedash() {
19
+ return useContext(WavedashContext);
20
+ }
21
+
22
+ // src/useAchievement.ts
23
+ function useAchievement(achievementName) {
24
+ const { isRunningInWavedash, wavedash } = useWavedash();
25
+ const [isUnlocked, setIsUnlocked] = useState2(null);
26
+ useEffect2(() => {
27
+ if (!isRunningInWavedash || isUnlocked !== null) {
28
+ return;
29
+ }
30
+ wavedash.requestStats().then(() => {
31
+ const value = wavedash.getAchievement(achievementName);
32
+ setIsUnlocked(value);
33
+ });
34
+ }, [isRunningInWavedash, wavedash, achievementName, isUnlocked]);
35
+ const unlock = useCallback2(
36
+ (storeNow = true) => {
37
+ if (!isRunningInWavedash) {
38
+ return false;
39
+ }
40
+ const response = wavedash.setAchievement(achievementName, storeNow);
41
+ if (response) {
42
+ setIsUnlocked(true);
43
+ }
44
+ return response;
45
+ },
46
+ [isRunningInWavedash, wavedash, achievementName]
47
+ );
48
+ return [isUnlocked, unlock];
49
+ }
50
+
51
+ // src/useLeaderboards.ts
52
+ import { useState as useState3, useEffect as useEffect3, useCallback as useCallback3 } from "react";
53
+ function useLeaderboard(leaderboardName, leaderboardOptions) {
54
+ const [leaderboard, setLeaderboard] = useState3(null);
55
+ const [isLoading, setIsLoading] = useState3(true);
56
+ const { isRunningInWavedash, wavedash } = useWavedash();
57
+ const { sortOrder, displayType } = leaderboardOptions ?? {};
58
+ useEffect3(() => {
59
+ if (!isRunningInWavedash) {
60
+ setIsLoading(false);
61
+ return;
62
+ }
63
+ setIsLoading(true);
64
+ wavedash.getOrCreateLeaderboard(
65
+ leaderboardName,
66
+ sortOrder ?? wavedash.LeaderboardSortOrder.DESC,
67
+ displayType ?? wavedash.LeaderboardDisplayType.NUMERIC
68
+ ).then((result) => {
69
+ if (result.success) {
70
+ setLeaderboard(result.data);
71
+ }
72
+ }).finally(() => {
73
+ setIsLoading(false);
74
+ });
75
+ }, [isRunningInWavedash, wavedash, leaderboardName, sortOrder, displayType]);
76
+ const leaderboardId = leaderboard?.id;
77
+ const submitScore = useCallback3(
78
+ async (score, keepBest = true, ugcId) => {
79
+ if (!isRunningInWavedash || !leaderboardId) {
80
+ return null;
81
+ }
82
+ const response = await wavedash.uploadLeaderboardScore(
83
+ leaderboardId,
84
+ score,
85
+ keepBest,
86
+ ugcId
87
+ );
88
+ return response.success ? response.data : null;
89
+ },
90
+ [isRunningInWavedash, leaderboardId, wavedash]
91
+ );
92
+ const getEntryCount = useCallback3(() => {
93
+ if (!isRunningInWavedash || !leaderboardId) {
94
+ return -1;
95
+ }
96
+ return wavedash.getLeaderboardEntryCount(leaderboardId);
97
+ }, [isRunningInWavedash, leaderboardId, wavedash]);
98
+ const getEntries = useCallback3(
99
+ async (start, count, friendsOnly) => {
100
+ if (!isRunningInWavedash || !leaderboardId) {
101
+ return [];
102
+ }
103
+ const response = await wavedash.listLeaderboardEntries(
104
+ leaderboardId,
105
+ start,
106
+ count,
107
+ friendsOnly
108
+ );
109
+ return response.success ? response.data : [];
110
+ },
111
+ [isRunningInWavedash, leaderboardId, wavedash]
112
+ );
113
+ const getEntriesAroundCurrentUser = useCallback3(
114
+ async (countAhead, countBehind, friendsOnly) => {
115
+ if (!isRunningInWavedash || !leaderboardId) {
116
+ return [];
117
+ }
118
+ const response = await wavedash.listLeaderboardEntriesAroundUser(
119
+ leaderboardId,
120
+ countAhead,
121
+ countBehind,
122
+ friendsOnly
123
+ );
124
+ return response.success ? response.data : [];
125
+ },
126
+ [isRunningInWavedash, leaderboardId, wavedash]
127
+ );
128
+ const getCurrentUserEntries = useCallback3(async () => {
129
+ if (!isRunningInWavedash || !leaderboardId) {
130
+ return [];
131
+ }
132
+ const response = await wavedash.getMyLeaderboardEntries(leaderboardId);
133
+ return response.success ? response.data : [];
134
+ }, [isRunningInWavedash, leaderboardId, wavedash]);
135
+ return {
136
+ isLoading,
137
+ leaderboard,
138
+ submitScore,
139
+ getEntryCount,
140
+ getEntries,
141
+ getEntriesAroundCurrentUser,
142
+ getCurrentUserEntries
143
+ };
144
+ }
145
+ function useLeaderboardEntries(leaderboardName, leaderboardEntriesOptions, leaderboardOptions) {
146
+ const { isLoading: isLeaderboardLoading, getEntries } = useLeaderboard(
147
+ leaderboardName,
148
+ leaderboardOptions
149
+ );
150
+ const [entries, setEntries] = useState3([]);
151
+ const [areEntriesLoading, setAreEntriesLoading] = useState3(true);
152
+ const { start, count, friendsOnly } = leaderboardEntriesOptions;
153
+ useEffect3(() => {
154
+ if (isLeaderboardLoading) {
155
+ return;
156
+ }
157
+ setAreEntriesLoading(true);
158
+ getEntries(start, count, friendsOnly).then(setEntries).finally(() => {
159
+ setAreEntriesLoading(false);
160
+ });
161
+ }, [isLeaderboardLoading, getEntries, start, count, friendsOnly]);
162
+ const isLoading = isLeaderboardLoading || areEntriesLoading;
163
+ return {
164
+ isLoading,
165
+ entries
166
+ };
167
+ }
168
+ function useLeaderboardCurrentUserEntries(leaderboardName, leaderboardOptions) {
169
+ const { isLoading: isLeaderboardLoading, getCurrentUserEntries } = useLeaderboard(leaderboardName, leaderboardOptions);
170
+ const [entries, setEntries] = useState3([]);
171
+ const [areEntriesLoading, setAreEntriesLoading] = useState3(true);
172
+ useEffect3(() => {
173
+ if (isLeaderboardLoading) {
174
+ return;
175
+ }
176
+ setAreEntriesLoading(true);
177
+ getCurrentUserEntries().then(setEntries).finally(() => {
178
+ setAreEntriesLoading(false);
179
+ });
180
+ }, [isLeaderboardLoading, getCurrentUserEntries]);
181
+ const isLoading = isLeaderboardLoading || areEntriesLoading;
182
+ return {
183
+ isLoading,
184
+ entries
185
+ };
186
+ }
187
+ function useLeaderboardEntriesAroundCurrentUser(leaderboardName, leaderboardEntriesOptions, leaderboardOptions) {
188
+ const { isLoading: isLeaderboardLoading, getEntriesAroundCurrentUser } = useLeaderboard(leaderboardName, leaderboardOptions);
189
+ const [entries, setEntries] = useState3([]);
190
+ const [areEntriesLoading, setAreEntriesLoading] = useState3(true);
191
+ const { countAhead, countBehind, friendsOnly } = leaderboardEntriesOptions;
192
+ useEffect3(() => {
193
+ if (isLeaderboardLoading) {
194
+ return;
195
+ }
196
+ setAreEntriesLoading(true);
197
+ getEntriesAroundCurrentUser(countAhead, countBehind, friendsOnly).then(setEntries).finally(() => {
198
+ setAreEntriesLoading(false);
199
+ });
200
+ }, [
201
+ isLeaderboardLoading,
202
+ getEntriesAroundCurrentUser,
203
+ countAhead,
204
+ countBehind,
205
+ friendsOnly
206
+ ]);
207
+ const isLoading = isLeaderboardLoading || areEntriesLoading;
208
+ return {
209
+ isLoading,
210
+ entries
211
+ };
212
+ }
213
+
214
+ // src/useStat.ts
215
+ import { useCallback as useCallback4, useState as useState4, useEffect as useEffect4 } from "react";
216
+ function useStat(statName) {
217
+ const { isRunningInWavedash, wavedash } = useWavedash();
218
+ const [statValue, setStatValue] = useState4(null);
219
+ useEffect4(() => {
220
+ if (!isRunningInWavedash || statValue !== null) {
221
+ return;
222
+ }
223
+ wavedash.requestStats().then(() => {
224
+ const value = wavedash.getStat(statName);
225
+ setStatValue(value);
226
+ });
227
+ }, [isRunningInWavedash, wavedash, statName, statValue]);
228
+ const set = useCallback4(
229
+ (newValue, storeNow = true) => {
230
+ if (!isRunningInWavedash) {
231
+ return false;
232
+ }
233
+ const response = wavedash.setStat(statName, newValue, storeNow);
234
+ if (response) {
235
+ setStatValue(newValue);
236
+ }
237
+ return response;
238
+ },
239
+ [isRunningInWavedash, wavedash, statName]
240
+ );
241
+ return [statValue, set];
242
+ }
243
+ export {
244
+ useAchievement,
245
+ useLeaderboard,
246
+ useLeaderboardCurrentUserEntries,
247
+ useLeaderboardEntries,
248
+ useLeaderboardEntriesAroundCurrentUser,
249
+ useStat,
250
+ useWavedash
251
+ };
252
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/useAchievement.ts","../src/WavedashProvider.tsx","../src/useLeaderboards.ts","../src/useStat.ts"],"sourcesContent":["import { useCallback, useState, useEffect } from \"react\";\r\n\r\nimport { useWavedash } from \"./WavedashProvider\";\r\n\r\nexport type UseAchievementReturnValue = [\r\n boolean | null,\r\n unlock: (storeNow?: boolean) => boolean,\r\n];\r\n\r\nexport function useAchievement(\r\n achievementName: string,\r\n): UseAchievementReturnValue {\r\n const { isRunningInWavedash, wavedash } = useWavedash();\r\n\r\n const [isUnlocked, setIsUnlocked] = useState<boolean | null>(null);\r\n\r\n useEffect(() => {\r\n if (!isRunningInWavedash || isUnlocked !== null) {\r\n return;\r\n }\r\n\r\n wavedash.requestStats().then(() => {\r\n const value = wavedash.getAchievement(achievementName);\r\n setIsUnlocked(value);\r\n });\r\n }, [isRunningInWavedash, wavedash, achievementName, isUnlocked]);\r\n\r\n const unlock = useCallback(\r\n (storeNow: boolean = true): boolean => {\r\n if (!isRunningInWavedash) {\r\n return false;\r\n }\r\n\r\n const response = wavedash.setAchievement(achievementName, storeNow);\r\n\r\n if (response) {\r\n setIsUnlocked(true);\r\n }\r\n\r\n return response;\r\n },\r\n [isRunningInWavedash, wavedash, achievementName],\r\n );\r\n\r\n return [isUnlocked, unlock];\r\n}\r\n","import {\r\n type ReactNode,\r\n createContext,\r\n useContext,\r\n useEffect,\r\n useMemo,\r\n useCallback,\r\n useState,\r\n} from \"react\";\r\nimport type { WavedashSDK, WavedashConfig } from \"@wvdsh/sdk-js\";\r\n\r\nexport type WavedashContextValue =\r\n | {\r\n isRunningInWavedash: true;\r\n wavedash: WavedashSDK;\r\n }\r\n | {\r\n isRunningInWavedash: false;\r\n wavedash?: null;\r\n };\r\n\r\nconst WavedashContext = createContext<WavedashContextValue>({\r\n isRunningInWavedash: false,\r\n wavedash: null,\r\n});\r\n\r\nexport type WavedashProviderProps = {\r\n children: ReactNode;\r\n preload?: Partial<Record<\"audio\" | \"image\" | \"video\", string[]>>;\r\n config?: WavedashConfig;\r\n};\r\n\r\nexport default function WavedashProvider({\r\n children,\r\n preload,\r\n config,\r\n}: WavedashProviderProps) {\r\n const [isInit, setIsInit] = useState(false);\r\n\r\n const contextValue: WavedashContextValue = useMemo(\r\n () =>\r\n typeof window !== \"undefined\" && window.Wavedash\r\n ? {\r\n isRunningInWavedash: true,\r\n wavedash: window.Wavedash,\r\n }\r\n : {\r\n isRunningInWavedash: false,\r\n wavedash: null,\r\n },\r\n [],\r\n );\r\n\r\n const init = useCallback(() => {\r\n setIsInit(true);\r\n\r\n if (isInit || !contextValue.isRunningInWavedash) {\r\n return;\r\n }\r\n\r\n contextValue.wavedash.updateLoadProgressZeroToOne(1);\r\n contextValue.wavedash.init(config);\r\n }, [contextValue, config, isInit, preload]);\r\n\r\n useEffect(() => {\r\n if (isInit || !contextValue.isRunningInWavedash) {\r\n return;\r\n }\r\n\r\n const { audio = [], image = [], video = [] } = preload ?? {};\r\n const totalCount = audio.length + image.length + video.length;\r\n let loadedCount = 0;\r\n\r\n if (totalCount === 0) {\r\n init();\r\n return;\r\n }\r\n\r\n const handleAssetLoad = () => {\r\n loadedCount += 1;\r\n contextValue.wavedash.updateLoadProgressZeroToOne(\r\n loadedCount / totalCount,\r\n );\r\n if (loadedCount === totalCount) {\r\n init();\r\n }\r\n };\r\n\r\n audio.forEach((src) => {\r\n const audioElement = new Audio(src);\r\n audioElement.addEventListener(\"canplaythrough\", handleAssetLoad, {\r\n once: true,\r\n });\r\n audioElement.addEventListener(\"error\", handleAssetLoad, { once: true });\r\n });\r\n\r\n image.forEach((src) => {\r\n const img = new Image();\r\n img.src = src;\r\n img.addEventListener(\"load\", handleAssetLoad, { once: true });\r\n img.addEventListener(\"error\", handleAssetLoad, { once: true });\r\n });\r\n\r\n video.forEach((src) => {\r\n const videoElement = document.createElement(\"video\");\r\n videoElement.src = src;\r\n videoElement.addEventListener(\"canplaythrough\", handleAssetLoad, {\r\n once: true,\r\n });\r\n videoElement.addEventListener(\"error\", handleAssetLoad, { once: true });\r\n });\r\n }, [isInit, preload, contextValue]);\r\n\r\n return (\r\n <WavedashContext.Provider value={contextValue}>\r\n {isInit ? children : null}\r\n </WavedashContext.Provider>\r\n );\r\n}\r\n\r\nexport function useWavedash(): WavedashContextValue {\r\n return useContext(WavedashContext);\r\n}\r\n","import { useState, useEffect, useCallback } from \"react\";\r\nimport type {\r\n Leaderboard,\r\n LeaderboardSortOrder,\r\n LeaderboardDisplayType,\r\n Id,\r\n LeaderboardEntries,\r\n UpsertedLeaderboardEntry,\r\n} from \"@wvdsh/sdk-js\";\r\n\r\nimport { useWavedash } from \"./WavedashProvider\";\r\n\r\nexport type UseLeaderBoardReturnValue = {\r\n isLoading: boolean;\r\n leaderboard: Leaderboard | null;\r\n submitScore: (\r\n score: number,\r\n keepBest?: boolean,\r\n ugcId?: Id<\"userGeneratedContent\">,\r\n ) => Promise<UpsertedLeaderboardEntry | null>;\r\n getEntryCount: () => number;\r\n getEntries: (\r\n start: number,\r\n count: number,\r\n friendsOnly?: boolean,\r\n ) => Promise<LeaderboardEntries>;\r\n getEntriesAroundCurrentUser: (\r\n countAhead: number,\r\n countBehind: number,\r\n friendsOnly?: boolean,\r\n ) => Promise<LeaderboardEntries>;\r\n getCurrentUserEntries: () => Promise<LeaderboardEntries>;\r\n};\r\n\r\nexport type LeaderboardOptions = {\r\n sortOrder?: LeaderboardSortOrder;\r\n displayType?: LeaderboardDisplayType;\r\n};\r\n\r\nexport function useLeaderboard(\r\n leaderboardName: string,\r\n leaderboardOptions?: LeaderboardOptions,\r\n): UseLeaderBoardReturnValue {\r\n const [leaderboard, setLeaderboard] = useState<Leaderboard | null>(null);\r\n const [isLoading, setIsLoading] = useState(true);\r\n const { isRunningInWavedash, wavedash } = useWavedash();\r\n\r\n const { sortOrder, displayType } = leaderboardOptions ?? {};\r\n\r\n useEffect(() => {\r\n if (!isRunningInWavedash) {\r\n setIsLoading(false);\r\n return;\r\n }\r\n\r\n setIsLoading(true);\r\n\r\n wavedash\r\n .getOrCreateLeaderboard(\r\n leaderboardName,\r\n sortOrder ?? wavedash.LeaderboardSortOrder.DESC,\r\n displayType ?? wavedash.LeaderboardDisplayType.NUMERIC,\r\n )\r\n .then((result) => {\r\n if (result.success) {\r\n setLeaderboard(result.data);\r\n }\r\n })\r\n .finally(() => {\r\n setIsLoading(false);\r\n });\r\n }, [isRunningInWavedash, wavedash, leaderboardName, sortOrder, displayType]);\r\n\r\n const leaderboardId = leaderboard?.id;\r\n\r\n const submitScore = useCallback(\r\n async (\r\n score: number,\r\n keepBest: boolean = true,\r\n ugcId?: Id<\"userGeneratedContent\">,\r\n ): Promise<UpsertedLeaderboardEntry | null> => {\r\n if (!isRunningInWavedash || !leaderboardId) {\r\n return null;\r\n }\r\n\r\n const response = await wavedash.uploadLeaderboardScore(\r\n leaderboardId,\r\n score,\r\n keepBest,\r\n ugcId,\r\n );\r\n\r\n return response.success ? response.data : null;\r\n },\r\n [isRunningInWavedash, leaderboardId, wavedash],\r\n );\r\n\r\n const getEntryCount = useCallback((): number => {\r\n if (!isRunningInWavedash || !leaderboardId) {\r\n return -1;\r\n }\r\n\r\n return wavedash.getLeaderboardEntryCount(leaderboardId);\r\n }, [isRunningInWavedash, leaderboardId, wavedash]);\r\n\r\n const getEntries = useCallback(\r\n async (\r\n start: number,\r\n count: number,\r\n friendsOnly?: boolean,\r\n ): Promise<LeaderboardEntries> => {\r\n if (!isRunningInWavedash || !leaderboardId) {\r\n return [];\r\n }\r\n\r\n const response = await wavedash.listLeaderboardEntries(\r\n leaderboardId,\r\n start,\r\n count,\r\n friendsOnly,\r\n );\r\n\r\n return response.success ? response.data : [];\r\n },\r\n [isRunningInWavedash, leaderboardId, wavedash],\r\n );\r\n\r\n const getEntriesAroundCurrentUser = useCallback(\r\n async (\r\n countAhead: number,\r\n countBehind: number,\r\n friendsOnly?: boolean,\r\n ): Promise<LeaderboardEntries> => {\r\n if (!isRunningInWavedash || !leaderboardId) {\r\n return [];\r\n }\r\n\r\n const response = await wavedash.listLeaderboardEntriesAroundUser(\r\n leaderboardId,\r\n countAhead,\r\n countBehind,\r\n friendsOnly,\r\n );\r\n\r\n return response.success ? response.data : [];\r\n },\r\n [isRunningInWavedash, leaderboardId, wavedash],\r\n );\r\n\r\n const getCurrentUserEntries =\r\n useCallback(async (): Promise<LeaderboardEntries> => {\r\n if (!isRunningInWavedash || !leaderboardId) {\r\n return [];\r\n }\r\n\r\n const response = await wavedash.getMyLeaderboardEntries(leaderboardId);\r\n return response.success ? response.data : [];\r\n }, [isRunningInWavedash, leaderboardId, wavedash]);\r\n\r\n return {\r\n isLoading,\r\n leaderboard,\r\n submitScore,\r\n getEntryCount,\r\n getEntries,\r\n getEntriesAroundCurrentUser,\r\n getCurrentUserEntries,\r\n };\r\n}\r\n\r\nexport type LeaderboardAllEntriesOptions = {\r\n start: number;\r\n count: number;\r\n friendsOnly?: boolean;\r\n};\r\n\r\nexport type LeaderboardAroundCurrentUserEntriesOptions = {\r\n countAhead: number;\r\n countBehind: number;\r\n friendsOnly?: boolean;\r\n};\r\n\r\nexport function useLeaderboardEntries(\r\n leaderboardName: string,\r\n leaderboardEntriesOptions: LeaderboardAllEntriesOptions,\r\n leaderboardOptions?: LeaderboardOptions,\r\n): { isLoading: boolean; entries: LeaderboardEntries } {\r\n const { isLoading: isLeaderboardLoading, getEntries } = useLeaderboard(\r\n leaderboardName,\r\n leaderboardOptions,\r\n );\r\n const [entries, setEntries] = useState<LeaderboardEntries>([]);\r\n\r\n const [areEntriesLoading, setAreEntriesLoading] = useState(true);\r\n\r\n const { start, count, friendsOnly } = leaderboardEntriesOptions;\r\n\r\n useEffect(() => {\r\n if (isLeaderboardLoading) {\r\n return;\r\n }\r\n\r\n setAreEntriesLoading(true);\r\n\r\n getEntries(start, count, friendsOnly)\r\n .then(setEntries)\r\n .finally(() => {\r\n setAreEntriesLoading(false);\r\n });\r\n }, [isLeaderboardLoading, getEntries, start, count, friendsOnly]);\r\n\r\n const isLoading = isLeaderboardLoading || areEntriesLoading;\r\n\r\n return {\r\n isLoading,\r\n entries,\r\n };\r\n}\r\n\r\nexport function useLeaderboardCurrentUserEntries(\r\n leaderboardName: string,\r\n leaderboardOptions?: LeaderboardOptions,\r\n): { isLoading: boolean; entries: LeaderboardEntries } {\r\n const { isLoading: isLeaderboardLoading, getCurrentUserEntries } =\r\n useLeaderboard(leaderboardName, leaderboardOptions);\r\n const [entries, setEntries] = useState<LeaderboardEntries>([]);\r\n const [areEntriesLoading, setAreEntriesLoading] = useState(true);\r\n\r\n useEffect(() => {\r\n if (isLeaderboardLoading) {\r\n return;\r\n }\r\n\r\n setAreEntriesLoading(true);\r\n getCurrentUserEntries()\r\n .then(setEntries)\r\n .finally(() => {\r\n setAreEntriesLoading(false);\r\n });\r\n }, [isLeaderboardLoading, getCurrentUserEntries]);\r\n\r\n const isLoading = isLeaderboardLoading || areEntriesLoading;\r\n\r\n return {\r\n isLoading,\r\n entries,\r\n };\r\n}\r\n\r\nexport function useLeaderboardEntriesAroundCurrentUser(\r\n leaderboardName: string,\r\n leaderboardEntriesOptions: LeaderboardAroundCurrentUserEntriesOptions,\r\n leaderboardOptions?: LeaderboardOptions,\r\n): { isLoading: boolean; entries: LeaderboardEntries } {\r\n const { isLoading: isLeaderboardLoading, getEntriesAroundCurrentUser } =\r\n useLeaderboard(leaderboardName, leaderboardOptions);\r\n const [entries, setEntries] = useState<LeaderboardEntries>([]);\r\n const [areEntriesLoading, setAreEntriesLoading] = useState(true);\r\n\r\n const { countAhead, countBehind, friendsOnly } = leaderboardEntriesOptions;\r\n\r\n useEffect(() => {\r\n if (isLeaderboardLoading) {\r\n return;\r\n }\r\n\r\n setAreEntriesLoading(true);\r\n getEntriesAroundCurrentUser(countAhead, countBehind, friendsOnly)\r\n .then(setEntries)\r\n .finally(() => {\r\n setAreEntriesLoading(false);\r\n });\r\n }, [\r\n isLeaderboardLoading,\r\n getEntriesAroundCurrentUser,\r\n countAhead,\r\n countBehind,\r\n friendsOnly,\r\n ]);\r\n\r\n const isLoading = isLeaderboardLoading || areEntriesLoading;\r\n\r\n return {\r\n isLoading,\r\n entries,\r\n };\r\n}\r\n","import { useCallback, useState, useEffect } from \"react\";\r\n\r\nimport { useWavedash } from \"./WavedashProvider\";\r\n\r\nexport type UseStatReturnValue = [\r\n number | null,\r\n (newValue: number, storeNow?: boolean) => boolean,\r\n];\r\n\r\nexport function useStat(statName: string): UseStatReturnValue {\r\n const { isRunningInWavedash, wavedash } = useWavedash();\r\n\r\n const [statValue, setStatValue] = useState<number | null>(null);\r\n\r\n useEffect(() => {\r\n if (!isRunningInWavedash || statValue !== null) {\r\n return;\r\n }\r\n\r\n wavedash.requestStats().then(() => {\r\n const value = wavedash.getStat(statName);\r\n setStatValue(value);\r\n });\r\n }, [isRunningInWavedash, wavedash, statName, statValue]);\r\n\r\n const set = useCallback(\r\n (newValue: number, storeNow: boolean = true): boolean => {\r\n if (!isRunningInWavedash) {\r\n return false;\r\n }\r\n\r\n const response = wavedash.setStat(statName, newValue, storeNow);\r\n\r\n if (response) {\r\n setStatValue(newValue);\r\n }\r\n\r\n return response;\r\n },\r\n [isRunningInWavedash, wavedash, statName],\r\n );\r\n\r\n return [statValue, set];\r\n}\r\n"],"mappings":"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","names":["useCallback","useState","useEffect","useState","useEffect","useCallback","useState","useEffect","useCallback","useState","useEffect","useCallback","useCallback","useState","useEffect","useState","useEffect","useCallback"]}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "wavedash-react",
3
+ "version": "0.1.0",
4
+ "description": "React wrapper for Wavedash",
5
+ "main": "./dist/index.cjs",
6
+ "scripts": {
7
+ "build": "tsup",
8
+ "dev": "tsup --watch",
9
+ "clean": "rimraf dist",
10
+ "prepublishOnly": "npm run build",
11
+ "typecheck": "tsc --noEmit"
12
+ },
13
+ "author": "",
14
+ "license": "MIT",
15
+ "devDependencies": {
16
+ "@types/react": "^19.2.14",
17
+ "react": "^19.2.6",
18
+ "@wvdsh/sdk-js": "^1.3.6",
19
+ "rimraf": "^6.1.3",
20
+ "tsup": "^8.5.1",
21
+ "typescript": "^6.0.3"
22
+ },
23
+ "type": "module",
24
+ "sideEffects": false,
25
+ "module": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "keywords": [
31
+ "react",
32
+ "wavedash",
33
+ "wrapper",
34
+ "typescript"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "exports": {
40
+ ".": {
41
+ "types": "./dist/index.d.ts",
42
+ "import": "./dist/index.js",
43
+ "require": "./dist/index.cjs"
44
+ }
45
+ },
46
+ "peerDependencies": {
47
+ "react": ">=18",
48
+ "@wvdsh/sdk-js": "^1.3.6"
49
+ }
50
+ }