@youversion/platform-react-hooks 0.4.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.
Files changed (181) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/CHANGELOG.md +9 -0
  3. package/LICENSE +201 -0
  4. package/dist/context/BibleSDKContext.d.ts +6 -0
  5. package/dist/context/BibleSDKContext.d.ts.map +1 -0
  6. package/dist/context/BibleSDKContext.js +4 -0
  7. package/dist/context/BibleSDKContext.js.map +1 -0
  8. package/dist/context/BibleSDKProvider.d.ts +8 -0
  9. package/dist/context/BibleSDKProvider.d.ts.map +1 -0
  10. package/dist/context/BibleSDKProvider.js +7 -0
  11. package/dist/context/BibleSDKProvider.js.map +1 -0
  12. package/dist/context/ReaderContext.d.ts +15 -0
  13. package/dist/context/ReaderContext.d.ts.map +1 -0
  14. package/dist/context/ReaderContext.js +11 -0
  15. package/dist/context/ReaderContext.js.map +1 -0
  16. package/dist/context/ReaderProvider.d.ts +11 -0
  17. package/dist/context/ReaderProvider.d.ts.map +1 -0
  18. package/dist/context/ReaderProvider.js +21 -0
  19. package/dist/context/ReaderProvider.js.map +1 -0
  20. package/dist/context/VerseSelectionContext.d.ts +9 -0
  21. package/dist/context/VerseSelectionContext.d.ts.map +1 -0
  22. package/dist/context/VerseSelectionContext.js +3 -0
  23. package/dist/context/VerseSelectionContext.js.map +1 -0
  24. package/dist/context/VerseSelectionProvider.d.ts +3 -0
  25. package/dist/context/VerseSelectionProvider.d.ts.map +1 -0
  26. package/dist/context/VerseSelectionProvider.js +33 -0
  27. package/dist/context/VerseSelectionProvider.js.map +1 -0
  28. package/dist/context/index.d.ts +7 -0
  29. package/dist/context/index.d.ts.map +1 -0
  30. package/dist/context/index.js +7 -0
  31. package/dist/context/index.js.map +1 -0
  32. package/dist/index.d.ts +21 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +21 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/test/setup.d.ts +2 -0
  37. package/dist/test/setup.d.ts.map +1 -0
  38. package/dist/test/setup.js +9 -0
  39. package/dist/test/setup.js.map +1 -0
  40. package/dist/useApiData.d.ts +12 -0
  41. package/dist/useApiData.d.ts.map +1 -0
  42. package/dist/useApiData.js +46 -0
  43. package/dist/useApiData.js.map +1 -0
  44. package/dist/useBibleClient.d.ts +3 -0
  45. package/dist/useBibleClient.d.ts.map +1 -0
  46. package/dist/useBibleClient.js +17 -0
  47. package/dist/useBibleClient.js.map +1 -0
  48. package/dist/useBook.d.ts +9 -0
  49. package/dist/useBook.d.ts.map +1 -0
  50. package/dist/useBook.js +11 -0
  51. package/dist/useBook.js.map +1 -0
  52. package/dist/useBooks.d.ts +9 -0
  53. package/dist/useBooks.d.ts.map +1 -0
  54. package/dist/useBooks.js +11 -0
  55. package/dist/useBooks.js.map +1 -0
  56. package/dist/useChapter.d.ts +9 -0
  57. package/dist/useChapter.d.ts.map +1 -0
  58. package/dist/useChapter.js +11 -0
  59. package/dist/useChapter.js.map +1 -0
  60. package/dist/useChapterNavigation.d.ts +23 -0
  61. package/dist/useChapterNavigation.d.ts.map +1 -0
  62. package/dist/useChapterNavigation.js +52 -0
  63. package/dist/useChapterNavigation.js.map +1 -0
  64. package/dist/useChapters.d.ts +9 -0
  65. package/dist/useChapters.d.ts.map +1 -0
  66. package/dist/useChapters.js +13 -0
  67. package/dist/useChapters.js.map +1 -0
  68. package/dist/useFilteredVersions.d.ts +6 -0
  69. package/dist/useFilteredVersions.d.ts.map +1 -0
  70. package/dist/useFilteredVersions.js +24 -0
  71. package/dist/useFilteredVersions.js.map +1 -0
  72. package/dist/useHighlights.d.ts +11 -0
  73. package/dist/useHighlights.d.ts.map +1 -0
  74. package/dist/useHighlights.js +40 -0
  75. package/dist/useHighlights.js.map +1 -0
  76. package/dist/useInitData.d.ts +23 -0
  77. package/dist/useInitData.d.ts.map +1 -0
  78. package/dist/useInitData.js +24 -0
  79. package/dist/useInitData.js.map +1 -0
  80. package/dist/useLanguages.d.ts +9 -0
  81. package/dist/useLanguages.d.ts.map +1 -0
  82. package/dist/useLanguages.js +29 -0
  83. package/dist/useLanguages.js.map +1 -0
  84. package/dist/usePassage.d.ts +18 -0
  85. package/dist/usePassage.d.ts.map +1 -0
  86. package/dist/usePassage.js +11 -0
  87. package/dist/usePassage.js.map +1 -0
  88. package/dist/useVOTD.d.ts +9 -0
  89. package/dist/useVOTD.d.ts.map +1 -0
  90. package/dist/useVOTD.js +9 -0
  91. package/dist/useVOTD.js.map +1 -0
  92. package/dist/useVerse.d.ts +9 -0
  93. package/dist/useVerse.d.ts.map +1 -0
  94. package/dist/useVerse.js +11 -0
  95. package/dist/useVerse.js.map +1 -0
  96. package/dist/useVerseSelection.d.ts +3 -0
  97. package/dist/useVerseSelection.d.ts.map +1 -0
  98. package/dist/useVerseSelection.js +10 -0
  99. package/dist/useVerseSelection.js.map +1 -0
  100. package/dist/useVerses.d.ts +9 -0
  101. package/dist/useVerses.d.ts.map +1 -0
  102. package/dist/useVerses.js +11 -0
  103. package/dist/useVerses.js.map +1 -0
  104. package/dist/useVersion.d.ts +9 -0
  105. package/dist/useVersion.d.ts.map +1 -0
  106. package/dist/useVersion.js +11 -0
  107. package/dist/useVersion.js.map +1 -0
  108. package/dist/useVersions.d.ts +9 -0
  109. package/dist/useVersions.d.ts.map +1 -0
  110. package/dist/useVersions.js +11 -0
  111. package/dist/useVersions.js.map +1 -0
  112. package/dist/utility/extractTextFromHTML.d.ts +9 -0
  113. package/dist/utility/extractTextFromHTML.d.ts.map +1 -0
  114. package/dist/utility/extractTextFromHTML.js +21 -0
  115. package/dist/utility/extractTextFromHTML.js.map +1 -0
  116. package/dist/utility/extractVersesFromHTML.d.ts +9 -0
  117. package/dist/utility/extractVersesFromHTML.d.ts.map +1 -0
  118. package/dist/utility/extractVersesFromHTML.js +26 -0
  119. package/dist/utility/extractVersesFromHTML.js.map +1 -0
  120. package/dist/utility/getDayOfYear.d.ts +2 -0
  121. package/dist/utility/getDayOfYear.d.ts.map +1 -0
  122. package/dist/utility/getDayOfYear.js +5 -0
  123. package/dist/utility/getDayOfYear.js.map +1 -0
  124. package/dist/utility/index.d.ts +6 -0
  125. package/dist/utility/index.d.ts.map +1 -0
  126. package/dist/utility/index.js +6 -0
  127. package/dist/utility/index.js.map +1 -0
  128. package/dist/utility/useDebounce.d.ts +14 -0
  129. package/dist/utility/useDebounce.d.ts.map +1 -0
  130. package/dist/utility/useDebounce.js +24 -0
  131. package/dist/utility/useDebounce.js.map +1 -0
  132. package/dist/utility/version.d.ts +3 -0
  133. package/dist/utility/version.d.ts.map +1 -0
  134. package/dist/utility/version.js +4 -0
  135. package/dist/utility/version.js.map +1 -0
  136. package/package.json +50 -0
  137. package/src/context/BibleSDKContext.tsx +9 -0
  138. package/src/context/BibleSDKProvider.tsx +16 -0
  139. package/src/context/ReaderContext.tsx +27 -0
  140. package/src/context/ReaderProvider.tsx +36 -0
  141. package/src/context/VerseSelectionContext.tsx +11 -0
  142. package/src/context/VerseSelectionProvider.tsx +39 -0
  143. package/src/context/index.ts +6 -0
  144. package/src/index.ts +20 -0
  145. package/src/test/setup.ts +9 -0
  146. package/src/useApiData.ts +71 -0
  147. package/src/useBibleClient.test.tsx +151 -0
  148. package/src/useBibleClient.ts +22 -0
  149. package/src/useBook.ts +28 -0
  150. package/src/useBooks.ts +31 -0
  151. package/src/useChapter.ts +33 -0
  152. package/src/useChapterNavigation.ts +77 -0
  153. package/src/useChapters.ts +36 -0
  154. package/src/useFilteredVersions.test.tsx +248 -0
  155. package/src/useFilteredVersions.ts +38 -0
  156. package/src/useHighlights.test.tsx +448 -0
  157. package/src/useHighlights.ts +80 -0
  158. package/src/useInitData.ts +54 -0
  159. package/src/useLanguages.test.tsx +296 -0
  160. package/src/useLanguages.ts +57 -0
  161. package/src/usePassage.ts +48 -0
  162. package/src/useVOTD.test.tsx +269 -0
  163. package/src/useVOTD.ts +19 -0
  164. package/src/useVerse.ts +35 -0
  165. package/src/useVerseSelection.ts +13 -0
  166. package/src/useVerses.ts +34 -0
  167. package/src/useVersion.ts +28 -0
  168. package/src/useVersions.ts +33 -0
  169. package/src/utility/extractTextFromHTML.test.ts +112 -0
  170. package/src/utility/extractTextFromHTML.ts +22 -0
  171. package/src/utility/extractVersesFromHTML.test.ts +186 -0
  172. package/src/utility/extractVersesFromHTML.ts +31 -0
  173. package/src/utility/getDayOfYear.ts +6 -0
  174. package/src/utility/index.ts +5 -0
  175. package/src/utility/useDebounce.test.tsx +95 -0
  176. package/src/utility/useDebounce.ts +27 -0
  177. package/src/utility/version.ts +5 -0
  178. package/tsconfig.build.json +8 -0
  179. package/tsconfig.json +13 -0
  180. package/vitest.config.ts +11 -0
  181. package/vitest.setup.ts +1 -0
@@ -0,0 +1,11 @@
1
+ 'use client';
2
+ import { useBibleClient } from './useBibleClient';
3
+ import { useApiData } from './useApiData';
4
+ export function useVersion(versionId, options) {
5
+ const bibleClient = useBibleClient();
6
+ const { data: version, loading, error, refetch, } = useApiData(() => bibleClient.getVersion(versionId), [bibleClient, versionId], {
7
+ enabled: options?.enabled !== false,
8
+ });
9
+ return { version, loading, error, refetch };
10
+ }
11
+ //# sourceMappingURL=useVersion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVersion.js","sourceRoot":"","sources":["../src/useVersion.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,UAAU,EAA0B,MAAM,cAAc,CAAC;AAGlE,MAAM,UAAU,UAAU,CACxB,SAAiB,EACjB,OAA2B;IAO3B,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,MAAM,EACJ,IAAI,EAAE,OAAO,EACb,OAAO,EACP,KAAK,EACL,OAAO,GACR,GAAG,UAAU,CAAe,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC,EAAE;QAC9F,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,KAAK;KACpC,CAAC,CAAC;IAEH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { type UseApiDataOptions } from './useApiData';
2
+ import type { Collection, BibleVersion } from '@youversion/platform-core';
3
+ export declare function useVersions(languageRanges?: string, licenseId?: string | number, options?: UseApiDataOptions): {
4
+ versions: Collection<BibleVersion> | null;
5
+ loading: boolean;
6
+ error: Error | null;
7
+ refetch: () => void;
8
+ };
9
+ //# sourceMappingURL=useVersions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVersions.d.ts","sourceRoot":"","sources":["../src/useVersions.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE1E,wBAAgB,WAAW,CACzB,cAAc,GAAE,MAAa,EAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAC3B,OAAO,CAAC,EAAE,iBAAiB,GAC1B;IACD,QAAQ,EAAE,UAAU,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAiBA"}
@@ -0,0 +1,11 @@
1
+ 'use client';
2
+ import { useBibleClient } from './useBibleClient';
3
+ import { useApiData } from './useApiData';
4
+ export function useVersions(languageRanges = 'en', licenseId, options) {
5
+ const bibleClient = useBibleClient();
6
+ const { data: versions, loading, error, refetch, } = useApiData(() => bibleClient.getVersions(languageRanges, licenseId), [bibleClient, languageRanges, licenseId], {
7
+ enabled: options?.enabled !== false,
8
+ });
9
+ return { versions, loading, error, refetch };
10
+ }
11
+ //# sourceMappingURL=useVersions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVersions.js","sourceRoot":"","sources":["../src/useVersions.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,UAAU,EAA0B,MAAM,cAAc,CAAC;AAGlE,MAAM,UAAU,WAAW,CACzB,iBAAyB,IAAI,EAC7B,SAA2B,EAC3B,OAA2B;IAO3B,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,MAAM,EACJ,IAAI,EAAE,QAAQ,EACd,OAAO,EACP,KAAK,EACL,OAAO,GACR,GAAG,UAAU,CACZ,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,cAAc,EAAE,SAAS,CAAC,EACxD,CAAC,WAAW,EAAE,cAAc,EAAE,SAAS,CAAC,EACxC;QACE,OAAO,EAAE,OAAO,EAAE,OAAO,KAAK,KAAK;KACpC,CACF,CAAC;IAEF,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Extracts readable text from an HTML string, focusing on content spans.
3
+ * This is needed because verses include markup for labels, footnotes, etc.
4
+ *
5
+ * @param html - The HTML content to extract text from
6
+ * @returns Plain text with normalized whitespace
7
+ */
8
+ export declare function extractTextFromHtml(html: string): string;
9
+ //# sourceMappingURL=extractTextFromHTML.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractTextFromHTML.d.ts","sourceRoot":"","sources":["../../src/utility/extractTextFromHTML.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcxD"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Extracts readable text from an HTML string, focusing on content spans.
3
+ * This is needed because verses include markup for labels, footnotes, etc.
4
+ *
5
+ * @param html - The HTML content to extract text from
6
+ * @returns Plain text with normalized whitespace
7
+ */
8
+ export function extractTextFromHtml(html) {
9
+ if (!html)
10
+ return '';
11
+ const container = document.createElement('div');
12
+ container.innerHTML = html;
13
+ // Extract text from content spans and join with spaces
14
+ const contentText = Array.from(container.querySelectorAll('span.content'))
15
+ .map((el) => (el.textContent || '').trim())
16
+ .filter(Boolean)
17
+ .join(' ');
18
+ // Normalize whitespace
19
+ return contentText.replace(/\s+/g, ' ').trim();
20
+ }
21
+ //# sourceMappingURL=extractTextFromHTML.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractTextFromHTML.js","sourceRoot":"","sources":["../../src/utility/extractTextFromHTML.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAErB,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAChD,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC;IAE3B,uDAAuD;IACvD,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAc,cAAc,CAAC,CAAC;SACpF,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;SAC1C,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,uBAAuB;IACvB,OAAO,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACjD,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Splits a passage HTML into an array of verse HTML strings.
3
+ * Expects markers like: <span class="yv-v" v="N"></span><span class="yv-vlbl">N</span>
4
+ */
5
+ export declare function extractVersesFromHTML(html: string | null | undefined): {
6
+ verse: number;
7
+ html: string;
8
+ }[];
9
+ //# sourceMappingURL=extractVersesFromHTML.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractVersesFromHTML.d.ts","sourceRoot":"","sources":["../../src/utility/extractVersesFromHTML.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC9B;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAwBnC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Splits a passage HTML into an array of verse HTML strings.
3
+ * Expects markers like: <span class="yv-v" v="N"></span><span class="yv-vlbl">N</span>
4
+ */
5
+ export function extractVersesFromHTML(html) {
6
+ if (!html)
7
+ return [];
8
+ const results = [];
9
+ const pattern = /<span class="yv-v" v="(\d+)"><\/span><span class="yv-vlbl">\d+<\/span>/g;
10
+ let execResult;
11
+ const indices = [];
12
+ while ((execResult = pattern.exec(html)) !== null) {
13
+ const verseNumString = execResult[1];
14
+ indices.push({ verse: parseInt(verseNumString, 10), index: execResult.index });
15
+ }
16
+ for (let i = 0; i < indices.length; i++) {
17
+ const current = indices[i];
18
+ const next = indices[i + 1];
19
+ const start = current.index;
20
+ const end = next ? next.index : html.length;
21
+ const slice = html.slice(start, end).trim();
22
+ results.push({ verse: current.verse, html: slice });
23
+ }
24
+ return results;
25
+ }
26
+ //# sourceMappingURL=extractVersesFromHTML.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractVersesFromHTML.js","sourceRoot":"","sources":["../../src/utility/extractVersesFromHTML.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,IAA+B;IAE/B,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAErB,MAAM,OAAO,GAAsC,EAAE,CAAC;IACtD,MAAM,OAAO,GAAG,yEAAyE,CAAC;IAE1F,IAAI,UAAkC,CAAC;IACvC,MAAM,OAAO,GAAuC,EAAE,CAAC;IAEvD,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAClD,MAAM,cAAc,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;IACjF,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function getDayOfYear(date: Date): number;
2
+ //# sourceMappingURL=getDayOfYear.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getDayOfYear.d.ts","sourceRoot":"","sources":["../../src/utility/getDayOfYear.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAK/C"}
@@ -0,0 +1,5 @@
1
+ export function getDayOfYear(date) {
2
+ const dayOfYear = Math.floor((date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000);
3
+ return dayOfYear;
4
+ }
5
+ //# sourceMappingURL=getDayOfYear.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getDayOfYear.js","sourceRoot":"","sources":["../../src/utility/getDayOfYear.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CAAC,IAAU;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAC1B,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,QAAQ,CAC3E,CAAC;IACF,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './extractTextFromHTML';
2
+ export * from './useDebounce';
3
+ export * from './version';
4
+ export * from './extractVersesFromHTML';
5
+ export * from './getDayOfYear';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utility/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './extractTextFromHTML';
2
+ export * from './useDebounce';
3
+ export * from './version';
4
+ export * from './extractVersesFromHTML';
5
+ export * from './getDayOfYear';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utility/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Custom hook for debouncing a value.
3
+ *
4
+ * The hook delays the update of the given value until a specified delay has passed
5
+ * after the last change. It is commonly used to optimize the performance of
6
+ * functions that depend on user input or rapidly updating values.
7
+ *
8
+ * @param value - The input value to be debounced.
9
+ * @param delay - The duration in milliseconds to delay the update of the value.
10
+ *
11
+ * @returns The debounced value, updated after the specified delay.
12
+ */
13
+ export declare function useDebounce<T>(value: T, delay: number): T;
14
+ //# sourceMappingURL=useDebounce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDebounce.d.ts","sourceRoot":"","sources":["../../src/utility/useDebounce.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,CAYzD"}
@@ -0,0 +1,24 @@
1
+ import { useEffect, useState } from 'react';
2
+ /**
3
+ * Custom hook for debouncing a value.
4
+ *
5
+ * The hook delays the update of the given value until a specified delay has passed
6
+ * after the last change. It is commonly used to optimize the performance of
7
+ * functions that depend on user input or rapidly updating values.
8
+ *
9
+ * @param value - The input value to be debounced.
10
+ * @param delay - The duration in milliseconds to delay the update of the value.
11
+ *
12
+ * @returns The debounced value, updated after the specified delay.
13
+ */
14
+ export function useDebounce(value, delay) {
15
+ const [debouncedValue, setDebouncedValue] = useState(value);
16
+ useEffect(() => {
17
+ const handler = setTimeout(() => {
18
+ setDebouncedValue(value);
19
+ }, delay);
20
+ return () => clearTimeout(handler);
21
+ }, [value, delay]);
22
+ return debouncedValue;
23
+ }
24
+ //# sourceMappingURL=useDebounce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDebounce.js","sourceRoot":"","sources":["../../src/utility/useDebounce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAI,KAAQ,EAAE,KAAa;IACpD,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE5D,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC,EAAE,KAAK,CAAC,CAAC;QAEV,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAEnB,OAAO,cAAc,CAAC;AACxB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { BibleVersion } from '@youversion/platform-core';
2
+ export declare function getISOFromVersion(version: BibleVersion): string;
3
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/utility/version.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE9D,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAE/D"}
@@ -0,0 +1,4 @@
1
+ export function getISOFromVersion(version) {
2
+ return version?.language_tag || 'unknown';
3
+ }
4
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/utility/version.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,iBAAiB,CAAC,OAAqB;IACrD,OAAO,OAAO,EAAE,YAAY,IAAI,SAAS,CAAC;AAC5C,CAAC"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@youversion/platform-react-hooks",
3
+ "version": "0.4.1",
4
+ "type": "module",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/youversion/platform-sdk-react",
11
+ "directory": "packages/hooks"
12
+ },
13
+ "main": "./dist/index.js",
14
+ "module": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js",
20
+ "require": "./dist/index.js"
21
+ }
22
+ },
23
+ "dependencies": {
24
+ "@youversion/platform-core": "0.4.1"
25
+ },
26
+ "peerDependencies": {
27
+ "react": "19.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "@testing-library/jest-dom": "^6.4.0",
31
+ "@testing-library/react": "^16.0.0",
32
+ "@types/react": "19.2.2",
33
+ "jsdom": "27.0.1",
34
+ "@vitejs/plugin-react": "^4.2.1",
35
+ "eslint": "9.38.0",
36
+ "typescript": "5.9.3",
37
+ "vitest": "4.0.4",
38
+ "@internal/eslint-config": "0.0.0",
39
+ "@internal/tsconfig": "0.0.0"
40
+ },
41
+ "scripts": {
42
+ "dev": "tsc --watch",
43
+ "build": "tsc -p tsconfig.build.json",
44
+ "lint": "eslint . --max-warnings 0",
45
+ "check-types": "tsc --noEmit",
46
+ "test": "vitest run",
47
+ "test:watch": "vitest",
48
+ "test:coverage": "vitest run --coverage"
49
+ }
50
+ }
@@ -0,0 +1,9 @@
1
+ 'use client';
2
+
3
+ import { createContext } from 'react';
4
+
5
+ type BibleSDKContextData = {
6
+ appId: string;
7
+ };
8
+
9
+ export const BibleSDKContext = createContext<BibleSDKContextData | null>(null);
@@ -0,0 +1,16 @@
1
+ 'use client';
2
+
3
+ import type { PropsWithChildren, ReactNode } from 'react';
4
+ import { BibleSDKContext } from './BibleSDKContext';
5
+
6
+ type BibleSDKProviderProps = {
7
+ children: ReactNode;
8
+ appId: string;
9
+ };
10
+
11
+ export function BibleSDKProvider({
12
+ appId,
13
+ children,
14
+ }: PropsWithChildren<BibleSDKProviderProps>): React.ReactElement {
15
+ return <BibleSDKContext.Provider value={{ appId }}>{children}</BibleSDKContext.Provider>;
16
+ }
@@ -0,0 +1,27 @@
1
+ 'use client';
2
+
3
+ import { createContext, useContext } from 'react';
4
+ import type { BibleBook, BibleChapter, BibleVerse, BibleVersion } from '@youversion/platform-core';
5
+
6
+ type ReaderContextData = {
7
+ currentVersion: BibleVersion;
8
+ currentChapter: BibleChapter;
9
+ currentBook: BibleBook;
10
+ currentVerse: BibleVerse | null;
11
+ setVersion: (version: BibleVersion) => void;
12
+ setChapter: (chapter: BibleChapter) => void;
13
+ setBook: (book: BibleBook) => void;
14
+ setVerse: (verse: BibleVerse | null) => void;
15
+ };
16
+
17
+ export const ReaderContext = createContext<ReaderContextData | null>(null);
18
+
19
+ export function useReaderContext(): ReaderContextData {
20
+ const context = useContext(ReaderContext);
21
+
22
+ if (!context) {
23
+ throw new Error('useReaderContext() must be used within a ReaderProvider');
24
+ }
25
+
26
+ return context;
27
+ }
@@ -0,0 +1,36 @@
1
+ 'use client';
2
+
3
+ import { type PropsWithChildren, useState } from 'react';
4
+ import { ReaderContext } from './ReaderContext';
5
+ import type { BibleBook, BibleChapter, BibleVerse, BibleVersion } from '@youversion/platform-core';
6
+
7
+ type ReaderProviderProps = {
8
+ currentVersion: BibleVersion;
9
+ currentChapter: BibleChapter;
10
+ currentBook: BibleBook;
11
+ currentVerse: BibleVerse | null;
12
+ };
13
+
14
+ export function ReaderProvider(props: PropsWithChildren<ReaderProviderProps>): React.ReactElement {
15
+ const [currentVersion, setCurrentVersion] = useState<BibleVersion>(props.currentVersion);
16
+ const [currentBook, setCurrentBook] = useState<BibleBook>(props.currentBook);
17
+ const [currentChapter, setCurrentChapter] = useState<BibleChapter>(props.currentChapter);
18
+ const [currentVerse, setCurrentVerse] = useState<BibleVerse | null>(props.currentVerse);
19
+
20
+ return (
21
+ <ReaderContext.Provider
22
+ value={{
23
+ currentVersion,
24
+ currentBook,
25
+ currentChapter,
26
+ currentVerse,
27
+ setVersion: setCurrentVersion,
28
+ setChapter: setCurrentChapter,
29
+ setBook: setCurrentBook,
30
+ setVerse: setCurrentVerse,
31
+ }}
32
+ >
33
+ {props.children}
34
+ </ReaderContext.Provider>
35
+ );
36
+ }
@@ -0,0 +1,11 @@
1
+ import { createContext } from 'react';
2
+
3
+ export type VerseSelectionContextData = {
4
+ selectedVerseUsfms: Set<string>;
5
+ toggleVerse: (usfm: string) => void;
6
+ isSelected: (usfm: string) => boolean;
7
+ clearSelection: () => void;
8
+ selectedCount: number;
9
+ };
10
+
11
+ export const VerseSelectionContext = createContext<VerseSelectionContextData | null>(null);
@@ -0,0 +1,39 @@
1
+ import { type PropsWithChildren, useCallback, useState } from 'react';
2
+ import { VerseSelectionContext } from './VerseSelectionContext';
3
+
4
+ export function VerseSelectionProvider({ children }: PropsWithChildren): React.ReactElement {
5
+ const [selectedVerseUsfms, setSelectedVerseUsfms] = useState<Set<string>>(new Set());
6
+
7
+ const toggleVerse = useCallback((usfm: string) => {
8
+ setSelectedVerseUsfms((prev) => {
9
+ const newSet = new Set(prev); // Make a new set to trigger rerender
10
+ if (newSet.has(usfm)) {
11
+ newSet.delete(usfm);
12
+ } else {
13
+ newSet.add(usfm);
14
+ }
15
+ return newSet;
16
+ });
17
+ }, []);
18
+
19
+ const isSelected = useCallback(
20
+ (usfm: string) => {
21
+ return selectedVerseUsfms.has(usfm);
22
+ },
23
+ [selectedVerseUsfms],
24
+ );
25
+
26
+ const clearSelection = useCallback(() => {
27
+ setSelectedVerseUsfms(new Set());
28
+ }, []);
29
+
30
+ const value = {
31
+ selectedVerseUsfms,
32
+ toggleVerse,
33
+ isSelected,
34
+ clearSelection,
35
+ selectedCount: selectedVerseUsfms.size,
36
+ };
37
+
38
+ return <VerseSelectionContext.Provider value={value}>{children}</VerseSelectionContext.Provider>;
39
+ }
@@ -0,0 +1,6 @@
1
+ export * from './BibleSDKContext';
2
+ export * from './BibleSDKProvider';
3
+ export * from './ReaderContext';
4
+ export * from './ReaderProvider';
5
+ export * from './VerseSelectionProvider';
6
+ export * from './VerseSelectionContext';
package/src/index.ts ADDED
@@ -0,0 +1,20 @@
1
+ export * from './useBook';
2
+ export * from './useBooks';
3
+ export * from './useChapter';
4
+ export * from './useChapters';
5
+ export * from './useVerse';
6
+ export * from './useVerses';
7
+ export * from './useVersion';
8
+ export * from './utility/useDebounce';
9
+ export * from './useVersions';
10
+ export * from './useFilteredVersions';
11
+ export * from './context';
12
+ export * from './utility';
13
+ export * from './useBibleClient';
14
+ export * from './useVerseSelection';
15
+ export * from './useChapterNavigation';
16
+ export * from './useInitData';
17
+ export * from './usePassage';
18
+ export * from './useVOTD';
19
+ export * from './useHighlights';
20
+ export * from './useLanguages';
@@ -0,0 +1,9 @@
1
+ // Vitest setup file
2
+ import { afterEach } from 'vitest';
3
+ import { cleanup } from '@testing-library/react';
4
+ import '@testing-library/jest-dom/vitest';
5
+
6
+ // Clean up after each test
7
+ afterEach(() => {
8
+ cleanup();
9
+ });
@@ -0,0 +1,71 @@
1
+ 'use client';
2
+
3
+ import { useState, useEffect, useCallback } from 'react';
4
+
5
+ export type UseApiDataOptions = {
6
+ enabled?: boolean;
7
+ };
8
+
9
+ type UseApiDataResult<T> = {
10
+ data: T | null;
11
+ loading: boolean;
12
+ error: Error | null;
13
+ refetch: () => void;
14
+ };
15
+
16
+ export function useApiData<T>(
17
+ fetchFn: () => Promise<T>,
18
+ deps: React.DependencyList,
19
+ options: UseApiDataOptions = {},
20
+ ): UseApiDataResult<T> {
21
+ const { enabled = true } = options;
22
+
23
+ const [data, setData] = useState<T | null>(null);
24
+ const [loading, setLoading] = useState(true);
25
+ const [error, setError] = useState<Error | null>(null);
26
+
27
+ const fetchData = useCallback(() => {
28
+ if (!enabled) {
29
+ setLoading(false);
30
+ return;
31
+ }
32
+
33
+ let canceled = false;
34
+
35
+ setLoading(true);
36
+ setError(null);
37
+
38
+ fetchFn()
39
+ .then((result) => {
40
+ if (!canceled) {
41
+ setData(result);
42
+ }
43
+ })
44
+ .catch((err) => {
45
+ if (!canceled) {
46
+ setError(err as Error);
47
+ }
48
+ })
49
+ .finally(() => {
50
+ if (!canceled) {
51
+ setLoading(false);
52
+ }
53
+ });
54
+
55
+ return () => {
56
+ canceled = true;
57
+ };
58
+ }, [fetchFn, enabled]);
59
+
60
+ const refetch = useCallback(() => {
61
+ fetchData();
62
+ }, [fetchData]);
63
+
64
+ useEffect(() => {
65
+ const cleanup = fetchData();
66
+ return cleanup;
67
+ // @eslint-disable-next-line react-hooks/exhaustive-deps
68
+ }, deps);
69
+
70
+ return { data, loading, error, refetch };
71
+ }