@youversion/platform-react-hooks 1.21.0 → 1.22.1
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/.turbo/turbo-build.log +21 -1
- package/CHANGELOG.md +21 -0
- package/dist/YouVersionAuthProvider-VORD6KDZ.js +80 -0
- package/dist/chunk-ITHJF2FD.js +17 -0
- package/dist/index.cjs +946 -0
- package/dist/index.js +788 -26
- package/package.json +11 -6
- package/tsconfig.build.json +4 -1
- package/dist/__tests__/mocks/auth.js +0 -43
- package/dist/__tests__/mocks/auth.js.map +0 -1
- package/dist/__tests__/mocks/bibles.js +0 -23
- package/dist/__tests__/mocks/bibles.js.map +0 -1
- package/dist/__tests__/mocks/core-mock-factory.js +0 -138
- package/dist/__tests__/mocks/core-mock-factory.js.map +0 -1
- package/dist/__tests__/utils/test-utils.js +0 -11
- package/dist/__tests__/utils/test-utils.js.map +0 -1
- package/dist/context/ReaderContext.js +0 -17
- package/dist/context/ReaderContext.js.map +0 -1
- package/dist/context/ReaderProvider.js +0 -24
- package/dist/context/ReaderProvider.js.map +0 -1
- package/dist/context/VerseSelectionContext.js +0 -6
- package/dist/context/VerseSelectionContext.js.map +0 -1
- package/dist/context/VerseSelectionProvider.js +0 -36
- package/dist/context/VerseSelectionProvider.js.map +0 -1
- package/dist/context/YouVersionAuthContext.js +0 -13
- package/dist/context/YouVersionAuthContext.js.map +0 -1
- package/dist/context/YouVersionAuthProvider.js +0 -81
- package/dist/context/YouVersionAuthProvider.js.map +0 -1
- package/dist/context/YouVersionContext.js +0 -4
- package/dist/context/YouVersionContext.js.map +0 -1
- package/dist/context/YouVersionProvider.js +0 -63
- package/dist/context/YouVersionProvider.js.map +0 -1
- package/dist/context/index.js +0 -7
- package/dist/context/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/test/setup.js +0 -9
- package/dist/test/setup.js.map +0 -1
- package/dist/test/utils.js +0 -7
- package/dist/test/utils.js.map +0 -1
- package/dist/types/auth.js +0 -2
- package/dist/types/auth.js.map +0 -1
- package/dist/useApiData.js +0 -46
- package/dist/useApiData.js.map +0 -1
- package/dist/useBibleClient.js +0 -18
- package/dist/useBibleClient.js.map +0 -1
- package/dist/useBook.js +0 -11
- package/dist/useBook.js.map +0 -1
- package/dist/useBooks.js +0 -11
- package/dist/useBooks.js.map +0 -1
- package/dist/useChapter.js +0 -11
- package/dist/useChapter.js.map +0 -1
- package/dist/useChapterNavigation.js +0 -57
- package/dist/useChapterNavigation.js.map +0 -1
- package/dist/useChapters.js +0 -13
- package/dist/useChapters.js.map +0 -1
- package/dist/useFilteredVersions.js +0 -29
- package/dist/useFilteredVersions.js.map +0 -1
- package/dist/useHighlights.js +0 -41
- package/dist/useHighlights.js.map +0 -1
- package/dist/useInitData.js +0 -29
- package/dist/useInitData.js.map +0 -1
- package/dist/useLanguage.js +0 -17
- package/dist/useLanguage.js.map +0 -1
- package/dist/useLanguageClient.js +0 -18
- package/dist/useLanguageClient.js.map +0 -1
- package/dist/useLanguages.js +0 -23
- package/dist/useLanguages.js.map +0 -1
- package/dist/usePassage.js +0 -11
- package/dist/usePassage.js.map +0 -1
- package/dist/useTheme.js +0 -21
- package/dist/useTheme.js.map +0 -1
- package/dist/useVOTD.js +0 -9
- package/dist/useVOTD.js.map +0 -1
- package/dist/useVerse.js +0 -11
- package/dist/useVerse.js.map +0 -1
- package/dist/useVerseSelection.js +0 -13
- package/dist/useVerseSelection.js.map +0 -1
- package/dist/useVerses.js +0 -11
- package/dist/useVerses.js.map +0 -1
- package/dist/useVersion.js +0 -11
- package/dist/useVersion.js.map +0 -1
- package/dist/useVersions.js +0 -35
- package/dist/useVersions.js.map +0 -1
- package/dist/useYVAuth.js +0 -144
- package/dist/useYVAuth.js.map +0 -1
- package/dist/utility/extractTextFromHTML.js +0 -21
- package/dist/utility/extractTextFromHTML.js.map +0 -1
- package/dist/utility/extractVersesFromHTML.js +0 -26
- package/dist/utility/extractVersesFromHTML.js.map +0 -1
- package/dist/utility/getDayOfYear.js +0 -5
- package/dist/utility/getDayOfYear.js.map +0 -1
- package/dist/utility/index.js +0 -6
- package/dist/utility/index.js.map +0 -1
- package/dist/utility/useDebounce.js +0 -24
- package/dist/utility/useDebounce.js.map +0 -1
- package/dist/utility/version.js +0 -4
- package/dist/utility/version.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,26 +1,788 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
1
|
+
import {
|
|
2
|
+
useYouVersionAuthContext
|
|
3
|
+
} from "./chunk-ITHJF2FD.js";
|
|
4
|
+
|
|
5
|
+
// src/useBibleClient.ts
|
|
6
|
+
import { useContext as useContext2, useMemo } from "react";
|
|
7
|
+
|
|
8
|
+
// src/context/YouVersionContext.tsx
|
|
9
|
+
import { createContext } from "react";
|
|
10
|
+
var YouVersionContext = createContext(null);
|
|
11
|
+
|
|
12
|
+
// src/context/YouVersionProvider.tsx
|
|
13
|
+
import { lazy, Suspense, useEffect, useState } from "react";
|
|
14
|
+
import { YouVersionPlatformConfiguration } from "@youversion/platform-core";
|
|
15
|
+
import { jsx } from "react/jsx-runtime";
|
|
16
|
+
var AuthProvider = lazy(() => import("./YouVersionAuthProvider-VORD6KDZ.js"));
|
|
17
|
+
function useResolvedTheme(theme) {
|
|
18
|
+
const [resolved, setResolved] = useState(() => {
|
|
19
|
+
if (theme !== "system") return theme;
|
|
20
|
+
if (typeof window === "undefined") return "light";
|
|
21
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
22
|
+
});
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (theme !== "system") {
|
|
25
|
+
setResolved(theme);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (typeof window === "undefined") return;
|
|
29
|
+
const mediaQueryList = window.matchMedia("(prefers-color-scheme: dark)");
|
|
30
|
+
setResolved(mediaQueryList.matches ? "dark" : "light");
|
|
31
|
+
const handler = (e) => {
|
|
32
|
+
setResolved(e.matches ? "dark" : "light");
|
|
33
|
+
};
|
|
34
|
+
mediaQueryList.addEventListener("change", handler);
|
|
35
|
+
return () => mediaQueryList.removeEventListener("change", handler);
|
|
36
|
+
}, [theme]);
|
|
37
|
+
return resolved;
|
|
38
|
+
}
|
|
39
|
+
function YouVersionProvider(props) {
|
|
40
|
+
const { appKey, apiHost = "api.youversion.com", includeAuth, theme = "light", children } = props;
|
|
41
|
+
const resolvedTheme = useResolvedTheme(theme);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
YouVersionPlatformConfiguration.appKey = appKey;
|
|
44
|
+
YouVersionPlatformConfiguration.apiHost = apiHost;
|
|
45
|
+
}, [appKey, apiHost]);
|
|
46
|
+
if (includeAuth) {
|
|
47
|
+
const { authRedirectUrl } = props;
|
|
48
|
+
return /* @__PURE__ */ jsx(
|
|
49
|
+
YouVersionContext.Provider,
|
|
50
|
+
{
|
|
51
|
+
value: {
|
|
52
|
+
appKey,
|
|
53
|
+
apiHost,
|
|
54
|
+
installationId: YouVersionPlatformConfiguration.installationId,
|
|
55
|
+
theme: resolvedTheme,
|
|
56
|
+
authEnabled: !!includeAuth
|
|
57
|
+
},
|
|
58
|
+
children: /* @__PURE__ */ jsx(Suspense, { children: /* @__PURE__ */ jsx(AuthProvider, { config: { appKey, apiHost, redirectUri: authRedirectUrl }, children }) })
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
return /* @__PURE__ */ jsx(
|
|
63
|
+
YouVersionContext.Provider,
|
|
64
|
+
{
|
|
65
|
+
value: {
|
|
66
|
+
appKey,
|
|
67
|
+
apiHost,
|
|
68
|
+
installationId: YouVersionPlatformConfiguration.installationId,
|
|
69
|
+
theme: resolvedTheme,
|
|
70
|
+
authEnabled: !!includeAuth
|
|
71
|
+
},
|
|
72
|
+
children
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/context/ReaderContext.tsx
|
|
78
|
+
import { createContext as createContext2, useContext } from "react";
|
|
79
|
+
var ReaderContext = createContext2(null);
|
|
80
|
+
function useReaderContext() {
|
|
81
|
+
const context = useContext(ReaderContext);
|
|
82
|
+
if (!context) {
|
|
83
|
+
throw new Error("useReaderContext() must be used within a ReaderProvider");
|
|
84
|
+
}
|
|
85
|
+
return context;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/context/ReaderProvider.tsx
|
|
89
|
+
import { useState as useState2 } from "react";
|
|
90
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
91
|
+
function ReaderProvider(props) {
|
|
92
|
+
const [currentVersion, setCurrentVersion] = useState2(props.currentVersion);
|
|
93
|
+
const [currentBook, setCurrentBook] = useState2(props.currentBook);
|
|
94
|
+
const [currentChapter, setCurrentChapter] = useState2(props.currentChapter);
|
|
95
|
+
const [currentVerse, setCurrentVerse] = useState2(props.currentVerse);
|
|
96
|
+
return /* @__PURE__ */ jsx2(
|
|
97
|
+
ReaderContext.Provider,
|
|
98
|
+
{
|
|
99
|
+
value: {
|
|
100
|
+
currentVersion,
|
|
101
|
+
currentBook,
|
|
102
|
+
currentChapter,
|
|
103
|
+
currentVerse,
|
|
104
|
+
setVersion: setCurrentVersion,
|
|
105
|
+
setChapter: setCurrentChapter,
|
|
106
|
+
setBook: setCurrentBook,
|
|
107
|
+
setVerse: setCurrentVerse
|
|
108
|
+
},
|
|
109
|
+
children: props.children
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/context/VerseSelectionProvider.tsx
|
|
115
|
+
import { useCallback, useState as useState3 } from "react";
|
|
116
|
+
|
|
117
|
+
// src/context/VerseSelectionContext.tsx
|
|
118
|
+
import { createContext as createContext3 } from "react";
|
|
119
|
+
var VerseSelectionContext = createContext3(null);
|
|
120
|
+
|
|
121
|
+
// src/context/VerseSelectionProvider.tsx
|
|
122
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
123
|
+
function VerseSelectionProvider({ children }) {
|
|
124
|
+
const [selectedVerseUsfms, setSelectedVerseUsfms] = useState3(/* @__PURE__ */ new Set());
|
|
125
|
+
const toggleVerse = useCallback((usfm) => {
|
|
126
|
+
setSelectedVerseUsfms((prev) => {
|
|
127
|
+
const newSet = new Set(prev);
|
|
128
|
+
if (newSet.has(usfm)) {
|
|
129
|
+
newSet.delete(usfm);
|
|
130
|
+
} else {
|
|
131
|
+
newSet.add(usfm);
|
|
132
|
+
}
|
|
133
|
+
return newSet;
|
|
134
|
+
});
|
|
135
|
+
}, []);
|
|
136
|
+
const isSelected = useCallback(
|
|
137
|
+
(usfm) => {
|
|
138
|
+
return selectedVerseUsfms.has(usfm);
|
|
139
|
+
},
|
|
140
|
+
[selectedVerseUsfms]
|
|
141
|
+
);
|
|
142
|
+
const clearSelection = useCallback(() => {
|
|
143
|
+
setSelectedVerseUsfms(/* @__PURE__ */ new Set());
|
|
144
|
+
}, []);
|
|
145
|
+
const value = {
|
|
146
|
+
selectedVerseUsfms,
|
|
147
|
+
toggleVerse,
|
|
148
|
+
isSelected,
|
|
149
|
+
clearSelection,
|
|
150
|
+
selectedCount: selectedVerseUsfms.size
|
|
151
|
+
};
|
|
152
|
+
return /* @__PURE__ */ jsx3(VerseSelectionContext.Provider, { value, children });
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// src/useBibleClient.ts
|
|
156
|
+
import { BibleClient, ApiClient } from "@youversion/platform-core";
|
|
157
|
+
function useBibleClient() {
|
|
158
|
+
const context = useContext2(YouVersionContext);
|
|
159
|
+
return useMemo(() => {
|
|
160
|
+
if (!context?.appKey) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
"YouVersion context not found. Make sure your component is wrapped with YouVersionProvider and an API key is provided."
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
return new BibleClient(
|
|
166
|
+
new ApiClient({
|
|
167
|
+
appKey: context.appKey,
|
|
168
|
+
apiHost: context.apiHost,
|
|
169
|
+
installationId: context.installationId
|
|
170
|
+
})
|
|
171
|
+
);
|
|
172
|
+
}, [context?.apiHost, context?.appKey, context?.installationId]);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/useApiData.ts
|
|
176
|
+
import { useState as useState4, useEffect as useEffect2, useCallback as useCallback2 } from "react";
|
|
177
|
+
function useApiData(fetchFn, deps, options = {}) {
|
|
178
|
+
const { enabled = true } = options;
|
|
179
|
+
const [data, setData] = useState4(null);
|
|
180
|
+
const [loading, setLoading] = useState4(true);
|
|
181
|
+
const [error, setError] = useState4(null);
|
|
182
|
+
const fetchData = useCallback2(() => {
|
|
183
|
+
if (!enabled) {
|
|
184
|
+
setLoading(false);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
let canceled = false;
|
|
188
|
+
setLoading(true);
|
|
189
|
+
setError(null);
|
|
190
|
+
fetchFn().then((result) => {
|
|
191
|
+
if (!canceled) {
|
|
192
|
+
setData(result);
|
|
193
|
+
}
|
|
194
|
+
}).catch((err) => {
|
|
195
|
+
if (!canceled) {
|
|
196
|
+
setError(err);
|
|
197
|
+
}
|
|
198
|
+
}).finally(() => {
|
|
199
|
+
if (!canceled) {
|
|
200
|
+
setLoading(false);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
return () => {
|
|
204
|
+
canceled = true;
|
|
205
|
+
};
|
|
206
|
+
}, [fetchFn, enabled]);
|
|
207
|
+
const refetch = useCallback2(() => {
|
|
208
|
+
fetchData();
|
|
209
|
+
}, [fetchData]);
|
|
210
|
+
useEffect2(() => {
|
|
211
|
+
const cleanup = fetchData();
|
|
212
|
+
return cleanup;
|
|
213
|
+
}, deps);
|
|
214
|
+
return { data, loading, error, refetch };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// src/useBook.ts
|
|
218
|
+
function useBook(versionId, book, options) {
|
|
219
|
+
const bibleClient = useBibleClient();
|
|
220
|
+
const { data, loading, error, refetch } = useApiData(
|
|
221
|
+
() => bibleClient.getBook(versionId, book),
|
|
222
|
+
[bibleClient, versionId, book],
|
|
223
|
+
{
|
|
224
|
+
enabled: options?.enabled !== false
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
return { book: data, loading, error, refetch };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// src/useBooks.ts
|
|
231
|
+
function useBooks(versionId, options) {
|
|
232
|
+
const bibleClient = useBibleClient();
|
|
233
|
+
const {
|
|
234
|
+
data: books,
|
|
235
|
+
loading,
|
|
236
|
+
error,
|
|
237
|
+
refetch
|
|
238
|
+
} = useApiData(
|
|
239
|
+
() => bibleClient.getBooks(versionId),
|
|
240
|
+
[bibleClient, versionId],
|
|
241
|
+
{
|
|
242
|
+
enabled: options?.enabled !== false
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
return { books, loading, error, refetch };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// src/useChapter.ts
|
|
249
|
+
function useChapter(versionId, book, chapter, options) {
|
|
250
|
+
const bibleClient = useBibleClient();
|
|
251
|
+
const {
|
|
252
|
+
data: chapterData,
|
|
253
|
+
loading,
|
|
254
|
+
error,
|
|
255
|
+
refetch
|
|
256
|
+
} = useApiData(
|
|
257
|
+
() => bibleClient.getChapter(versionId, book, chapter),
|
|
258
|
+
[bibleClient, versionId, book, chapter],
|
|
259
|
+
{
|
|
260
|
+
enabled: options?.enabled !== false
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
return { chapter: chapterData, loading, error, refetch };
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// src/useChapters.ts
|
|
267
|
+
function useChapters(versionId, book, options) {
|
|
268
|
+
const bibleClient = useBibleClient();
|
|
269
|
+
const isValidBook = Boolean(book) && book !== "undefined" && book !== "null";
|
|
270
|
+
const {
|
|
271
|
+
data: chapters,
|
|
272
|
+
loading,
|
|
273
|
+
error,
|
|
274
|
+
refetch
|
|
275
|
+
} = useApiData(
|
|
276
|
+
() => bibleClient.getChapters(versionId, book),
|
|
277
|
+
[bibleClient, versionId, book],
|
|
278
|
+
{
|
|
279
|
+
enabled: options?.enabled !== false && isValidBook
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
return { chapters, loading, error, refetch };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// src/useVerse.ts
|
|
286
|
+
function useVerse(versionId, book, chapter, verse, options) {
|
|
287
|
+
const bibleClient = useBibleClient();
|
|
288
|
+
const {
|
|
289
|
+
data: verseData,
|
|
290
|
+
loading,
|
|
291
|
+
error,
|
|
292
|
+
refetch
|
|
293
|
+
} = useApiData(
|
|
294
|
+
() => bibleClient.getVerse(versionId, book, chapter, verse),
|
|
295
|
+
[bibleClient, versionId, book, chapter, verse],
|
|
296
|
+
{
|
|
297
|
+
enabled: options?.enabled !== false
|
|
298
|
+
}
|
|
299
|
+
);
|
|
300
|
+
return { verse: verseData, loading, error, refetch };
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// src/useVerses.ts
|
|
304
|
+
function useVerses(versionId, book, chapter, options) {
|
|
305
|
+
const bibleClient = useBibleClient();
|
|
306
|
+
const {
|
|
307
|
+
data: verses,
|
|
308
|
+
loading,
|
|
309
|
+
error,
|
|
310
|
+
refetch
|
|
311
|
+
} = useApiData(
|
|
312
|
+
() => bibleClient.getVerses(versionId, book, chapter),
|
|
313
|
+
[bibleClient, versionId, book, chapter],
|
|
314
|
+
{
|
|
315
|
+
enabled: options?.enabled !== false
|
|
316
|
+
}
|
|
317
|
+
);
|
|
318
|
+
return { verses, loading, error, refetch };
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// src/useVersion.ts
|
|
322
|
+
function useVersion(versionId, options) {
|
|
323
|
+
const bibleClient = useBibleClient();
|
|
324
|
+
const {
|
|
325
|
+
data: version,
|
|
326
|
+
loading,
|
|
327
|
+
error,
|
|
328
|
+
refetch
|
|
329
|
+
} = useApiData(() => bibleClient.getVersion(versionId), [bibleClient, versionId], {
|
|
330
|
+
enabled: options?.enabled !== false
|
|
331
|
+
});
|
|
332
|
+
return { version, loading, error, refetch };
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/utility/useDebounce.ts
|
|
336
|
+
import { useEffect as useEffect3, useState as useState5 } from "react";
|
|
337
|
+
function useDebounce(value, delay) {
|
|
338
|
+
const [debouncedValue, setDebouncedValue] = useState5(value);
|
|
339
|
+
useEffect3(() => {
|
|
340
|
+
const handler = setTimeout(() => {
|
|
341
|
+
setDebouncedValue(value);
|
|
342
|
+
}, delay);
|
|
343
|
+
return () => clearTimeout(handler);
|
|
344
|
+
}, [value, delay]);
|
|
345
|
+
return debouncedValue;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// src/useVersions.ts
|
|
349
|
+
function useVersions(languageRanges = "en", licenseId, options) {
|
|
350
|
+
const bibleClient = useBibleClient();
|
|
351
|
+
const getVersionsOptions = options?.page_size !== void 0 || options?.page_token !== void 0 || options?.fields !== void 0 || options?.all_available !== void 0 ? {
|
|
352
|
+
page_size: options?.page_size,
|
|
353
|
+
page_token: options?.page_token,
|
|
354
|
+
fields: options?.fields,
|
|
355
|
+
all_available: options?.all_available
|
|
356
|
+
} : void 0;
|
|
357
|
+
const languageRangesKey = Array.isArray(languageRanges) ? languageRanges.join(",") : languageRanges;
|
|
358
|
+
const fieldsKey = options?.fields?.join(",");
|
|
359
|
+
const {
|
|
360
|
+
data: versions,
|
|
361
|
+
loading,
|
|
362
|
+
error,
|
|
363
|
+
refetch
|
|
364
|
+
} = useApiData(
|
|
365
|
+
() => bibleClient.getVersions(languageRanges, licenseId, getVersionsOptions),
|
|
366
|
+
[
|
|
367
|
+
bibleClient,
|
|
368
|
+
languageRangesKey,
|
|
369
|
+
licenseId,
|
|
370
|
+
options?.page_size,
|
|
371
|
+
options?.page_token,
|
|
372
|
+
fieldsKey,
|
|
373
|
+
options?.all_available
|
|
374
|
+
],
|
|
375
|
+
{
|
|
376
|
+
enabled: options?.enabled !== false
|
|
377
|
+
}
|
|
378
|
+
);
|
|
379
|
+
return { versions, loading, error, refetch };
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// src/useFilteredVersions.ts
|
|
383
|
+
import { useMemo as useMemo2 } from "react";
|
|
384
|
+
|
|
385
|
+
// src/utility/version.ts
|
|
386
|
+
function getISOFromVersion(version) {
|
|
387
|
+
return version?.language_tag || "unknown";
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// src/useFilteredVersions.ts
|
|
391
|
+
function useFilteredVersions(versions, searchTerm, selectedLanguage, recentVersions) {
|
|
392
|
+
return useMemo2(() => {
|
|
393
|
+
let result = [...versions];
|
|
394
|
+
if (selectedLanguage && selectedLanguage !== "*") {
|
|
395
|
+
result = result.filter(
|
|
396
|
+
(version) => getISOFromVersion(version).toLowerCase() === selectedLanguage.toLowerCase()
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
if (searchTerm.trim()) {
|
|
400
|
+
const searchLower = searchTerm.toLowerCase();
|
|
401
|
+
result = result.filter(
|
|
402
|
+
(version) => version.title.toLowerCase().includes(searchLower) || version.abbreviation.toLowerCase().includes(searchLower) || getISOFromVersion(version).toLowerCase().includes(searchLower)
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
if (recentVersions) {
|
|
406
|
+
const recentVersionIds = recentVersions.map((version) => version.id);
|
|
407
|
+
result = result.filter((version) => !recentVersionIds.includes(version.id));
|
|
408
|
+
}
|
|
409
|
+
return result;
|
|
410
|
+
}, [versions, recentVersions, searchTerm, selectedLanguage]);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// src/utility/extractTextFromHTML.ts
|
|
414
|
+
function extractTextFromHtml(html) {
|
|
415
|
+
if (!html) return "";
|
|
416
|
+
const container = document.createElement("div");
|
|
417
|
+
container.innerHTML = html;
|
|
418
|
+
const contentText = Array.from(container.querySelectorAll("span.content")).map((el) => (el.textContent || "").trim()).filter(Boolean).join(" ");
|
|
419
|
+
return contentText.replace(/\s+/g, " ").trim();
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// src/utility/extractVersesFromHTML.ts
|
|
423
|
+
function extractVersesFromHTML(html) {
|
|
424
|
+
if (!html) return [];
|
|
425
|
+
const results = [];
|
|
426
|
+
const pattern = /<span class="yv-v" v="(\d+)"><\/span><span class="yv-vlbl">\d+<\/span>/g;
|
|
427
|
+
let execResult;
|
|
428
|
+
const indices = [];
|
|
429
|
+
while ((execResult = pattern.exec(html)) !== null) {
|
|
430
|
+
const verseNumString = execResult[1];
|
|
431
|
+
indices.push({ verse: parseInt(verseNumString, 10), index: execResult.index });
|
|
432
|
+
}
|
|
433
|
+
for (let i = 0; i < indices.length; i++) {
|
|
434
|
+
const current = indices[i];
|
|
435
|
+
const next = indices[i + 1];
|
|
436
|
+
const start = current.index;
|
|
437
|
+
const end = next ? next.index : html.length;
|
|
438
|
+
const slice = html.slice(start, end).trim();
|
|
439
|
+
results.push({ verse: current.verse, html: slice });
|
|
440
|
+
}
|
|
441
|
+
return results;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// src/utility/getDayOfYear.ts
|
|
445
|
+
function getDayOfYear(date) {
|
|
446
|
+
const dayOfYear = Math.floor(
|
|
447
|
+
(date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 864e5
|
|
448
|
+
);
|
|
449
|
+
return dayOfYear;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// src/useVerseSelection.ts
|
|
453
|
+
import { useContext as useContext3 } from "react";
|
|
454
|
+
function useVerseSelection() {
|
|
455
|
+
const context = useContext3(VerseSelectionContext);
|
|
456
|
+
if (!context) {
|
|
457
|
+
throw new Error("useVerseSelection must be used within a VerseSelectionProvider");
|
|
458
|
+
}
|
|
459
|
+
return context;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// src/useChapterNavigation.ts
|
|
463
|
+
import { getAdjacentChapter } from "@youversion/platform-core";
|
|
464
|
+
function useChapterNavigation() {
|
|
465
|
+
const { currentChapter, currentVersion, currentBook, setChapter, setBook } = useReaderContext();
|
|
466
|
+
const { books, loading: booksLoading } = useBooks(currentVersion?.id ?? 0, {
|
|
467
|
+
enabled: Boolean(currentVersion?.id)
|
|
468
|
+
});
|
|
469
|
+
const booksData = books?.data ?? [];
|
|
470
|
+
const bookId = currentBook?.id ?? "";
|
|
471
|
+
const chapterId = currentChapter?.id ?? "";
|
|
472
|
+
const nextResult = getAdjacentChapter(booksData, bookId, chapterId, "next");
|
|
473
|
+
const prevResult = getAdjacentChapter(booksData, bookId, chapterId, "previous");
|
|
474
|
+
const canNavigateNext = !booksLoading && nextResult !== null;
|
|
475
|
+
const canNavigatePrevious = !booksLoading && prevResult !== null;
|
|
476
|
+
const currentChapterIndex = currentBook?.chapters?.findIndex((c) => c.id === currentChapter?.id) ?? -1;
|
|
477
|
+
const navigate = (result) => {
|
|
478
|
+
if (!result || !booksData.length) return;
|
|
479
|
+
const targetBook = booksData.find((b) => b.id === result.bookId);
|
|
480
|
+
if (!targetBook) return;
|
|
481
|
+
const targetChapter = targetBook.chapters?.find((c) => c.id === result.chapterId) ?? (targetBook.intro?.id === result.chapterId ? {
|
|
482
|
+
id: targetBook.intro.id,
|
|
483
|
+
passage_id: targetBook.intro.passage_id,
|
|
484
|
+
title: targetBook.intro.title
|
|
485
|
+
} : void 0);
|
|
486
|
+
if (!targetChapter) return;
|
|
487
|
+
if (targetBook.id !== currentBook?.id) {
|
|
488
|
+
setBook(targetBook);
|
|
489
|
+
}
|
|
490
|
+
setChapter(targetChapter);
|
|
491
|
+
};
|
|
492
|
+
const navigateToNext = () => navigate(nextResult);
|
|
493
|
+
const navigateToPrevious = () => navigate(prevResult);
|
|
494
|
+
return {
|
|
495
|
+
canNavigatePrevious,
|
|
496
|
+
canNavigateNext,
|
|
497
|
+
navigateToPrevious,
|
|
498
|
+
navigateToNext,
|
|
499
|
+
currentChapterIndex,
|
|
500
|
+
isLoading: booksLoading
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// src/useInitData.ts
|
|
505
|
+
import { DEFAULT_LICENSE_FREE_BIBLE_VERSION } from "@youversion/platform-core";
|
|
506
|
+
var DEFAULT = {
|
|
507
|
+
VERSION: DEFAULT_LICENSE_FREE_BIBLE_VERSION,
|
|
508
|
+
BOOK: "GEN",
|
|
509
|
+
CHAPTER: 1
|
|
510
|
+
};
|
|
511
|
+
function useInitData({ version, book, chapter } = {
|
|
512
|
+
version: DEFAULT.VERSION,
|
|
513
|
+
book: DEFAULT.BOOK,
|
|
514
|
+
chapter: DEFAULT.CHAPTER
|
|
515
|
+
}) {
|
|
516
|
+
const {
|
|
517
|
+
version: versionData,
|
|
518
|
+
loading: versionLoading,
|
|
519
|
+
error: versionError
|
|
520
|
+
} = useVersion(version);
|
|
521
|
+
const { book: bookData, loading: bookLoading, error: bookError } = useBook(version, book);
|
|
522
|
+
const {
|
|
523
|
+
chapter: chapterData,
|
|
524
|
+
loading: chapterLoading,
|
|
525
|
+
error: chapterError
|
|
526
|
+
} = useChapter(version, book, chapter);
|
|
527
|
+
const allDataAvailable = versionData && bookData && chapterData;
|
|
528
|
+
return {
|
|
529
|
+
loading: versionLoading || bookLoading || chapterLoading,
|
|
530
|
+
error: [versionError, bookError, chapterError].filter(Boolean).join(" "),
|
|
531
|
+
data: allDataAvailable ? { version: versionData, book: bookData, chapter: chapterData } : null
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// src/usePassage.ts
|
|
536
|
+
function usePassage({
|
|
537
|
+
versionId,
|
|
538
|
+
usfm,
|
|
539
|
+
format = "html",
|
|
540
|
+
include_headings = false,
|
|
541
|
+
include_notes = false,
|
|
542
|
+
options
|
|
543
|
+
}) {
|
|
544
|
+
const bibleClient = useBibleClient();
|
|
545
|
+
const isValidUsfm = Boolean(usfm) && usfm !== "undefined" && usfm !== "null";
|
|
546
|
+
const { data, loading, error, refetch } = useApiData(
|
|
547
|
+
() => bibleClient.getPassage(versionId, usfm, format, include_headings, include_notes),
|
|
548
|
+
[bibleClient, versionId, usfm, format, include_headings, include_notes],
|
|
549
|
+
{ enabled: options?.enabled !== false && isValidUsfm }
|
|
550
|
+
);
|
|
551
|
+
return { passage: data, loading, error, refetch };
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// src/useVOTD.ts
|
|
555
|
+
function useVerseOfTheDay(day, options) {
|
|
556
|
+
const bibleClient = useBibleClient();
|
|
557
|
+
const { data, loading, error, refetch } = useApiData(
|
|
558
|
+
() => bibleClient.getVOTD(day),
|
|
559
|
+
[bibleClient, day],
|
|
560
|
+
{ enabled: options?.enabled !== false }
|
|
561
|
+
);
|
|
562
|
+
return { data, loading, error, refetch };
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// src/useHighlights.ts
|
|
566
|
+
import { useMemo as useMemo3, useCallback as useCallback3 } from "react";
|
|
567
|
+
import { useContext as useContext4 } from "react";
|
|
568
|
+
import { HighlightsClient, ApiClient as ApiClient2 } from "@youversion/platform-core";
|
|
569
|
+
import "@youversion/platform-core";
|
|
570
|
+
function useHighlights(options, apiOptions) {
|
|
571
|
+
const context = useContext4(YouVersionContext);
|
|
572
|
+
const highlightsClient = useMemo3(() => {
|
|
573
|
+
if (!context?.appKey) {
|
|
574
|
+
throw new Error(
|
|
575
|
+
"YouVersion context not found. Make sure your component is wrapped with YouVersionProvider and an API key is provided."
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
return new HighlightsClient(
|
|
579
|
+
new ApiClient2({
|
|
580
|
+
appKey: context.appKey,
|
|
581
|
+
apiHost: context.apiHost,
|
|
582
|
+
installationId: context.installationId
|
|
583
|
+
})
|
|
584
|
+
);
|
|
585
|
+
}, [context?.apiHost, context?.appKey, context?.installationId]);
|
|
586
|
+
const { data, loading, error, refetch } = useApiData(
|
|
587
|
+
() => highlightsClient.getHighlights(options),
|
|
588
|
+
[highlightsClient, options?.version_id, options?.passage_id],
|
|
589
|
+
{
|
|
590
|
+
enabled: apiOptions?.enabled !== false
|
|
591
|
+
}
|
|
592
|
+
);
|
|
593
|
+
const createHighlight = useCallback3(
|
|
594
|
+
async (data2) => {
|
|
595
|
+
const result = await highlightsClient.createHighlight(data2);
|
|
596
|
+
refetch();
|
|
597
|
+
return result;
|
|
598
|
+
},
|
|
599
|
+
[highlightsClient, refetch]
|
|
600
|
+
);
|
|
601
|
+
const deleteHighlight = useCallback3(
|
|
602
|
+
async (passageId, deleteOptions) => {
|
|
603
|
+
await highlightsClient.deleteHighlight(passageId, deleteOptions);
|
|
604
|
+
refetch();
|
|
605
|
+
},
|
|
606
|
+
[highlightsClient, refetch]
|
|
607
|
+
);
|
|
608
|
+
return {
|
|
609
|
+
highlights: data,
|
|
610
|
+
loading,
|
|
611
|
+
error,
|
|
612
|
+
refetch,
|
|
613
|
+
createHighlight,
|
|
614
|
+
deleteHighlight
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// src/useLanguages.ts
|
|
619
|
+
import "@youversion/platform-core";
|
|
620
|
+
|
|
621
|
+
// src/useLanguageClient.ts
|
|
622
|
+
import { useContext as useContext5, useMemo as useMemo4 } from "react";
|
|
623
|
+
import { ApiClient as ApiClient3, LanguagesClient } from "@youversion/platform-core";
|
|
624
|
+
function useLanguagesClient() {
|
|
625
|
+
const context = useContext5(YouVersionContext);
|
|
626
|
+
return useMemo4(() => {
|
|
627
|
+
if (!context?.appKey) {
|
|
628
|
+
throw new Error(
|
|
629
|
+
"YouVersion context not found. Make sure your component is wrapped with YouVersionProvider and an API key is provided."
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
return new LanguagesClient(
|
|
633
|
+
new ApiClient3({
|
|
634
|
+
appKey: context.appKey,
|
|
635
|
+
apiHost: context.apiHost,
|
|
636
|
+
installationId: context.installationId
|
|
637
|
+
})
|
|
638
|
+
);
|
|
639
|
+
}, [context?.apiHost, context?.appKey, context?.installationId]);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// src/useLanguages.ts
|
|
643
|
+
function useLanguages(options = {}, apiOptions) {
|
|
644
|
+
const languagesClient = useLanguagesClient();
|
|
645
|
+
const { data, loading, error, refetch } = useApiData(
|
|
646
|
+
() => languagesClient.getLanguages(options),
|
|
647
|
+
[
|
|
648
|
+
languagesClient,
|
|
649
|
+
JSON.stringify(options.fields),
|
|
650
|
+
options?.country,
|
|
651
|
+
options?.page_size,
|
|
652
|
+
options?.page_token
|
|
653
|
+
],
|
|
654
|
+
{
|
|
655
|
+
enabled: apiOptions?.enabled !== false
|
|
656
|
+
}
|
|
657
|
+
);
|
|
658
|
+
return {
|
|
659
|
+
languages: data,
|
|
660
|
+
loading,
|
|
661
|
+
error,
|
|
662
|
+
refetch
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// src/useLanguage.ts
|
|
667
|
+
import "@youversion/platform-core";
|
|
668
|
+
function useLanguage(languageId, apiOptions) {
|
|
669
|
+
const languagesClient = useLanguagesClient();
|
|
670
|
+
const { data, loading, error, refetch } = useApiData(
|
|
671
|
+
() => languagesClient.getLanguage(languageId),
|
|
672
|
+
[languagesClient, languageId],
|
|
673
|
+
{
|
|
674
|
+
enabled: apiOptions?.enabled !== false
|
|
675
|
+
}
|
|
676
|
+
);
|
|
677
|
+
return {
|
|
678
|
+
language: data,
|
|
679
|
+
loading,
|
|
680
|
+
error,
|
|
681
|
+
refetch
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// src/useTheme.ts
|
|
686
|
+
import { useContext as useContext6 } from "react";
|
|
687
|
+
function useTheme() {
|
|
688
|
+
const context = useContext6(YouVersionContext);
|
|
689
|
+
return context?.theme || "light";
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// src/useYVAuth.ts
|
|
693
|
+
import { useMemo as useMemo5, useCallback as useCallback4 } from "react";
|
|
694
|
+
import {
|
|
695
|
+
YouVersionAPIUsers,
|
|
696
|
+
YouVersionPlatformConfiguration as YouVersionPlatformConfiguration2
|
|
697
|
+
} from "@youversion/platform-core";
|
|
698
|
+
function useYVAuth() {
|
|
699
|
+
const { userInfo, setUserInfo, isLoading, error, redirectUri } = useYouVersionAuthContext();
|
|
700
|
+
const isAuthenticated = !!userInfo;
|
|
701
|
+
const authTokens = useMemo5(() => {
|
|
702
|
+
if (typeof window !== "undefined") {
|
|
703
|
+
return {
|
|
704
|
+
accessToken: YouVersionPlatformConfiguration2.accessToken,
|
|
705
|
+
idToken: YouVersionPlatformConfiguration2.idToken
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
return { accessToken: null, idToken: null };
|
|
709
|
+
}, []);
|
|
710
|
+
const signIn = useCallback4(
|
|
711
|
+
async (params) => {
|
|
712
|
+
const url = params?.redirectUrl ?? redirectUri;
|
|
713
|
+
if (!url) {
|
|
714
|
+
throw new Error(
|
|
715
|
+
"redirectUrl is required. Provide it via signIn params or configure redirectUri in the auth provider."
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
if (params?.scopes) {
|
|
719
|
+
await YouVersionAPIUsers.signIn(url, params.scopes);
|
|
720
|
+
} else {
|
|
721
|
+
await YouVersionAPIUsers.signIn(url);
|
|
722
|
+
}
|
|
723
|
+
},
|
|
724
|
+
[redirectUri]
|
|
725
|
+
);
|
|
726
|
+
const processCallback = useCallback4(async () => {
|
|
727
|
+
const result = await YouVersionAPIUsers.handleAuthCallback();
|
|
728
|
+
return result;
|
|
729
|
+
}, []);
|
|
730
|
+
const auth = useMemo5(
|
|
731
|
+
() => ({
|
|
732
|
+
isAuthenticated,
|
|
733
|
+
isLoading,
|
|
734
|
+
accessToken: authTokens.accessToken,
|
|
735
|
+
idToken: authTokens.idToken,
|
|
736
|
+
result: null,
|
|
737
|
+
error
|
|
738
|
+
}),
|
|
739
|
+
[isAuthenticated, isLoading, authTokens.accessToken, authTokens.idToken, error]
|
|
740
|
+
);
|
|
741
|
+
const signOut = useCallback4(() => {
|
|
742
|
+
YouVersionPlatformConfiguration2.clearAuthTokens();
|
|
743
|
+
setUserInfo(null);
|
|
744
|
+
}, []);
|
|
745
|
+
return {
|
|
746
|
+
auth,
|
|
747
|
+
signIn,
|
|
748
|
+
signOut,
|
|
749
|
+
processCallback,
|
|
750
|
+
userInfo,
|
|
751
|
+
redirectUri
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
export {
|
|
755
|
+
DEFAULT,
|
|
756
|
+
ReaderContext,
|
|
757
|
+
ReaderProvider,
|
|
758
|
+
VerseSelectionContext,
|
|
759
|
+
VerseSelectionProvider,
|
|
760
|
+
YouVersionContext,
|
|
761
|
+
YouVersionProvider,
|
|
762
|
+
extractTextFromHtml,
|
|
763
|
+
extractVersesFromHTML,
|
|
764
|
+
getDayOfYear,
|
|
765
|
+
getISOFromVersion,
|
|
766
|
+
useBibleClient,
|
|
767
|
+
useBook,
|
|
768
|
+
useBooks,
|
|
769
|
+
useChapter,
|
|
770
|
+
useChapterNavigation,
|
|
771
|
+
useChapters,
|
|
772
|
+
useDebounce,
|
|
773
|
+
useFilteredVersions,
|
|
774
|
+
useHighlights,
|
|
775
|
+
useInitData,
|
|
776
|
+
useLanguage,
|
|
777
|
+
useLanguages,
|
|
778
|
+
usePassage,
|
|
779
|
+
useReaderContext,
|
|
780
|
+
useTheme,
|
|
781
|
+
useVerse,
|
|
782
|
+
useVerseOfTheDay,
|
|
783
|
+
useVerseSelection,
|
|
784
|
+
useVerses,
|
|
785
|
+
useVersion,
|
|
786
|
+
useVersions,
|
|
787
|
+
useYVAuth
|
|
788
|
+
};
|