react-achievements 3.9.1 → 4.0.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.
Files changed (52) hide show
  1. package/README.md +148 -101
  2. package/dist/headless.cjs +317 -0
  3. package/dist/headless.cjs.map +1 -0
  4. package/dist/headless.d.ts +176 -0
  5. package/dist/headless.esm.js +222 -0
  6. package/dist/headless.esm.js.map +1 -0
  7. package/dist/index.cjs +839 -881
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.ts +163 -153
  10. package/dist/index.esm.js +835 -883
  11. package/dist/index.esm.js.map +1 -1
  12. package/dist/web.cjs +1416 -0
  13. package/dist/web.cjs.map +1 -0
  14. package/dist/web.d.ts +534 -0
  15. package/dist/web.esm.js +1306 -0
  16. package/dist/web.esm.js.map +1 -0
  17. package/package.json +13 -28
  18. package/dist/types/__mocks__/confetti-wrapper.d.ts +0 -5
  19. package/dist/types/__mocks__/react-confetti.d.ts +0 -3
  20. package/dist/types/__mocks__/react-toastify.d.ts +0 -13
  21. package/dist/types/core/components/BadgesButton.d.ts +0 -25
  22. package/dist/types/core/components/BadgesButtonWithModal.d.ts +0 -53
  23. package/dist/types/core/components/BadgesModal.d.ts +0 -14
  24. package/dist/types/core/components/ConfettiWrapper.d.ts +0 -6
  25. package/dist/types/core/errors/AchievementErrors.d.ts +0 -55
  26. package/dist/types/core/hooks/useWindowSize.d.ts +0 -16
  27. package/dist/types/core/icons/defaultIcons.d.ts +0 -8
  28. package/dist/types/core/storage/AsyncStorageAdapter.d.ts +0 -48
  29. package/dist/types/core/storage/IndexedDBStorage.d.ts +0 -29
  30. package/dist/types/core/storage/LocalStorage.d.ts +0 -16
  31. package/dist/types/core/storage/MemoryStorage.d.ts +0 -11
  32. package/dist/types/core/storage/OfflineQueueStorage.d.ts +0 -42
  33. package/dist/types/core/storage/RestApiStorage.d.ts +0 -20
  34. package/dist/types/core/styles/defaultStyles.d.ts +0 -2
  35. package/dist/types/core/types.d.ts +0 -115
  36. package/dist/types/core/ui/BuiltInConfetti.d.ts +0 -7
  37. package/dist/types/core/ui/BuiltInModal.d.ts +0 -7
  38. package/dist/types/core/ui/BuiltInNotification.d.ts +0 -7
  39. package/dist/types/core/ui/LegacyWrappers.d.ts +0 -21
  40. package/dist/types/core/ui/interfaces.d.ts +0 -127
  41. package/dist/types/core/ui/legacyDetector.d.ts +0 -40
  42. package/dist/types/core/ui/themes.d.ts +0 -14
  43. package/dist/types/core/utils/configNormalizer.d.ts +0 -3
  44. package/dist/types/core/utils/dataExport.d.ts +0 -34
  45. package/dist/types/core/utils/dataImport.d.ts +0 -50
  46. package/dist/types/hooks/useAchievementEngine.d.ts +0 -36
  47. package/dist/types/hooks/useAchievements.d.ts +0 -1
  48. package/dist/types/hooks/useSimpleAchievements.d.ts +0 -63
  49. package/dist/types/index.d.ts +0 -36
  50. package/dist/types/providers/AchievementProvider.d.ts +0 -47
  51. package/dist/types/setupTests.d.ts +0 -1
  52. package/dist/types/utils/achievementHelpers.d.ts +0 -135
package/README.md CHANGED
@@ -1,10 +1,8 @@
1
1
  # React Achievements
2
2
 
3
- **Add gamification to your React app in 5 minutes** - Unlock achievements, celebrate milestones, delight users.
3
+ **Add gamification to your React app in minutes** - Track progress, unlock achievements, show badges, and celebrate milestones.
4
4
 
5
- [![Demo video](https://raw.githubusercontent.com/dave-b-b/react-achievements/main/assets/achievements.png)](https://github.com/user-attachments/assets/a33fdae5-439b-4fc9-a388-ccb2f432a3a8)
6
-
7
- [📚 Documentation](https://dave-b-b.github.io/react-achievements/) | [🎮 Interactive Demo](https://dave-b-b.github.io/react-achievements/?path=/story/introduction--page) | [📦 npm Package](https://www.npmjs.com/package/react-achievements)
5
+ [📚 Documentation](https://dave-b-b.github.io/react-achievements/) | [📦 npm Package](https://www.npmjs.com/package/react-achievements)
8
6
 
9
7
  [![npm version](https://img.shields.io/npm/v/react-achievements.svg)](https://www.npmjs.com/package/react-achievements) [![License](https://img.shields.io/badge/license-Dual%20(MIT%20%2B%20Commercial)-blue.svg)](./LICENSE) [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
10
8
 
@@ -14,170 +12,219 @@
14
12
  npm install react-achievements
15
13
  ```
16
14
 
17
- **Requirements:** React 17.0+, Node.js 16+
18
-
19
- ---
15
+ **Requirements:** React 16.8+, Node.js 16+
20
16
 
21
- ## Start Here (60 Seconds)
17
+ ## Start Here
22
18
 
23
19
  ```tsx
24
- import { AchievementProvider, useSimpleAchievements, BadgesButtonWithModal } from 'react-achievements';
20
+ import {
21
+ AchievementProvider,
22
+ AchievementsWidget,
23
+ useSimpleAchievements,
24
+ } from 'react-achievements';
25
25
 
26
26
  const achievements = {
27
27
  score: {
28
28
  100: { title: 'Century!', description: 'Score 100 points', icon: '🏆' },
29
- }
29
+ },
30
30
  };
31
31
 
32
- function AchievementsUI() {
33
- const { track, unlocked } = useSimpleAchievements();
32
+ function Game() {
33
+ const { track } = useSimpleAchievements();
34
34
 
35
35
  return (
36
- <div>
37
- <button onClick={() => track('score', 100)}>Score 100</button>
38
- <BadgesButtonWithModal unlockedAchievements={unlocked} />
39
- </div>
36
+ <button onClick={() => track('score', 100)}>
37
+ Score 100
38
+ </button>
40
39
  );
41
40
  }
42
41
 
43
42
  export default function App() {
44
43
  return (
45
- <AchievementProvider achievements={achievements} useBuiltInUI={true}>
46
- <AchievementsUI />
44
+ <AchievementProvider achievements={achievements}>
45
+ <Game />
46
+ <AchievementsWidget />
47
47
  </AchievementProvider>
48
48
  );
49
49
  }
50
50
  ```
51
51
 
52
- ---
52
+ `AchievementsWidget` reads from context, shows the unlocked count, and opens a modal with locked and unlocked achievements. Use `placement="inline"` to put it in a drawer, sidebar, or navigation area. For an exact visual match, pass `renderTrigger` and use your app's own drawer row, nav item, or profile menu button while the widget still controls the modal.
53
53
 
54
- ## Usage
55
-
56
- React Achievements supports two tracking patterns:
54
+ ```tsx
55
+ <AchievementsWidget
56
+ placement="inline"
57
+ renderTrigger={({ buttonProps, unlockedCount, totalCount }) => (
58
+ <button {...buttonProps} className="drawer-row">
59
+ Achievements
60
+ <span>{unlockedCount}/{totalCount}</span>
61
+ </button>
62
+ )}
63
+ />
64
+ ```
57
65
 
58
- ### Pattern 1: Event-Based Tracking
66
+ ## Common Placements
59
67
 
60
- Track achievements using semantic events. Perfect for complex applications or multi-framework projects.
68
+ Use the same context-aware UI in whichever surface already fits your app:
61
69
 
62
70
  ```tsx
63
- // achievementEngine.ts
64
- import { AchievementEngine } from 'react-achievements';
71
+ import { useState } from 'react';
72
+ import {
73
+ AchievementsList,
74
+ AchievementsModal,
75
+ AchievementsWidget,
76
+ } from 'react-achievements';
65
77
 
66
- const achievements = {
67
- score: {
68
- 100: { title: 'Century!', description: 'Score 100 points', icon: '🏆' },
69
- }
70
- };
78
+ // Floating launcher in a corner
79
+ <AchievementsWidget position="bottom-right" />
71
80
 
72
- const eventMapping = {
73
- 'userScored': (data) => ({ score: data.points }),
74
- };
81
+ // Inline nav, drawer, sidebar, or profile menu item
82
+ <AchievementsWidget placement="inline" label="Badges" />
75
83
 
76
- export const engine = new AchievementEngine({
77
- achievements,
78
- eventMapping,
79
- storage: 'local'
80
- });
81
- ```
84
+ // Existing button or drawer row that opens the built-in modal
85
+ const [open, setOpen] = useState(false);
82
86
 
83
- ```tsx
84
- // App.tsx
85
- import { AchievementProvider } from 'react-achievements';
86
- import { engine } from './achievementEngine';
87
+ <button onClick={() => setOpen(true)}>View achievements</button>
88
+ <AchievementsModal isOpen={open} onClose={() => setOpen(false)} />
87
89
 
88
- function App() {
89
- return (
90
- <AchievementProvider engine={engine} useBuiltInUI={true}>
91
- <Game />
92
- </AchievementProvider>
93
- );
94
- }
90
+ // Inline achievements page, panel, drawer, or settings section
91
+ <AchievementsList showLocked />
95
92
  ```
96
93
 
97
- ```tsx
98
- // Game.tsx
99
- import { useAchievementEngine } from 'react-achievements';
94
+ Storybook includes examples for floating buttons, nav buttons, drawer rows, existing controls that open a modal, dashboard cards, profile menus, and inline lists.
100
95
 
101
- function Game() {
102
- const engine = useAchievementEngine();
103
-
104
- return (
105
- <button onClick={() => engine.emit('userScored', { points: 100 })}>
106
- Score Points
107
- </button>
108
- );
109
- }
96
+ Provider-level icons and UI options are shared across notifications, widgets, modals, and lists:
97
+
98
+ ```tsx
99
+ <AchievementProvider
100
+ achievements={achievements}
101
+ icons={{ login: '🔑', streak: '🔥' }}
102
+ ui={{
103
+ theme: 'minimal',
104
+ NotificationComponent: MyNotification,
105
+ ModalComponent: MyAchievementsModal,
106
+ ConfettiComponent: MyConfetti,
107
+ }}
108
+ >
109
+ <App />
110
+ </AchievementProvider>
110
111
  ```
111
112
 
112
- ➡️ **[Event-Based Tracking Guide](https://dave-b-b.github.io/react-achievements/docs/guides/event-based-tracking)**
113
+ ## Hooks
113
114
 
114
- ---
115
+ ```tsx
116
+ const {
117
+ track,
118
+ increment,
119
+ trackMultiple,
120
+ unlockedIds,
121
+ unlockedAchievements,
122
+ allAchievements,
123
+ unlockedCount,
124
+ totalCount,
125
+ } = useSimpleAchievements();
126
+ ```
115
127
 
116
- ### Pattern 2: Direct Track Updates
128
+ Deprecated aliases from v3, including `unlocked`, remain available until `4.2`.
117
129
 
118
- Update metrics directly in your React components. Perfect for simple applications or quick prototypes.
130
+ ## Event-Based Tracking
119
131
 
120
- ```tsx
121
- // achievements.ts
122
- const achievements = {
123
- score: {
124
- 100: { title: 'Century!', description: 'Score 100 points', icon: '🏆' },
125
- }
126
- };
127
- ```
132
+ For larger apps, create an engine and emit semantic events:
128
133
 
129
134
  ```tsx
130
- // App.tsx
131
- import { AchievementProvider } from 'react-achievements';
135
+ import {
136
+ AchievementEngine,
137
+ AchievementProvider,
138
+ AchievementsWidget,
139
+ useAchievementEngine,
140
+ } from 'react-achievements';
141
+
142
+ const engine = new AchievementEngine({
143
+ achievements,
144
+ eventMapping: {
145
+ userScored: (data) => ({ score: data.points }),
146
+ },
147
+ storage: 'local',
148
+ });
132
149
 
133
- function App() {
150
+ function Game() {
151
+ const engine = useAchievementEngine();
152
+ return <button onClick={() => engine.emit('userScored', { points: 100 })}>Score</button>;
153
+ }
154
+
155
+ export default function App() {
134
156
  return (
135
- <AchievementProvider achievements={achievements} useBuiltInUI={true}>
157
+ <AchievementProvider engine={engine}>
136
158
  <Game />
159
+ <AchievementsWidget />
137
160
  </AchievementProvider>
138
161
  );
139
162
  }
140
163
  ```
141
164
 
165
+ ## Headless Usage
166
+
167
+ Use the DOM-free entry point when building custom UI or preparing a React Native integration:
168
+
142
169
  ```tsx
143
- // Game.tsx
144
- import { useSimpleAchievements, BadgesButtonWithModal } from 'react-achievements';
170
+ import {
171
+ AchievementProvider,
172
+ useAchievementState,
173
+ useSimpleAchievements,
174
+ } from 'react-achievements/headless';
145
175
 
146
- function Game() {
147
- const { track, unlocked } = useSimpleAchievements();
176
+ function CustomAchievementsPanel() {
177
+ const { track } = useSimpleAchievements();
178
+ const { allAchievements, unlockedCount, totalCount } = useAchievementState();
179
+
180
+ return (
181
+ <section>
182
+ <button onClick={() => track('score', 100)}>Score 100</button>
183
+ <p>{unlockedCount} / {totalCount} unlocked</p>
184
+
185
+ {allAchievements.map((achievement) => (
186
+ <div key={achievement.achievementId}>
187
+ {achievement.isUnlocked ? 'Unlocked' : 'Locked'}: {achievement.achievementTitle}
188
+ </div>
189
+ ))}
190
+ </section>
191
+ );
192
+ }
148
193
 
194
+ export function App() {
149
195
  return (
150
- <div>
151
- <button onClick={() => track('score', 100)}>Score Points</button>
152
- <BadgesButtonWithModal unlockedAchievements={unlocked} />
153
- </div>
196
+ <AchievementProvider achievements={achievements}>
197
+ <CustomAchievementsPanel />
198
+ </AchievementProvider>
154
199
  );
155
200
  }
156
201
  ```
157
202
 
158
- ➡️ **[Direct Updates Guide](https://dave-b-b.github.io/react-achievements/docs/guides/direct-updates)**
203
+ React Native UI components are not included in `4.0`; use `achievements-engine` or the `/headless` React APIs with your own native UI.
159
204
 
160
- ---
205
+ ## Entry Points
161
206
 
162
- ## Documentation
207
+ - `react-achievements` - v4 web API with provider, hooks, built-in effects, widget, modal, and list components
208
+ - `react-achievements/web` - explicit web entry point
209
+ - `react-achievements/headless` - provider, hooks, engine, storage, and types without DOM UI
163
210
 
164
- 📚 **[Full Documentation](https://dave-b-b.github.io/react-achievements/)** - Complete guides, API reference, and examples
211
+ ## Migrating From v3
165
212
 
166
- ---
213
+ - Built-in UI is now the default; `useBuiltInUI` is a deprecated no-op.
214
+ - `AchievementsWidget` replaces the legacy manual `BadgesButtonWithModal` setup.
215
+ - `useSimpleAchievements()` now returns `unlockedIds`, `unlockedAchievements`, and `allAchievements`.
216
+ - External UI peer dependencies are no longer required.
217
+ - Deprecated v3 component names remain as compatibility wrappers until `4.2`.
167
218
 
168
219
  ## License
169
220
 
170
- React Achievements is **dual-licensed**:
171
-
172
- - **Free for Non-Commercial Use** (MIT License) - Personal projects, education, non-profits, open source
173
- - **Commercial License Required** - Businesses, SaaS, commercial apps, enterprise
174
-
175
- **[Get Commercial License →](https://github.com/sponsors/dave-b-b)** | **[License Details](./LICENSE)** | **[Commercial Terms](./COMMERCIAL-LICENSE.md)**
221
+ React Achievements is dual-licensed:
176
222
 
177
- ---
223
+ - **Free for Non-Commercial Use** (MIT License)
224
+ - **Commercial License Required** for businesses, SaaS, commercial apps, and enterprise use
178
225
 
179
- **Built with ❤️ by [Dave B](https://github.com/dave-b-b)** | [📚 Documentation](https://dave-b-b.github.io/react-achievements/) | [ Star on GitHub](https://github.com/dave-b-b/react-achievements)
226
+ [Get Commercial License](https://github.com/sponsors/dave-b-b) | [License Details](./LICENSE) | [Commercial Terms](./COMMERCIAL-LICENSE.md)
180
227
 
181
228
  ## AI Agents
182
229
 
183
- If you're using AI coding agents, see `AGENTS.md` for a concise integration prompt, pitfalls, and the recommended API.
230
+ If you're using AI coding agents, see `AGENTS.md` for the recommended v4 integration prompt.
@@ -0,0 +1,317 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var achievementsEngine = require('achievements-engine');
5
+
6
+ // Type guard to detect async storage
7
+ function isAsyncStorage(storage) {
8
+ // Check if methods return Promises
9
+ const testResult = storage.getMetrics();
10
+ return testResult && typeof testResult.then === 'function';
11
+ }
12
+ var StorageType;
13
+ (function (StorageType) {
14
+ StorageType["Local"] = "local";
15
+ StorageType["Memory"] = "memory";
16
+ StorageType["IndexedDB"] = "indexeddb";
17
+ StorageType["RestAPI"] = "restapi"; // Asynchronous REST API storage
18
+ })(StorageType || (StorageType = {}));
19
+
20
+ const warnedMessages = new Set();
21
+ function warnDeprecation(message) {
22
+ var _a, _b;
23
+ const isProduction = typeof globalThis !== 'undefined' &&
24
+ ((_b = (_a = globalThis.process) === null || _a === void 0 ? void 0 : _a.env) === null || _b === void 0 ? void 0 : _b.NODE_ENV) === 'production';
25
+ if (isProduction || warnedMessages.has(message)) {
26
+ return;
27
+ }
28
+ warnedMessages.add(message);
29
+ console.warn(`[react-achievements] ${message}`);
30
+ }
31
+
32
+ const AchievementContext = React.createContext(undefined);
33
+ const getAllAchievementRecord = (engine) => {
34
+ return Object.fromEntries(engine.getAllAchievements().map((achievement) => [
35
+ achievement.achievementId,
36
+ achievement,
37
+ ]));
38
+ };
39
+ const AchievementProvider = ({ achievements: achievementsConfig, storage = 'local', children, onError, useBuiltInUI, restApiConfig, engine: externalEngine, eventMapping, icons = {}, }) => {
40
+ if (useBuiltInUI !== undefined) {
41
+ warnDeprecation('`useBuiltInUI` is deprecated and is now a no-op because built-in UI is the default. It will be removed in 4.2.');
42
+ }
43
+ if (achievementsConfig && externalEngine) {
44
+ throw new Error('Cannot provide both "achievements" and "engine" props to AchievementProvider.\n\n' +
45
+ 'Choose one pattern:\n' +
46
+ '1. Direct metric tracking: <AchievementProvider achievements={config}>\n' +
47
+ '2. Event-based tracking: <AchievementProvider engine={myEngine}>');
48
+ }
49
+ const isProviderCreatedEngine = Boolean(achievementsConfig);
50
+ const [engine] = React.useState(() => {
51
+ if (externalEngine) {
52
+ return externalEngine;
53
+ }
54
+ if (!achievementsConfig) {
55
+ throw new Error('AchievementProvider requires either "achievements" or "engine" prop.\n\n' +
56
+ '1. Direct metric tracking: <AchievementProvider achievements={config}>\n' +
57
+ '2. Event-based tracking: <AchievementProvider engine={myEngine}>');
58
+ }
59
+ return new achievementsEngine.AchievementEngine({
60
+ achievements: achievementsConfig,
61
+ storage: storage,
62
+ restApiConfig,
63
+ onError: onError,
64
+ eventMapping,
65
+ });
66
+ });
67
+ const [achievementState, setAchievementState] = React.useState(() => ({
68
+ unlocked: [...engine.getUnlocked()],
69
+ all: getAllAchievementRecord(engine),
70
+ }));
71
+ const syncAchievementState = React.useCallback(() => {
72
+ setAchievementState({
73
+ unlocked: [...engine.getUnlocked()],
74
+ all: getAllAchievementRecord(engine),
75
+ });
76
+ }, [engine]);
77
+ React.useEffect(() => {
78
+ return () => {
79
+ if (!externalEngine) {
80
+ engine.destroy();
81
+ }
82
+ };
83
+ }, [engine, externalEngine]);
84
+ React.useEffect(() => {
85
+ const unsubscribeUnlocked = engine.on('achievement:unlocked', syncAchievementState);
86
+ const unsubscribeStateChanged = engine.on('state:changed', syncAchievementState);
87
+ return () => {
88
+ unsubscribeUnlocked();
89
+ unsubscribeStateChanged();
90
+ };
91
+ }, [engine, syncAchievementState]);
92
+ const update = (newMetrics) => {
93
+ engine.update(newMetrics);
94
+ };
95
+ const reset = () => {
96
+ engine.reset();
97
+ syncAchievementState();
98
+ };
99
+ const getState = () => {
100
+ const metrics = engine.getMetrics();
101
+ const unlocked = engine.getUnlocked();
102
+ const metricsInArrayFormat = {};
103
+ Object.entries(metrics).forEach(([key, value]) => {
104
+ metricsInArrayFormat[key] = Array.isArray(value) ? value : [value];
105
+ });
106
+ return {
107
+ metrics: metricsInArrayFormat,
108
+ unlocked: [...unlocked],
109
+ };
110
+ };
111
+ const exportData = () => {
112
+ return engine.export();
113
+ };
114
+ const importData = (jsonString, options) => {
115
+ const result = engine.import(jsonString, options);
116
+ syncAchievementState();
117
+ return result;
118
+ };
119
+ const getAllAchievements = () => {
120
+ return engine.getAllAchievements();
121
+ };
122
+ return (React.createElement(AchievementContext.Provider, { value: {
123
+ update,
124
+ achievements: achievementState,
125
+ reset,
126
+ getState,
127
+ exportData,
128
+ importData,
129
+ getAllAchievements,
130
+ engine,
131
+ icons,
132
+ _isLegacyPattern: isProviderCreatedEngine,
133
+ } }, children));
134
+ };
135
+
136
+ const useAchievements = () => {
137
+ const context = React.useContext(AchievementContext);
138
+ if (!context) {
139
+ throw new Error('useAchievements must be used within an AchievementProvider');
140
+ }
141
+ return context;
142
+ };
143
+
144
+ const useAchievementState = () => {
145
+ const { achievements, getAllAchievements, getState } = useAchievements();
146
+ const allAchievements = getAllAchievements();
147
+ const unlockedIds = achievements.unlocked;
148
+ const unlockedAchievementSet = new Set(unlockedIds);
149
+ const unlockedAchievements = allAchievements.filter((achievement) => unlockedAchievementSet.has(achievement.achievementId));
150
+ return {
151
+ unlockedIds,
152
+ unlockedAchievements,
153
+ allAchievements,
154
+ unlockedCount: unlockedIds.length,
155
+ totalCount: allAchievements.length,
156
+ metrics: getState().metrics,
157
+ };
158
+ };
159
+
160
+ /**
161
+ * A simplified hook for achievement tracking.
162
+ * Provides the v4 happy path for direct metric updates plus explicit state names.
163
+ */
164
+ const useSimpleAchievements = () => {
165
+ const { update, reset, getState, exportData, importData } = useAchievements();
166
+ const achievementState = useAchievementState();
167
+ const track = (metric, value) => update({ [metric]: value });
168
+ const increment = (metric, amount = 1) => {
169
+ const currentState = getState();
170
+ const currentMetricArray = currentState.metrics[metric] || [0];
171
+ const currentValue = Array.isArray(currentMetricArray)
172
+ ? currentMetricArray[0]
173
+ : currentMetricArray;
174
+ const newValue = (typeof currentValue === 'number' ? currentValue : 0) + amount;
175
+ update({ [metric]: newValue });
176
+ };
177
+ const trackMultiple = (metrics) => update(metrics);
178
+ return {
179
+ track,
180
+ increment,
181
+ trackMultiple,
182
+ unlockedIds: achievementState.unlockedIds,
183
+ unlockedAchievements: achievementState.unlockedAchievements,
184
+ allAchievements: achievementState.allAchievements,
185
+ unlockedCount: achievementState.unlockedCount,
186
+ totalCount: achievementState.totalCount,
187
+ metrics: achievementState.metrics,
188
+ reset,
189
+ getState,
190
+ exportData,
191
+ importData,
192
+ getAllAchievements: () => achievementState.allAchievements,
193
+ /**
194
+ * @deprecated Use `unlockedIds` instead. This alias will be removed in 4.2.
195
+ */
196
+ unlocked: achievementState.unlockedIds,
197
+ /**
198
+ * @deprecated Use `allAchievements` instead. This alias will be removed in 4.2.
199
+ */
200
+ all: achievementState.allAchievements,
201
+ };
202
+ };
203
+
204
+ /**
205
+ * Access the active AchievementEngine instance.
206
+ *
207
+ * In v4 this works with both provider-created engines (`achievements` prop) and
208
+ * injected engines (`engine` prop).
209
+ */
210
+ const useAchievementEngine = () => {
211
+ const context = React.useContext(AchievementContext);
212
+ if (!context) {
213
+ throw new Error('useAchievementEngine must be used within an AchievementProvider.\n\n' +
214
+ 'Wrap your component tree:\n' +
215
+ '<AchievementProvider achievements={achievements}>\n' +
216
+ ' <YourComponent />\n' +
217
+ '</AchievementProvider>');
218
+ }
219
+ return context.engine;
220
+ };
221
+
222
+ Object.defineProperty(exports, 'AchievementBuilder', {
223
+ enumerable: true,
224
+ get: function () { return achievementsEngine.AchievementBuilder; }
225
+ });
226
+ Object.defineProperty(exports, 'AchievementEngine', {
227
+ enumerable: true,
228
+ get: function () { return achievementsEngine.AchievementEngine; }
229
+ });
230
+ Object.defineProperty(exports, 'AchievementError', {
231
+ enumerable: true,
232
+ get: function () { return achievementsEngine.AchievementError; }
233
+ });
234
+ Object.defineProperty(exports, 'AsyncStorageAdapter', {
235
+ enumerable: true,
236
+ get: function () { return achievementsEngine.AsyncStorageAdapter; }
237
+ });
238
+ Object.defineProperty(exports, 'ConfigurationError', {
239
+ enumerable: true,
240
+ get: function () { return achievementsEngine.ConfigurationError; }
241
+ });
242
+ Object.defineProperty(exports, 'ImportValidationError', {
243
+ enumerable: true,
244
+ get: function () { return achievementsEngine.ImportValidationError; }
245
+ });
246
+ Object.defineProperty(exports, 'IndexedDBStorage', {
247
+ enumerable: true,
248
+ get: function () { return achievementsEngine.IndexedDBStorage; }
249
+ });
250
+ Object.defineProperty(exports, 'LocalStorage', {
251
+ enumerable: true,
252
+ get: function () { return achievementsEngine.LocalStorage; }
253
+ });
254
+ Object.defineProperty(exports, 'MemoryStorage', {
255
+ enumerable: true,
256
+ get: function () { return achievementsEngine.MemoryStorage; }
257
+ });
258
+ Object.defineProperty(exports, 'OfflineQueueStorage', {
259
+ enumerable: true,
260
+ get: function () { return achievementsEngine.OfflineQueueStorage; }
261
+ });
262
+ Object.defineProperty(exports, 'RestApiStorage', {
263
+ enumerable: true,
264
+ get: function () { return achievementsEngine.RestApiStorage; }
265
+ });
266
+ Object.defineProperty(exports, 'StorageError', {
267
+ enumerable: true,
268
+ get: function () { return achievementsEngine.StorageError; }
269
+ });
270
+ Object.defineProperty(exports, 'StorageQuotaError', {
271
+ enumerable: true,
272
+ get: function () { return achievementsEngine.StorageQuotaError; }
273
+ });
274
+ Object.defineProperty(exports, 'StorageType', {
275
+ enumerable: true,
276
+ get: function () { return achievementsEngine.StorageType; }
277
+ });
278
+ Object.defineProperty(exports, 'SyncError', {
279
+ enumerable: true,
280
+ get: function () { return achievementsEngine.SyncError; }
281
+ });
282
+ Object.defineProperty(exports, 'createConfigHash', {
283
+ enumerable: true,
284
+ get: function () { return achievementsEngine.createConfigHash; }
285
+ });
286
+ Object.defineProperty(exports, 'exportAchievementData', {
287
+ enumerable: true,
288
+ get: function () { return achievementsEngine.exportAchievementData; }
289
+ });
290
+ Object.defineProperty(exports, 'importAchievementData', {
291
+ enumerable: true,
292
+ get: function () { return achievementsEngine.importAchievementData; }
293
+ });
294
+ Object.defineProperty(exports, 'isAchievementError', {
295
+ enumerable: true,
296
+ get: function () { return achievementsEngine.isAchievementError; }
297
+ });
298
+ Object.defineProperty(exports, 'isRecoverableError', {
299
+ enumerable: true,
300
+ get: function () { return achievementsEngine.isRecoverableError; }
301
+ });
302
+ Object.defineProperty(exports, 'isSimpleConfig', {
303
+ enumerable: true,
304
+ get: function () { return achievementsEngine.isSimpleConfig; }
305
+ });
306
+ Object.defineProperty(exports, 'normalizeAchievements', {
307
+ enumerable: true,
308
+ get: function () { return achievementsEngine.normalizeAchievements; }
309
+ });
310
+ exports.AchievementContext = AchievementContext;
311
+ exports.AchievementProvider = AchievementProvider;
312
+ exports.isAsyncStorage = isAsyncStorage;
313
+ exports.useAchievementEngine = useAchievementEngine;
314
+ exports.useAchievementState = useAchievementState;
315
+ exports.useAchievements = useAchievements;
316
+ exports.useSimpleAchievements = useSimpleAchievements;
317
+ //# sourceMappingURL=headless.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless.cjs","sources":["../src/core/types.ts","../src/core/utils/deprecation.ts","../src/providers/AchievementProvider.tsx","../src/hooks/useAchievements.ts","../src/hooks/useAchievementState.ts","../src/hooks/useSimpleAchievements.ts","../src/hooks/useAchievementEngine.ts"],"sourcesContent":[null,null,null,null,null,null,null],"names":["createContext","useState","AchievementEngine","useCallback","useEffect","useContext"],"mappings":";;;;;AAgFA;AACM,SAAU,cAAc,CAAC,OAA8B,EAAA;;AAEzD,IAAA,MAAM,UAAU,GAAI,OAAe,CAAC,UAAU,EAAE,CAAC;IACjD,OAAO,UAAU,IAAI,OAAO,UAAU,CAAC,IAAI,KAAK,UAAU,CAAC;AAC/D,CAAC;AA6DD,IAAY,WAKX,CAAA;AALD,CAAA,UAAY,WAAW,EAAA;AACnB,IAAA,WAAA,CAAA,OAAA,CAAA,GAAA,OAAe,CAAA;AACf,IAAA,WAAA,CAAA,QAAA,CAAA,GAAA,QAAiB,CAAA;AACjB,IAAA,WAAA,CAAA,WAAA,CAAA,GAAA,WAAuB,CAAA;IACvB,WAAmB,CAAA,SAAA,CAAA,GAAA,SAAA,CAAA;AACvB,CAAC,EALW,WAAW,KAAX,WAAW,GAKtB,EAAA,CAAA,CAAA;;ACvJD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;AAEnC,SAAU,eAAe,CAAC,OAAe,EAAA;;AAC7C,IAAA,MAAM,YAAY,GAChB,OAAO,UAAU,KAAK,WAAW;QACjC,CAAA,CAAA,EAAA,GAAA,CAAC,EAAA,GAAA,UAAkB,CAAC,OAAO,MAAE,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,GAAG,MAAE,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,QAAQ,MAAK,YAAY,CAAC;IAE9D,IAAI,YAAY,IAAI,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;QAC/C,OAAO;KACR;AAED,IAAA,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC5B,IAAA,OAAO,CAAC,IAAI,CAAC,wBAAwB,OAAO,CAAA,CAAE,CAAC,CAAC;AAClD;;MCyBa,kBAAkB,GAAGA,mBAAa,CAAqC,SAAS,EAAE;AAkB/F,MAAM,uBAAuB,GAAG,CAC9B,MAAyB,KACgB;AACzC,IAAA,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,kBAAkB,EAAE,CAAC,GAAG,CAAC,CAAC,WAAW,KAAK;AAC/C,QAAA,WAAW,CAAC,aAAa;QACzB,WAAW;AACZ,KAAA,CAAC,CACH,CAAC;AACJ,CAAC,CAAC;AAEK,MAAM,mBAAmB,GAAuC,CAAC,EACtE,YAAY,EAAE,kBAAkB,EAChC,OAAO,GAAG,OAAO,EACjB,QAAQ,EACR,OAAO,EACP,YAAY,EACZ,aAAa,EACb,MAAM,EAAE,cAAc,EACtB,YAAY,EACZ,KAAK,GAAG,EAAE,GACX,KAAI;AACH,IAAA,IAAI,YAAY,KAAK,SAAS,EAAE;QAC9B,eAAe,CACb,gHAAgH,CACjH,CAAC;KACH;AAED,IAAA,IAAI,kBAAkB,IAAI,cAAc,EAAE;QACxC,MAAM,IAAI,KAAK,CACb,mFAAmF;YACjF,uBAAuB;YACvB,0EAA0E;AAC1E,YAAA,kEAAkE,CACrE,CAAC;KACH;AAED,IAAA,MAAM,uBAAuB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAE5D,IAAA,MAAM,CAAC,MAAM,CAAC,GAAGC,cAAQ,CAAoB,MAAK;QAChD,IAAI,cAAc,EAAE;AAClB,YAAA,OAAO,cAAc,CAAC;SACvB;QAED,IAAI,CAAC,kBAAkB,EAAE;YACvB,MAAM,IAAI,KAAK,CACb,0EAA0E;gBACxE,0EAA0E;AAC1E,gBAAA,kEAAkE,CACrE,CAAC;SACH;QAED,OAAO,IAAIC,oCAAiB,CAAC;AAC3B,YAAA,YAAY,EAAE,kBAAkB;AAChC,YAAA,OAAO,EAAE,OAAc;YACvB,aAAa;AACb,YAAA,OAAO,EAAE,OAA+C;YACxD,YAAY;AACb,SAAA,CAAC,CAAC;AACL,KAAC,CAAC,CAAC;IAEH,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAGD,cAAQ,CAGrD,OAAO;AACR,QAAA,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;AACnC,QAAA,GAAG,EAAE,uBAAuB,CAAC,MAAM,CAAC;AACrC,KAAA,CAAC,CAAC,CAAC;AAEJ,IAAA,MAAM,oBAAoB,GAAGE,iBAAW,CAAC,MAAK;AAC5C,QAAA,mBAAmB,CAAC;AAClB,YAAA,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;AACnC,YAAA,GAAG,EAAE,uBAAuB,CAAC,MAAM,CAAC;AACrC,SAAA,CAAC,CAAC;AACL,KAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEbC,eAAS,CAAC,MAAK;AACb,QAAA,OAAO,MAAK;YACV,IAAI,CAAC,cAAc,EAAE;gBACnB,MAAM,CAAC,OAAO,EAAE,CAAC;aAClB;AACH,SAAC,CAAC;AACJ,KAAC,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;IAE7BA,eAAS,CAAC,MAAK;QACb,MAAM,mBAAmB,GAAG,MAAM,CAAC,EAAE,CAAC,sBAAsB,EAAE,oBAAoB,CAAC,CAAC;QACpF,MAAM,uBAAuB,GAAG,MAAM,CAAC,EAAE,CAAC,eAAe,EAAE,oBAAoB,CAAC,CAAC;AAEjF,QAAA,OAAO,MAAK;AACV,YAAA,mBAAmB,EAAE,CAAC;AACtB,YAAA,uBAAuB,EAAE,CAAC;AAC5B,SAAC,CAAC;AACJ,KAAC,EAAE,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;AAEnC,IAAA,MAAM,MAAM,GAAG,CAAC,UAA+B,KAAI;AACjD,QAAA,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAC5B,KAAC,CAAC;IAEF,MAAM,KAAK,GAAG,MAAK;QACjB,MAAM,CAAC,KAAK,EAAE,CAAC;AACf,QAAA,oBAAoB,EAAE,CAAC;AACzB,KAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAK;AACpB,QAAA,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;AACpC,QAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;QACtC,MAAM,oBAAoB,GAAwB,EAAE,CAAC;AAErD,QAAA,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,KAAI;YAC/C,oBAAoB,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC;AACrE,SAAC,CAAC,CAAC;QAEH,OAAO;AACL,YAAA,OAAO,EAAE,oBAAoB;AAC7B,YAAA,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC;SACxB,CAAC;AACJ,KAAC,CAAC;IAEF,MAAM,UAAU,GAAG,MAAa;AAC9B,QAAA,OAAO,MAAM,CAAC,MAAM,EAAE,CAAC;AACzB,KAAC,CAAC;AAEF,IAAA,MAAM,UAAU,GAAG,CAAC,UAAkB,EAAE,OAAuB,KAAkB;QAC/E,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AAClD,QAAA,oBAAoB,EAAE,CAAC;AACvB,QAAA,OAAO,MAAM,CAAC;AAChB,KAAC,CAAC;IAEF,MAAM,kBAAkB,GAAG,MAA8B;AACvD,QAAA,OAAO,MAAM,CAAC,kBAAkB,EAAE,CAAC;AACrC,KAAC,CAAC;AAEF,IAAA,QACE,KAAC,CAAA,aAAA,CAAA,kBAAkB,CAAC,QAAQ,EAAA,EAC1B,KAAK,EAAE;YACL,MAAM;AACN,YAAA,YAAY,EAAE,gBAAgB;YAC9B,KAAK;YACL,QAAQ;YACR,UAAU;YACV,UAAU;YACV,kBAAkB;YAClB,MAAM;YACN,KAAK;AACL,YAAA,gBAAgB,EAAE,uBAAuB;SAC1C,EAEA,EAAA,QAAQ,CACmB,EAC9B;AACJ;;AC3MO,MAAM,eAAe,GAAG,MAAK;AAClC,IAAA,MAAM,OAAO,GAAGC,gBAAU,CAAC,kBAAkB,CAAC,CAAC;IAE/C,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;KAC/E;AAED,IAAA,OAAO,OAAO,CAAC;AACjB;;ACTO,MAAM,mBAAmB,GAAG,MAAK;IACtC,MAAM,EAAE,YAAY,EAAE,kBAAkB,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE,CAAC;AACzE,IAAA,MAAM,eAAe,GAAG,kBAAkB,EAAE,CAAC;AAC7C,IAAA,MAAM,WAAW,GAAG,YAAY,CAAC,QAAQ,CAAC;AAC1C,IAAA,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IACpD,MAAM,oBAAoB,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,WAAW,KAC9D,sBAAsB,CAAC,GAAG,CAAC,WAAW,CAAC,aAAa,CAAC,CACtD,CAAC;IAEF,OAAO;QACL,WAAW;QACX,oBAAoB;QACpB,eAAe;QACf,aAAa,EAAE,WAAW,CAAC,MAAM;QACjC,UAAU,EAAE,eAAe,CAAC,MAAM;AAClC,QAAA,OAAO,EAAE,QAAQ,EAAE,CAAC,OAAO;KAC5B,CAAC;AACJ;;AChBA;;;AAGG;AACI,MAAM,qBAAqB,GAAG,MAAK;AACxC,IAAA,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,eAAe,EAAE,CAAC;AAC9E,IAAA,MAAM,gBAAgB,GAAG,mBAAmB,EAAE,CAAC;AAE/C,IAAA,MAAM,KAAK,GAAG,CAAC,MAAc,EAAE,KAAU,KAAK,MAAM,CAAC,EAAE,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC,CAAC;IAE1E,MAAM,SAAS,GAAG,CAAC,MAAc,EAAE,MAAiB,GAAA,CAAC,KAAI;AACvD,QAAA,MAAM,YAAY,GAAG,QAAQ,EAAE,CAAC;AAChC,QAAA,MAAM,kBAAkB,GAAG,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC/D,QAAA,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,kBAAkB,CAAC;AACpD,cAAE,kBAAkB,CAAC,CAAC,CAAC;cACrB,kBAAkB,CAAC;AACvB,QAAA,MAAM,QAAQ,GAAG,CAAC,OAAO,YAAY,KAAK,QAAQ,GAAG,YAAY,GAAG,CAAC,IAAI,MAAM,CAAC;QAChF,MAAM,CAAC,EAAE,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC,CAAC;AACjC,KAAC,CAAC;IAEF,MAAM,aAAa,GAAG,CAAC,OAA4B,KAAK,MAAM,CAAC,OAAO,CAAC,CAAC;IAExE,OAAO;QACL,KAAK;QACL,SAAS;QACT,aAAa;QACb,WAAW,EAAE,gBAAgB,CAAC,WAAW;QACzC,oBAAoB,EAAE,gBAAgB,CAAC,oBAAoB;QAC3D,eAAe,EAAE,gBAAgB,CAAC,eAAe;QACjD,aAAa,EAAE,gBAAgB,CAAC,aAAa;QAC7C,UAAU,EAAE,gBAAgB,CAAC,UAAU;QACvC,OAAO,EAAE,gBAAgB,CAAC,OAAO;QACjC,KAAK;QACL,QAAQ;QACR,UAAU;QACV,UAAU;AACV,QAAA,kBAAkB,EAAE,MAAM,gBAAgB,CAAC,eAAe;AAC1D;;AAEG;QACH,QAAQ,EAAE,gBAAgB,CAAC,WAAW;AACtC;;AAEG;QACH,GAAG,EAAE,gBAAgB,CAAC,eAAe;KACtC,CAAC;AACJ;;AC7CA;;;;;AAKG;AACI,MAAM,oBAAoB,GAAG,MAAwB;AAC1D,IAAA,MAAM,OAAO,GAAGA,gBAAU,CAAC,kBAAkB,CAAC,CAAC;IAE/C,IAAI,CAAC,OAAO,EAAE;QACZ,MAAM,IAAI,KAAK,CACb,sEAAsE;YACpE,6BAA6B;YAC7B,qDAAqD;YACrD,uBAAuB;AACvB,YAAA,wBAAwB,CAC3B,CAAC;KACH;IAED,OAAO,OAAO,CAAC,MAAM,CAAC;AACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}