@youversion/platform-react-ui 1.17.0 → 1.18.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.
@@ -1 +1 @@
1
- {"version":3,"file":"bible-card.d.ts","sourceRoot":"","sources":["../../src/components/bible-card.tsx"],"names":[],"mappings":"AAQA,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AACF,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,SAAS,EACT,UAAU,EACV,iBAAyB,GAC1B,EAAE,cAAc,GAAG,KAAK,CAAC,SAAS,CAmElC"}
1
+ {"version":3,"file":"bible-card.d.ts","sourceRoot":"","sources":["../../src/components/bible-card.tsx"],"names":[],"mappings":"AAWA,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAwEF,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,SAAS,EACT,UAAU,EACV,iBAAyB,GAC1B,EAAE,cAAc,GAAG,KAAK,CAAC,SAAS,CAuDlC"}
@@ -1,4 +1,11 @@
1
+ import { usePassage } from '@youversion/platform-react-hooks';
1
2
  import { type FontFamily } from '@/lib/verse-html-utils';
3
+ type PassageResult = ReturnType<typeof usePassage>;
4
+ export type BibleTextViewPassageState = {
5
+ passage: PassageResult['passage'];
6
+ loading: PassageResult['loading'];
7
+ error: PassageResult['error'];
8
+ };
2
9
  /**
3
10
  * Represents a single verse with its number, text, and optional size.
4
11
  */
@@ -57,10 +64,11 @@ export type BibleTextViewProps = {
57
64
  selectedVerses?: number[];
58
65
  onVerseSelect?: (verses: number[]) => void;
59
66
  highlightedVerses?: Record<number, boolean>;
67
+ passageState?: Partial<BibleTextViewPassageState>;
60
68
  };
61
69
  /**
62
70
  * A component that renders style Bible text.
63
71
  */
64
- export declare const BibleTextView: ({ reference, fontFamily, fontSize, lineHeight, versionId, showVerseNumbers, renderNotes, theme, selectedVerses, onVerseSelect, highlightedVerses, }: BibleTextViewProps) => React.ReactElement;
72
+ export declare const BibleTextView: ({ reference, fontFamily, fontSize, lineHeight, versionId, showVerseNumbers, renderNotes, theme, selectedVerses, onVerseSelect, highlightedVerses, passageState, }: BibleTextViewProps) => React.ReactElement;
65
73
  export {};
66
74
  //# sourceMappingURL=verse.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"verse.d.ts","sourceRoot":"","sources":["../../src/components/verse.tsx"],"names":[],"mappings":"AAcA,OAAO,EAGL,KAAK,UAAU,EAEhB,MAAM,wBAAwB,CAAC;AAmLhC;;GAEG;AACH,KAAK,UAAU,GAAG;IAChB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;CACzB,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,KAAK;IAChB;;;;;;;;OAQG;mCACwC,UAAU,KAAG,KAAK,CAAC,YAAY;;CAwE3E,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,qJAY3B,kBAAkB,KAAG,KAAK,CAAC,YAmD7B,CAAC"}
1
+ {"version":3,"file":"verse.d.ts","sourceRoot":"","sources":["../../src/components/verse.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAY,MAAM,kCAAkC,CAAC;AAYxE,OAAO,EAGL,KAAK,UAAU,EAEhB,MAAM,wBAAwB,CAAC;AAchC,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAEnD,MAAM,MAAM,yBAAyB,GAAG;IACtC,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IAClC,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IAClC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC/B,CAAC;AA4KF;;GAEG;AACH,KAAK,UAAU,GAAG;IAChB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;CACzB,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,KAAK;IAChB;;;;;;;;OAQG;mCACwC,UAAU,KAAG,KAAK,CAAC,YAAY;;CAwE3E,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,YAAY,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;CACnD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,mKAa3B,kBAAkB,KAAG,KAAK,CAAC,YAmE7B,CAAC"}
package/dist/index.cjs CHANGED
@@ -15819,10 +15819,17 @@ function buildVerseHtml(wrappers) {
15819
15819
  }
15820
15820
  return parts.join("");
15821
15821
  }
15822
+ var FOOTNOTE_KEY_ATTR = "data-footnote-key";
15823
+ function assignFootnoteKeys(doc) {
15824
+ let introIdx = 0;
15825
+ doc.querySelectorAll(".yv-n.f").forEach((fn) => {
15826
+ const verseNum = fn.closest(".yv-v[v]")?.getAttribute("v");
15827
+ fn.setAttribute(FOOTNOTE_KEY_ATTR, verseNum ?? `intro-${introIdx++}`);
15828
+ });
15829
+ }
15822
15830
  function replaceFootnotesWithAnchors(doc, footnotes) {
15823
15831
  for (const fn of footnotes) {
15824
- const verseNum = fn.closest(".yv-v[v]")?.getAttribute("v");
15825
- if (!verseNum) continue;
15832
+ const key = fn.getAttribute(FOOTNOTE_KEY_ATTR);
15826
15833
  const prev = fn.previousSibling;
15827
15834
  const next = fn.nextSibling;
15828
15835
  const prevText = prev?.textContent ?? "";
@@ -15833,21 +15840,20 @@ function replaceFootnotesWithAnchors(doc, footnotes) {
15833
15840
  fn.parentNode.insertBefore(doc.createTextNode(" "), fn);
15834
15841
  }
15835
15842
  const anchor = doc.createElement("span");
15836
- anchor.setAttribute("data-verse-footnote", verseNum);
15843
+ anchor.setAttribute("data-verse-footnote", key);
15837
15844
  fn.replaceWith(anchor);
15838
15845
  }
15839
15846
  }
15840
15847
  function extractNotesFromWrappedHtml(doc) {
15841
15848
  const footnotes = Array.from(doc.querySelectorAll(".yv-n.f"));
15842
15849
  if (!footnotes.length) return {};
15843
- const footnotesByVerse = /* @__PURE__ */ new Map();
15850
+ const footnotesByKey = /* @__PURE__ */ new Map();
15844
15851
  for (const fn of footnotes) {
15845
- const verseNum = fn.closest(".yv-v[v]")?.getAttribute("v");
15846
- if (!verseNum) continue;
15847
- let arr = footnotesByVerse.get(verseNum);
15852
+ const key = fn.getAttribute(FOOTNOTE_KEY_ATTR);
15853
+ let arr = footnotesByKey.get(key);
15848
15854
  if (!arr) {
15849
15855
  arr = [];
15850
- footnotesByVerse.set(verseNum, arr);
15856
+ footnotesByKey.set(key, arr);
15851
15857
  }
15852
15858
  arr.push(fn);
15853
15859
  }
@@ -15860,10 +15866,12 @@ function extractNotesFromWrappedHtml(doc) {
15860
15866
  else wrappersByVerse.set(verseNum, [el]);
15861
15867
  });
15862
15868
  const notes = {};
15863
- for (const [verseNum, fns] of footnotesByVerse) {
15864
- notes[verseNum] = {
15865
- verseHtml: buildVerseHtml(wrappersByVerse.get(verseNum) ?? []),
15866
- notes: fns.map((fn) => fn.innerHTML)
15869
+ for (const [key, fns] of footnotesByKey) {
15870
+ const wrappers = wrappersByVerse.get(key);
15871
+ notes[key] = {
15872
+ verseHtml: wrappers ? buildVerseHtml(wrappers) : "",
15873
+ notes: fns.map((fn) => fn.innerHTML),
15874
+ hasVerseContext: !!wrappers
15867
15875
  };
15868
15876
  }
15869
15877
  replaceFootnotesWithAnchors(doc, footnotes);
@@ -15915,6 +15923,7 @@ function transformBibleHtml(html) {
15915
15923
  "text/html"
15916
15924
  );
15917
15925
  wrapVerseContent(doc);
15926
+ assignFootnoteKeys(doc);
15918
15927
  const notes = extractNotesFromWrappedHtml(doc);
15919
15928
  addNbspToVerseLabels(doc);
15920
15929
  fixIrregularTables(doc);
@@ -15975,6 +15984,7 @@ var VerseFootnoteButton = (0, import_react3.memo)(function VerseFootnoteButton2(
15975
15984
  fontSize,
15976
15985
  theme
15977
15986
  }) {
15987
+ const { hasVerseContext } = verseNotes;
15978
15988
  const verseReference = reference ? `${reference}:${verseNum}` : `Verse ${verseNum}`;
15979
15989
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Popover, { children: [
15980
15990
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PopoverTrigger, { "data-yv-sdk": true, "data-yv-theme": theme, asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
@@ -15992,15 +16002,17 @@ var VerseFootnoteButton = (0, import_react3.memo)(function VerseFootnoteButton2(
15992
16002
  heading: "Footnotes",
15993
16003
  theme,
15994
16004
  children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "yv:p-3 yv:overflow-y-auto yv:max-h-[33svh]", children: [
15995
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "yv:font-bold yv:mb-2", children: verseReference }),
15996
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
15997
- "div",
15998
- {
15999
- className: "yv:mb-3 yv:font-serif yv:*:font-serif",
16000
- style: { fontSize: fontSize ? `${fontSize}px` : "1.25rem" },
16001
- dangerouslySetInnerHTML: { __html: verseNotes.verseHtml }
16002
- }
16003
- ),
16005
+ hasVerseContext && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
16006
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "yv:font-bold yv:mb-2", children: verseReference }),
16007
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
16008
+ "div",
16009
+ {
16010
+ className: "yv:mb-3 yv:font-serif yv:*:font-serif",
16011
+ style: { fontSize: fontSize ? `${fontSize}px` : "1.25rem" },
16012
+ dangerouslySetInnerHTML: { __html: verseNotes.verseHtml }
16013
+ }
16014
+ )
16015
+ ] }),
16004
16016
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("ul", { className: "yv:list-none yv:p-0 yv:m-0 yv:space-y-1", children: verseNotes.notes.map((note, index) => {
16005
16017
  const marker = getFootnoteMarker(index);
16006
16018
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
@@ -16186,17 +16198,29 @@ var BibleTextView = ({
16186
16198
  theme,
16187
16199
  selectedVerses,
16188
16200
  onVerseSelect,
16189
- highlightedVerses
16201
+ highlightedVerses,
16202
+ passageState
16190
16203
  }) => {
16191
- const { passage, loading, error: error46 } = (0, import_platform_react_hooks3.usePassage)({
16204
+ const providerTheme = (0, import_platform_react_hooks3.useTheme)();
16205
+ const currentTheme = theme || providerTheme;
16206
+ const hasProvidedPassageState = passageState !== void 0;
16207
+ const {
16208
+ passage: fetchedPassage,
16209
+ loading: fetchedLoading,
16210
+ error: fetchedError
16211
+ } = (0, import_platform_react_hooks3.usePassage)({
16192
16212
  versionId,
16193
16213
  usfm: reference,
16194
16214
  include_headings: true,
16195
- include_notes: true
16215
+ include_notes: true,
16216
+ options: {
16217
+ enabled: !hasProvidedPassageState
16218
+ }
16196
16219
  });
16197
- const providerTheme = (0, import_platform_react_hooks3.useTheme)();
16198
- const currentTheme = theme || providerTheme;
16199
- if (loading) {
16220
+ const currentPassage = hasProvidedPassageState ? passageState?.passage : fetchedPassage;
16221
+ const currentLoading = hasProvidedPassageState ? passageState?.loading ?? false : fetchedLoading;
16222
+ const currentError = hasProvidedPassageState ? passageState?.error ?? null : fetchedError;
16223
+ if (currentLoading) {
16200
16224
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "data-yv-sdk": true, "data-yv-theme": currentTheme, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
16201
16225
  Verse.Html,
16202
16226
  {
@@ -16210,19 +16234,19 @@ var BibleTextView = ({
16210
16234
  }
16211
16235
  ) });
16212
16236
  }
16213
- if (error46) {
16237
+ if (currentError) {
16214
16238
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "data-yv-sdk": true, "data-yv-theme": currentTheme, className: "yv:mt-4", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VerseUnavailableMessage, {}) });
16215
16239
  }
16216
16240
  return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { "data-yv-sdk": true, "data-yv-theme": currentTheme, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
16217
16241
  Verse.Html,
16218
16242
  {
16219
- html: passage?.content || "",
16243
+ html: currentPassage?.content || "",
16220
16244
  fontFamily,
16221
16245
  fontSize,
16222
16246
  lineHeight,
16223
16247
  showVerseNumbers,
16224
16248
  renderNotes,
16225
- reference: passage?.reference,
16249
+ reference: currentPassage?.reference,
16226
16250
  theme: currentTheme,
16227
16251
  selectedVerses,
16228
16252
  onVerseSelect,
@@ -17201,6 +17225,52 @@ function VerseOfTheDay({
17201
17225
  var import_platform_react_hooks7 = require("@youversion/platform-react-hooks");
17202
17226
  var import_react8 = require("react");
17203
17227
  var import_jsx_runtime32 = require("react/jsx-runtime");
17228
+ function BibleCardHeaderError() {
17229
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "yv:flex yv:flex-col yv:gap-2", role: "alert", "aria-live": "polite", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("h2", { className: "yv:font-bold yv:tracking-widest yv:text-xs yv:uppercase yv:text-foreground", children: "Error" }) });
17230
+ }
17231
+ function BibleCardHeaderReference({
17232
+ passage,
17233
+ version: version2
17234
+ }) {
17235
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("h2", { className: "yv:font-bold yv:tracking-widest yv:text-xs yv:uppercase yv:text-foreground", children: [
17236
+ passage.reference,
17237
+ " ",
17238
+ version2?.localized_abbreviation
17239
+ ] });
17240
+ }
17241
+ function BibleCardVersionPicker({
17242
+ versionId,
17243
+ onVersionChange,
17244
+ theme
17245
+ }) {
17246
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
17247
+ BibleVersionPicker.Root,
17248
+ {
17249
+ onVersionChange,
17250
+ versionId,
17251
+ background: theme,
17252
+ children: [
17253
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(BibleVersionPicker.Trigger, { "aria-label": "Change Bible version", children: ({ version: version2, loading }) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
17254
+ Button,
17255
+ {
17256
+ variant: "secondary",
17257
+ className: "yv:font-bold yv:text-xs",
17258
+ disabled: loading,
17259
+ "data-yv-theme": theme,
17260
+ children: loading ? "Loading..." : version2?.localized_abbreviation || "Select version"
17261
+ }
17262
+ ) }),
17263
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(BibleVersionPicker.Content, {})
17264
+ ]
17265
+ }
17266
+ );
17267
+ }
17268
+ function BibleCardFooter({ copyright }) {
17269
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "yv:grid yv:grid-cols-[1fr_auto] yv:gap-4 yv:items-center yv:mt-4", children: [
17270
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "yv:text-balance yv:text-muted-foreground yv:justify-self-start yv:font-bold yv:text-[0.5rem]", children: copyright || "" }),
17271
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "yv:justify-self-end", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(SvgComponent, { fontSize: 12 }) })
17272
+ ] });
17273
+ }
17204
17274
  function BibleCard({
17205
17275
  reference,
17206
17276
  versionId,
@@ -17209,7 +17279,11 @@ function BibleCard({
17209
17279
  }) {
17210
17280
  const [versionNum, setVersionNum] = (0, import_react8.useState)(versionId);
17211
17281
  const { version: version2 } = (0, import_platform_react_hooks7.useVersion)(versionNum);
17212
- const { passage } = (0, import_platform_react_hooks7.usePassage)({
17282
+ const {
17283
+ passage,
17284
+ loading: passageLoading,
17285
+ error: passageError
17286
+ } = (0, import_platform_react_hooks7.usePassage)({
17213
17287
  versionId: versionNum,
17214
17288
  usfm: reference,
17215
17289
  include_headings: true,
@@ -17225,30 +17299,14 @@ function BibleCard({
17225
17299
  className: "yv:flex yv:flex-col yv:bg-card yv:p-6 yv:max-w-md yv:rounded-2xl",
17226
17300
  children: [
17227
17301
  /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "yv:flex yv:justify-between yv:items-center", children: [
17228
- passage?.reference ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("h2", { className: "yv:font-bold yv:tracking-widest yv:text-xs yv:uppercase yv:text-foreground", children: [
17229
- passage.reference,
17230
- " ",
17231
- version2?.localized_abbreviation
17232
- ] }) : null,
17233
- showVersionPicker ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
17234
- BibleVersionPicker.Root,
17302
+ passageError ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(BibleCardHeaderError, {}) : null,
17303
+ !passageError && passage ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(BibleCardHeaderReference, { passage, version: version2 }) : null,
17304
+ showVersionPicker && !passageError ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
17305
+ BibleCardVersionPicker,
17235
17306
  {
17236
- onVersionChange: setVersionNum,
17237
17307
  versionId: versionNum,
17238
- background: theme,
17239
- children: [
17240
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(BibleVersionPicker.Trigger, { "aria-label": "Change Bible version", children: ({ version: version3, loading }) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
17241
- Button,
17242
- {
17243
- variant: "secondary",
17244
- className: "yv:font-bold yv:text-xs",
17245
- disabled: loading,
17246
- "data-yv-theme": theme,
17247
- children: loading ? "Loading..." : version3?.localized_abbreviation || "Select version"
17248
- }
17249
- ) }),
17250
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(BibleVersionPicker.Content, {})
17251
- ]
17308
+ onVersionChange: setVersionNum,
17309
+ theme
17252
17310
  }
17253
17311
  ) : null
17254
17312
  ] }),
@@ -17259,13 +17317,15 @@ function BibleCard({
17259
17317
  fontSize: 16,
17260
17318
  fontFamily: SOURCE_SERIF_FONT,
17261
17319
  reference,
17262
- versionId: versionNum
17320
+ versionId: versionNum,
17321
+ passageState: {
17322
+ passage,
17323
+ loading: passageLoading,
17324
+ error: passageError
17325
+ }
17263
17326
  }
17264
17327
  ),
17265
- /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "yv:grid yv:grid-cols-[1fr_auto] yv:gap-4 yv:items-center yv:mt-4", children: [
17266
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "yv:text-balance yv:text-muted-foreground yv:justify-self-start yv:font-bold yv:text-[0.5rem]", children: version2?.copyright }),
17267
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "yv:justify-self-end", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(SvgComponent, { fontSize: 12 }) })
17268
- ] })
17328
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(BibleCardFooter, { copyright: !passageError ? version2?.copyright : null })
17269
17329
  ]
17270
17330
  }
17271
17331
  );
package/dist/index.js CHANGED
@@ -15806,10 +15806,17 @@ function buildVerseHtml(wrappers) {
15806
15806
  }
15807
15807
  return parts.join("");
15808
15808
  }
15809
+ var FOOTNOTE_KEY_ATTR = "data-footnote-key";
15810
+ function assignFootnoteKeys(doc) {
15811
+ let introIdx = 0;
15812
+ doc.querySelectorAll(".yv-n.f").forEach((fn) => {
15813
+ const verseNum = fn.closest(".yv-v[v]")?.getAttribute("v");
15814
+ fn.setAttribute(FOOTNOTE_KEY_ATTR, verseNum ?? `intro-${introIdx++}`);
15815
+ });
15816
+ }
15809
15817
  function replaceFootnotesWithAnchors(doc, footnotes) {
15810
15818
  for (const fn of footnotes) {
15811
- const verseNum = fn.closest(".yv-v[v]")?.getAttribute("v");
15812
- if (!verseNum) continue;
15819
+ const key = fn.getAttribute(FOOTNOTE_KEY_ATTR);
15813
15820
  const prev = fn.previousSibling;
15814
15821
  const next = fn.nextSibling;
15815
15822
  const prevText = prev?.textContent ?? "";
@@ -15820,21 +15827,20 @@ function replaceFootnotesWithAnchors(doc, footnotes) {
15820
15827
  fn.parentNode.insertBefore(doc.createTextNode(" "), fn);
15821
15828
  }
15822
15829
  const anchor = doc.createElement("span");
15823
- anchor.setAttribute("data-verse-footnote", verseNum);
15830
+ anchor.setAttribute("data-verse-footnote", key);
15824
15831
  fn.replaceWith(anchor);
15825
15832
  }
15826
15833
  }
15827
15834
  function extractNotesFromWrappedHtml(doc) {
15828
15835
  const footnotes = Array.from(doc.querySelectorAll(".yv-n.f"));
15829
15836
  if (!footnotes.length) return {};
15830
- const footnotesByVerse = /* @__PURE__ */ new Map();
15837
+ const footnotesByKey = /* @__PURE__ */ new Map();
15831
15838
  for (const fn of footnotes) {
15832
- const verseNum = fn.closest(".yv-v[v]")?.getAttribute("v");
15833
- if (!verseNum) continue;
15834
- let arr = footnotesByVerse.get(verseNum);
15839
+ const key = fn.getAttribute(FOOTNOTE_KEY_ATTR);
15840
+ let arr = footnotesByKey.get(key);
15835
15841
  if (!arr) {
15836
15842
  arr = [];
15837
- footnotesByVerse.set(verseNum, arr);
15843
+ footnotesByKey.set(key, arr);
15838
15844
  }
15839
15845
  arr.push(fn);
15840
15846
  }
@@ -15847,10 +15853,12 @@ function extractNotesFromWrappedHtml(doc) {
15847
15853
  else wrappersByVerse.set(verseNum, [el]);
15848
15854
  });
15849
15855
  const notes = {};
15850
- for (const [verseNum, fns] of footnotesByVerse) {
15851
- notes[verseNum] = {
15852
- verseHtml: buildVerseHtml(wrappersByVerse.get(verseNum) ?? []),
15853
- notes: fns.map((fn) => fn.innerHTML)
15856
+ for (const [key, fns] of footnotesByKey) {
15857
+ const wrappers = wrappersByVerse.get(key);
15858
+ notes[key] = {
15859
+ verseHtml: wrappers ? buildVerseHtml(wrappers) : "",
15860
+ notes: fns.map((fn) => fn.innerHTML),
15861
+ hasVerseContext: !!wrappers
15854
15862
  };
15855
15863
  }
15856
15864
  replaceFootnotesWithAnchors(doc, footnotes);
@@ -15902,6 +15910,7 @@ function transformBibleHtml(html) {
15902
15910
  "text/html"
15903
15911
  );
15904
15912
  wrapVerseContent(doc);
15913
+ assignFootnoteKeys(doc);
15905
15914
  const notes = extractNotesFromWrappedHtml(doc);
15906
15915
  addNbspToVerseLabels(doc);
15907
15916
  fixIrregularTables(doc);
@@ -15962,6 +15971,7 @@ var VerseFootnoteButton = memo(function VerseFootnoteButton2({
15962
15971
  fontSize,
15963
15972
  theme
15964
15973
  }) {
15974
+ const { hasVerseContext } = verseNotes;
15965
15975
  const verseReference = reference ? `${reference}:${verseNum}` : `Verse ${verseNum}`;
15966
15976
  return /* @__PURE__ */ jsxs7(Popover, { children: [
15967
15977
  /* @__PURE__ */ jsx22(PopoverTrigger, { "data-yv-sdk": true, "data-yv-theme": theme, asChild: true, children: /* @__PURE__ */ jsx22(
@@ -15979,15 +15989,17 @@ var VerseFootnoteButton = memo(function VerseFootnoteButton2({
15979
15989
  heading: "Footnotes",
15980
15990
  theme,
15981
15991
  children: /* @__PURE__ */ jsxs7("div", { className: "yv:p-3 yv:overflow-y-auto yv:max-h-[33svh]", children: [
15982
- /* @__PURE__ */ jsx22("div", { className: "yv:font-bold yv:mb-2", children: verseReference }),
15983
- /* @__PURE__ */ jsx22(
15984
- "div",
15985
- {
15986
- className: "yv:mb-3 yv:font-serif yv:*:font-serif",
15987
- style: { fontSize: fontSize ? `${fontSize}px` : "1.25rem" },
15988
- dangerouslySetInnerHTML: { __html: verseNotes.verseHtml }
15989
- }
15990
- ),
15992
+ hasVerseContext && /* @__PURE__ */ jsxs7(Fragment2, { children: [
15993
+ /* @__PURE__ */ jsx22("div", { className: "yv:font-bold yv:mb-2", children: verseReference }),
15994
+ /* @__PURE__ */ jsx22(
15995
+ "div",
15996
+ {
15997
+ className: "yv:mb-3 yv:font-serif yv:*:font-serif",
15998
+ style: { fontSize: fontSize ? `${fontSize}px` : "1.25rem" },
15999
+ dangerouslySetInnerHTML: { __html: verseNotes.verseHtml }
16000
+ }
16001
+ )
16002
+ ] }),
15991
16003
  /* @__PURE__ */ jsx22("ul", { className: "yv:list-none yv:p-0 yv:m-0 yv:space-y-1", children: verseNotes.notes.map((note, index) => {
15992
16004
  const marker = getFootnoteMarker(index);
15993
16005
  return /* @__PURE__ */ jsxs7(
@@ -16173,17 +16185,29 @@ var BibleTextView = ({
16173
16185
  theme,
16174
16186
  selectedVerses,
16175
16187
  onVerseSelect,
16176
- highlightedVerses
16188
+ highlightedVerses,
16189
+ passageState
16177
16190
  }) => {
16178
- const { passage, loading, error: error46 } = usePassage({
16191
+ const providerTheme = useTheme3();
16192
+ const currentTheme = theme || providerTheme;
16193
+ const hasProvidedPassageState = passageState !== void 0;
16194
+ const {
16195
+ passage: fetchedPassage,
16196
+ loading: fetchedLoading,
16197
+ error: fetchedError
16198
+ } = usePassage({
16179
16199
  versionId,
16180
16200
  usfm: reference,
16181
16201
  include_headings: true,
16182
- include_notes: true
16202
+ include_notes: true,
16203
+ options: {
16204
+ enabled: !hasProvidedPassageState
16205
+ }
16183
16206
  });
16184
- const providerTheme = useTheme3();
16185
- const currentTheme = theme || providerTheme;
16186
- if (loading) {
16207
+ const currentPassage = hasProvidedPassageState ? passageState?.passage : fetchedPassage;
16208
+ const currentLoading = hasProvidedPassageState ? passageState?.loading ?? false : fetchedLoading;
16209
+ const currentError = hasProvidedPassageState ? passageState?.error ?? null : fetchedError;
16210
+ if (currentLoading) {
16187
16211
  return /* @__PURE__ */ jsx22("div", { "data-yv-sdk": true, "data-yv-theme": currentTheme, children: /* @__PURE__ */ jsx22(
16188
16212
  Verse.Html,
16189
16213
  {
@@ -16197,19 +16221,19 @@ var BibleTextView = ({
16197
16221
  }
16198
16222
  ) });
16199
16223
  }
16200
- if (error46) {
16224
+ if (currentError) {
16201
16225
  return /* @__PURE__ */ jsx22("div", { "data-yv-sdk": true, "data-yv-theme": currentTheme, className: "yv:mt-4", children: /* @__PURE__ */ jsx22(VerseUnavailableMessage, {}) });
16202
16226
  }
16203
16227
  return /* @__PURE__ */ jsx22("div", { "data-yv-sdk": true, "data-yv-theme": currentTheme, children: /* @__PURE__ */ jsx22(
16204
16228
  Verse.Html,
16205
16229
  {
16206
- html: passage?.content || "",
16230
+ html: currentPassage?.content || "",
16207
16231
  fontFamily,
16208
16232
  fontSize,
16209
16233
  lineHeight,
16210
16234
  showVerseNumbers,
16211
16235
  renderNotes,
16212
- reference: passage?.reference,
16236
+ reference: currentPassage?.reference,
16213
16237
  theme: currentTheme,
16214
16238
  selectedVerses,
16215
16239
  onVerseSelect,
@@ -17194,6 +17218,52 @@ function VerseOfTheDay({
17194
17218
  import { usePassage as usePassage3, useVersion as useVersion4, useTheme as useTheme7 } from "@youversion/platform-react-hooks";
17195
17219
  import { useState as useState5 } from "react";
17196
17220
  import { jsx as jsx32, jsxs as jsxs15 } from "react/jsx-runtime";
17221
+ function BibleCardHeaderError() {
17222
+ return /* @__PURE__ */ jsx32("div", { className: "yv:flex yv:flex-col yv:gap-2", role: "alert", "aria-live": "polite", children: /* @__PURE__ */ jsx32("h2", { className: "yv:font-bold yv:tracking-widest yv:text-xs yv:uppercase yv:text-foreground", children: "Error" }) });
17223
+ }
17224
+ function BibleCardHeaderReference({
17225
+ passage,
17226
+ version: version2
17227
+ }) {
17228
+ return /* @__PURE__ */ jsxs15("h2", { className: "yv:font-bold yv:tracking-widest yv:text-xs yv:uppercase yv:text-foreground", children: [
17229
+ passage.reference,
17230
+ " ",
17231
+ version2?.localized_abbreviation
17232
+ ] });
17233
+ }
17234
+ function BibleCardVersionPicker({
17235
+ versionId,
17236
+ onVersionChange,
17237
+ theme
17238
+ }) {
17239
+ return /* @__PURE__ */ jsxs15(
17240
+ BibleVersionPicker.Root,
17241
+ {
17242
+ onVersionChange,
17243
+ versionId,
17244
+ background: theme,
17245
+ children: [
17246
+ /* @__PURE__ */ jsx32(BibleVersionPicker.Trigger, { "aria-label": "Change Bible version", children: ({ version: version2, loading }) => /* @__PURE__ */ jsx32(
17247
+ Button,
17248
+ {
17249
+ variant: "secondary",
17250
+ className: "yv:font-bold yv:text-xs",
17251
+ disabled: loading,
17252
+ "data-yv-theme": theme,
17253
+ children: loading ? "Loading..." : version2?.localized_abbreviation || "Select version"
17254
+ }
17255
+ ) }),
17256
+ /* @__PURE__ */ jsx32(BibleVersionPicker.Content, {})
17257
+ ]
17258
+ }
17259
+ );
17260
+ }
17261
+ function BibleCardFooter({ copyright }) {
17262
+ return /* @__PURE__ */ jsxs15("div", { className: "yv:grid yv:grid-cols-[1fr_auto] yv:gap-4 yv:items-center yv:mt-4", children: [
17263
+ /* @__PURE__ */ jsx32("p", { className: "yv:text-balance yv:text-muted-foreground yv:justify-self-start yv:font-bold yv:text-[0.5rem]", children: copyright || "" }),
17264
+ /* @__PURE__ */ jsx32("div", { className: "yv:justify-self-end", children: /* @__PURE__ */ jsx32(SvgComponent, { fontSize: 12 }) })
17265
+ ] });
17266
+ }
17197
17267
  function BibleCard({
17198
17268
  reference,
17199
17269
  versionId,
@@ -17202,7 +17272,11 @@ function BibleCard({
17202
17272
  }) {
17203
17273
  const [versionNum, setVersionNum] = useState5(versionId);
17204
17274
  const { version: version2 } = useVersion4(versionNum);
17205
- const { passage } = usePassage3({
17275
+ const {
17276
+ passage,
17277
+ loading: passageLoading,
17278
+ error: passageError
17279
+ } = usePassage3({
17206
17280
  versionId: versionNum,
17207
17281
  usfm: reference,
17208
17282
  include_headings: true,
@@ -17218,30 +17292,14 @@ function BibleCard({
17218
17292
  className: "yv:flex yv:flex-col yv:bg-card yv:p-6 yv:max-w-md yv:rounded-2xl",
17219
17293
  children: [
17220
17294
  /* @__PURE__ */ jsxs15("div", { className: "yv:flex yv:justify-between yv:items-center", children: [
17221
- passage?.reference ? /* @__PURE__ */ jsxs15("h2", { className: "yv:font-bold yv:tracking-widest yv:text-xs yv:uppercase yv:text-foreground", children: [
17222
- passage.reference,
17223
- " ",
17224
- version2?.localized_abbreviation
17225
- ] }) : null,
17226
- showVersionPicker ? /* @__PURE__ */ jsxs15(
17227
- BibleVersionPicker.Root,
17295
+ passageError ? /* @__PURE__ */ jsx32(BibleCardHeaderError, {}) : null,
17296
+ !passageError && passage ? /* @__PURE__ */ jsx32(BibleCardHeaderReference, { passage, version: version2 }) : null,
17297
+ showVersionPicker && !passageError ? /* @__PURE__ */ jsx32(
17298
+ BibleCardVersionPicker,
17228
17299
  {
17229
- onVersionChange: setVersionNum,
17230
17300
  versionId: versionNum,
17231
- background: theme,
17232
- children: [
17233
- /* @__PURE__ */ jsx32(BibleVersionPicker.Trigger, { "aria-label": "Change Bible version", children: ({ version: version3, loading }) => /* @__PURE__ */ jsx32(
17234
- Button,
17235
- {
17236
- variant: "secondary",
17237
- className: "yv:font-bold yv:text-xs",
17238
- disabled: loading,
17239
- "data-yv-theme": theme,
17240
- children: loading ? "Loading..." : version3?.localized_abbreviation || "Select version"
17241
- }
17242
- ) }),
17243
- /* @__PURE__ */ jsx32(BibleVersionPicker.Content, {})
17244
- ]
17301
+ onVersionChange: setVersionNum,
17302
+ theme
17245
17303
  }
17246
17304
  ) : null
17247
17305
  ] }),
@@ -17252,13 +17310,15 @@ function BibleCard({
17252
17310
  fontSize: 16,
17253
17311
  fontFamily: SOURCE_SERIF_FONT,
17254
17312
  reference,
17255
- versionId: versionNum
17313
+ versionId: versionNum,
17314
+ passageState: {
17315
+ passage,
17316
+ loading: passageLoading,
17317
+ error: passageError
17318
+ }
17256
17319
  }
17257
17320
  ),
17258
- /* @__PURE__ */ jsxs15("div", { className: "yv:grid yv:grid-cols-[1fr_auto] yv:gap-4 yv:items-center yv:mt-4", children: [
17259
- /* @__PURE__ */ jsx32("p", { className: "yv:text-balance yv:text-muted-foreground yv:justify-self-start yv:font-bold yv:text-[0.5rem]", children: version2?.copyright }),
17260
- /* @__PURE__ */ jsx32("div", { className: "yv:justify-self-end", children: /* @__PURE__ */ jsx32(SvgComponent, { fontSize: 12 }) })
17261
- ] })
17321
+ /* @__PURE__ */ jsx32(BibleCardFooter, { copyright: !passageError ? version2?.copyright : null })
17262
17322
  ]
17263
17323
  }
17264
17324
  );
@@ -11,6 +11,7 @@ export declare function getFootnoteMarker(index: number): string;
11
11
  export type VerseNotes = {
12
12
  verseHtml: string;
13
13
  notes: string[];
14
+ hasVerseContext: boolean;
14
15
  };
15
16
  export declare const INTER_FONT: "\"Inter\", sans-serif";
16
17
  export declare const SOURCE_SERIF_FONT: "\"Source Serif 4\", serif";
@@ -1 +1 @@
1
- {"version":3,"file":"verse-html-utils.d.ts","sourceRoot":"","sources":["../../src/lib/verse-html-utils.ts"],"names":[],"mappings":"AAMA;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAavD;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAG,uBAA8B,CAAC;AACzD,eAAO,MAAM,iBAAiB,EAAG,2BAAkC,CAAC;AACpE,MAAM,MAAM,UAAU,GAAG,OAAO,UAAU,GAAG,OAAO,iBAAiB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AA0UtF;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;CAAE,CAgBpG"}
1
+ {"version":3,"file":"verse-html-utils.d.ts","sourceRoot":"","sources":["../../src/lib/verse-html-utils.ts"],"names":[],"mappings":"AAMA;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAavD;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,UAAU,EAAG,uBAA8B,CAAC;AACzD,eAAO,MAAM,iBAAiB,EAAG,2BAAkC,CAAC;AACpE,MAAM,MAAM,UAAU,GAAG,OAAO,UAAU,GAAG,OAAO,iBAAiB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AA4VtF;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;CAAE,CAiBpG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youversion/platform-react-ui",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "React SDK for YouVersion Platform",
5
5
  "license": "TBD",
6
6
  "type": "module",
@@ -38,8 +38,8 @@
38
38
  "isomorphic-dompurify": "2.23.0",
39
39
  "tailwind-merge": "3.3.1",
40
40
  "tw-animate-css": "1.4.0",
41
- "@youversion/platform-core": "1.17.0",
42
- "@youversion/platform-react-hooks": "1.17.0"
41
+ "@youversion/platform-core": "1.18.0",
42
+ "@youversion/platform-react-hooks": "1.18.0"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "react": ">=19.1.0 <20.0.0",
@@ -76,8 +76,8 @@
76
76
  "vite": "7.1.11",
77
77
  "vitest": "4.0.4",
78
78
  "vitest-browser-react": "2.0.2",
79
- "@internal/tsconfig": "0.0.0",
80
- "@internal/eslint-config": "0.0.0"
79
+ "@internal/eslint-config": "0.0.0",
80
+ "@internal/tsconfig": "0.0.0"
81
81
  },
82
82
  "publishConfig": {
83
83
  "access": "public",