boltdocs 3.3.6 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/dist/{adapters-BKzKe2mO.mjs → adapters-BXiBWAKs.mjs} +1 -1
  2. package/dist/{adapters-DwDTQoCG.cjs → adapters-Czl3WtQt.cjs} +1 -1
  3. package/dist/{build-CxT38vPv.cjs → build-CNkXRdk8.cjs} +1 -1
  4. package/dist/{build-BJnL-FHG.mjs → build-CqUBsXVC.mjs} +1 -1
  5. package/dist/client/index.cjs +223 -51
  6. package/dist/client/index.d.cts +3 -3
  7. package/dist/client/index.d.ts +3 -3
  8. package/dist/client/index.js +226 -56
  9. package/dist/client/mdx.cjs +1 -1
  10. package/dist/client/mdx.js +1 -1
  11. package/dist/client/primitives.cjs +5 -5
  12. package/dist/client/primitives.d.cts +53 -34
  13. package/dist/client/primitives.d.ts +62 -43
  14. package/dist/client/primitives.js +4 -4
  15. package/dist/client/router.cjs +1 -1
  16. package/dist/client/router.d.cts +1 -1
  17. package/dist/client/router.d.ts +1 -1
  18. package/dist/client/router.js +1 -1
  19. package/dist/client/theme/reset.css +41 -0
  20. package/dist/{config-BJp3lGzE.cjs → config-B3SEoVjG.cjs} +2 -2
  21. package/dist/{config-BC_qhXws.cjs → config-Bfakeadu.cjs} +1 -1
  22. package/dist/{config-B3_iVsbi.mjs → config-CTcfF-0c.mjs} +2 -2
  23. package/dist/dev-D1DmOSjn.mjs +6 -0
  24. package/dist/dev-DH6cSge8.cjs +6 -0
  25. package/dist/{docs-layout-D3Fmb0Wd.js → docs-layout-CmntYM6p.js} +33 -33
  26. package/dist/{docs-layout-SgphExoE.cjs → docs-layout-DIgxJ5c7.cjs} +9 -9
  27. package/dist/{doctor-BqxOFRt3.cjs → doctor-BLxm2alc.cjs} +1 -1
  28. package/dist/{doctor-TS3JGNEU.cjs → doctor-Dd-JMTRo.cjs} +1 -1
  29. package/dist/{doctor-Cv5lXnay.mjs → doctor-DogHujrP.mjs} +1 -1
  30. package/dist/{image-Bkx85rsq.cjs → image-Bke2ojW1.cjs} +3 -3
  31. package/dist/{image-BAiDReNd.js → image-CaY2w0ua.js} +2 -1
  32. package/dist/index--xbYbT8N.d.ts +343 -0
  33. package/dist/{index-B1Mx0dHl.d.ts → index-B_o5y34l.d.cts} +89 -10
  34. package/dist/{index-DLaHgD-i.d.cts → index-Bx0CUd7Q.d.ts} +89 -10
  35. package/dist/index-RK7W_Fxy.d.cts +343 -0
  36. package/dist/{link-q1qHNGK_.js → link-CSe_oD8Y.js} +86 -113
  37. package/dist/{link-hLWOsx0x.cjs → link-Xb69Oy2F.cjs} +87 -143
  38. package/dist/{mdx-Qi0DmaY8.cjs → mdx-BCOrMd-P.cjs} +68 -16
  39. package/dist/{mdx-CJGWzBGy.js → mdx-BijiEbkp.js} +62 -15
  40. package/dist/{native-nLA4Jr0T.cjs → native-BbtRkce5.cjs} +1 -1
  41. package/dist/node/cli-entry.cjs +1 -1
  42. package/dist/node/cli-entry.mjs +1 -1
  43. package/dist/node/highlight.d.cts +2 -2
  44. package/dist/node/highlight.d.mts +2 -2
  45. package/dist/node/index.cjs +1 -1
  46. package/dist/node/index.d.cts +18 -39
  47. package/dist/node/index.d.mts +19 -40
  48. package/dist/node/index.mjs +1 -1
  49. package/dist/node/mdx/shiki-adapter.d.cts +1 -1
  50. package/dist/node/mdx/shiki-adapter.d.mts +1 -1
  51. package/dist/node-BgiLCa0I.cjs +39 -0
  52. package/dist/node-Da3tYBHo.mjs +39 -0
  53. package/dist/{package-Bah2tHjK.cjs → package-D1gVs5gQ.cjs} +1 -1
  54. package/dist/{package-D6bf68FR.mjs → package-YgQJn3Yh.mjs} +1 -1
  55. package/dist/pages-external-B_r6gvqP.cjs +6 -0
  56. package/dist/pages-external-jmK7AHaO.mjs +6 -0
  57. package/dist/{parser-CD8Oo8qh.mjs → parser-CvNZc5s3.mjs} +1 -1
  58. package/dist/{parser-vPaKvzLp.cjs → parser-DJLWTiO-.cjs} +1 -1
  59. package/dist/plugin-DW9K2fW5.mjs +69 -0
  60. package/dist/plugin-NwGKyTJX.cjs +69 -0
  61. package/dist/{plugin-context-b5qVVQSU.mjs → plugin-context-COh-cbsW.mjs} +1 -1
  62. package/dist/{plugin-context-BZs5lvDu.cjs → plugin-context-FIHaWn6r.cjs} +1 -1
  63. package/dist/{plugin-lifecycle-s89gzTlh.cjs → plugin-lifecycle-D9fTRaWY.cjs} +1 -1
  64. package/dist/{registry-B8pt41zj.d.cts → registry-BFmzj1yg.d.mts} +1 -1
  65. package/dist/{registry-BrrH2X9c.d.mts → registry-BoswPzYV.d.cts} +1 -1
  66. package/dist/{resolve-C5rT6B21.mjs → resolve-5puUe7eS.mjs} +1 -1
  67. package/dist/{resolve-BelytNYR.cjs → resolve-CF4ZLfqx.cjs} +1 -1
  68. package/dist/route-paths-B6ocUfNY.cjs +6 -0
  69. package/dist/route-paths-DyDji4bX.mjs +6 -0
  70. package/dist/{router-CZBxMRAH.js → router-B5e8k4qK.js} +175 -10
  71. package/dist/{router-C3kygdRK.cjs → router-DKC0Lu0n.cjs} +204 -9
  72. package/dist/{routes-Dq_2EUIB.cjs → routes-D55M8UrH.cjs} +1 -1
  73. package/dist/{routes-CzhKOw67.cjs → routes-DdE6Lfcl.cjs} +1 -1
  74. package/dist/{routes-Dw6g0bfF.mjs → routes-_I_8PQYF.mjs} +1 -1
  75. package/dist/{search-dialog-CguKVtUu.cjs → search-dialog-BOQRHKTb.cjs} +53 -20
  76. package/dist/{search-dialog-mYnqU4v7.js → search-dialog-BXil4_7P.js} +57 -24
  77. package/dist/{search-dialog-BYZS9aeO.cjs → search-dialog-CwlBd-Mu.cjs} +5 -5
  78. package/dist/{search-dialog-DQwod5Xc.js → search-dialog-D3Obh3eA.js} +1 -1
  79. package/dist/{search-dialog-DzObE-Ar.js → search-dialog-DeplpVEB.js} +3 -3
  80. package/dist/{search-dialog-QgKRRbsI.cjs → search-dialog-cHXR5zhL.cjs} +1 -1
  81. package/dist/server/index.cjs +1 -1
  82. package/dist/server/index.d.mts +1 -1
  83. package/dist/server/index.mjs +1 -1
  84. package/dist/ssg-static-options-Br1_u9qp.mjs +6 -0
  85. package/dist/ssg-static-options-CVvGKM8i.cjs +6 -0
  86. package/dist/types-58Ac3UGI.d.cts +114 -0
  87. package/dist/types-BwnGf-1E.d.mts +114 -0
  88. package/dist/{virtual-modules-C3S3Nz8r.cjs → virtual-modules-C4-qxFlL.cjs} +1 -1
  89. package/dist/{virtual-modules-CaxqrFd6.mjs → virtual-modules-DiWUKJGP.mjs} +1 -1
  90. package/package.json +5 -3
  91. package/src/shared/types.ts +133 -987
  92. package/dist/dev-46NiL0MC.cjs +0 -6
  93. package/dist/dev-C4kjO5xs.mjs +0 -6
  94. package/dist/index-CgWkOCCn.d.cts +0 -1193
  95. package/dist/index-CuNSD3E2.d.ts +0 -1193
  96. package/dist/node-7Cfw6nMr.cjs +0 -23
  97. package/dist/node-CT2E84nY.mjs +0 -23
  98. package/dist/pages-external-BBw8ObVK.mjs +0 -6
  99. package/dist/pages-external-DPiPFxxP.cjs +0 -6
  100. package/dist/plugin-AgNI3ktz.cjs +0 -69
  101. package/dist/plugin-BAv_pYLt.mjs +0 -69
  102. package/dist/types-74i_xUe2.d.mts +0 -975
  103. package/dist/types-X_Pwk8Cg.d.cts +0 -975
  104. /package/dist/{audit-CMc_ydRr.mjs → audit-CYAkXXvP.mjs} +0 -0
  105. /package/dist/{audit-CHkGiV3c.cjs → audit-DxCZZTuX.cjs} +0 -0
  106. /package/dist/{csp-BiGAG8aF.cjs → csp-B-gc2Iha.cjs} +0 -0
  107. /package/dist/{csp-D0BOH8ae.mjs → csp-f8DOcI_7.mjs} +0 -0
  108. /package/dist/{generator-BCrZL53x.cjs → generator-CBAPKY6r.cjs} +0 -0
  109. /package/dist/{generator-CFukoGa0.mjs → generator-MRpn-yp6.mjs} +0 -0
  110. /package/dist/{handler-Lex5DbvG.mjs → handler-DBZqoWt2.mjs} +0 -0
  111. /package/dist/{handler-Ch-Q9NAB.cjs → handler-ryZR9Q41.cjs} +0 -0
  112. /package/dist/{index-HAwIo4nZ.d.mts → index-CPr34I2C.d.mts} +0 -0
  113. /package/dist/{native-BYKMke79.mjs → native-DZ6WMwjG.mjs} +0 -0
  114. /package/dist/{native-BOet8hpE.cjs → native-DeKxny_T.cjs} +0 -0
  115. /package/dist/{update-check-BXD1atVv.mjs → update-check-BXx8te9F.mjs} +0 -0
  116. /package/dist/{update-check-DFQZyoSU.cjs → update-check-CiIeC7CX.cjs} +0 -0
@@ -3,8 +3,8 @@
3
3
  * Copyright (c) 2026 Jesus Alcala
4
4
  * Licensed under the MIT License.
5
5
  */
6
- import { E as useLocation, O as useNavigate, c as hasUriScheme, h as resolveUrlReference, k as usePrefetch, l as hasUrlBase, m as parseUrlReference } from "./router-CZBxMRAH.js";
7
- import { createContext, use, useCallback, useEffect, useMemo, useState } from "react";
6
+ import { E as useLocation, O as useNavigate, V as useConfig, c as hasUriScheme, h as resolveUrlReference, k as usePrefetch, l as hasUrlBase, m as parseUrlReference, z as useViewTransition } from "./router-B5e8k4qK.js";
7
+ import React, { createContext, use, useCallback, useEffect, useMemo, useState } from "react";
8
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { clsx } from "clsx";
10
10
  import { twMerge } from "tailwind-merge";
@@ -39,10 +39,10 @@ function getSavedPrefs() {
39
39
  return {};
40
40
  }
41
41
  }
42
- const globalRegistry$1 = globalThis;
43
- const existingContext = globalRegistry$1[BOLTDOCS_CONTEXT_SYMBOL];
42
+ const globalRegistry = globalThis;
43
+ const existingContext = globalRegistry[BOLTDOCS_CONTEXT_SYMBOL];
44
44
  const BoltdocsContext = existingContext || createContext(void 0);
45
- if (!existingContext) Reflect.set(globalRegistry$1, BOLTDOCS_CONTEXT_SYMBOL, BoltdocsContext);
45
+ if (!existingContext) Reflect.set(globalRegistry, BOLTDOCS_CONTEXT_SYMBOL, BoltdocsContext);
46
46
  function BoltdocsProvider({ children, initialLocale = "", initialVersion = "" }) {
47
47
  const [locale, setLocaleState] = useState(() => {
48
48
  if (initialLocale) return initialLocale;
@@ -65,7 +65,7 @@ function BoltdocsProvider({ children, initialLocale = "", initialVersion = "" })
65
65
  return newL;
66
66
  });
67
67
  if (typeof globalThis !== "undefined") Reflect.set(globalThis, BOLTDOCS_INSTANCE_SYMBOL, {
68
- ...globalRegistry$1[BOLTDOCS_INSTANCE_SYMBOL],
68
+ ...globalRegistry[BOLTDOCS_INSTANCE_SYMBOL],
69
69
  currentLocale: newL
70
70
  });
71
71
  if (typeof window !== "undefined") try {
@@ -83,7 +83,7 @@ function BoltdocsProvider({ children, initialLocale = "", initialVersion = "" })
83
83
  return newV;
84
84
  });
85
85
  if (typeof globalThis !== "undefined") Reflect.set(globalThis, BOLTDOCS_INSTANCE_SYMBOL, {
86
- ...globalRegistry$1[BOLTDOCS_INSTANCE_SYMBOL],
86
+ ...globalRegistry[BOLTDOCS_INSTANCE_SYMBOL],
87
87
  currentVersion: newV
88
88
  });
89
89
  if (typeof window !== "undefined") try {
@@ -122,41 +122,6 @@ function useBoltdocsContext() {
122
122
  return context;
123
123
  }
124
124
 
125
- //#endregion
126
- //#region src/client/app/config-context.tsx
127
- /**
128
- * Context for the global documentation configuration.
129
- * Using a global singleton pattern to survive dual-package or duplicated-code hazards.
130
- */
131
- const CONFIG_CONTEXT_SYMBOL = Symbol.for("__BDOCS_CONFIG_CONTEXT__");
132
- const CONFIG_INSTANCE_SYMBOL = Symbol.for("__BDOCS_CONFIG_INSTANCE__");
133
- const globalRegistry = globalThis;
134
- const existingConfigContext = globalRegistry[CONFIG_CONTEXT_SYMBOL];
135
- const ConfigContext = existingConfigContext || createContext(null);
136
- if (!existingConfigContext) globalRegistry[CONFIG_CONTEXT_SYMBOL] = ConfigContext;
137
- /**
138
- * Hook to access the Boltdocs configuration when one is available.
139
- *
140
- * Low-level primitives such as icons can also be rendered standalone (for
141
- * example in a component preview or a unit test), so they must not be forced
142
- * to mount the full application provider just to render an inline SVG.
143
- */
144
- function useOptionalConfig() {
145
- const context = use(ConfigContext);
146
- if (context) return context;
147
- const globalConfig = globalRegistry[CONFIG_INSTANCE_SYMBOL];
148
- if (globalConfig) return globalConfig;
149
- return null;
150
- }
151
- /**
152
- * Hook to access the Boltdocs configuration.
153
- */
154
- function useConfig() {
155
- const config = useOptionalConfig();
156
- if (!config) throw new Error("useConfig must be used within a ConfigProvider");
157
- return config;
158
- }
159
-
160
125
  //#endregion
161
126
  //#region src/client/components/ui-base/icons.tsx
162
127
  var icons_exports = /* @__PURE__ */ __exportAll({
@@ -564,6 +529,66 @@ const FaceBad = createIcon("FaceBad", /* @__PURE__ */ jsxs(Fragment$1, { childre
564
529
  })
565
530
  ] }));
566
531
 
532
+ //#endregion
533
+ //#region src/client/router/prefetch-viewport.ts
534
+ /**
535
+ * Viewport-triggered route prefetching.
536
+ *
537
+ * Hover prefetching only warms a link once the pointer commits to it, which
538
+ * misses the most common case: a reader scrolls the sidebar, reads a heading,
539
+ * and clicks without ever hovering. Every destination they are plausibly
540
+ * heading for sits on screen, untouched.
541
+ *
542
+ * A single shared `IntersectionObserver` watches anchors registered by
543
+ * `Link` and fires the normal prefetch pipeline when one becomes visible, so
544
+ * the route chunk and its loader data are already cached by the time the click
545
+ * lands. Hover keeps working and still wins: whichever signal arrives first
546
+ * populates `prefetchCache`, and the other is a cache hit.
547
+ *
548
+ * The existing prefetch queue bounds the cost (two in flight, a shallow
549
+ * backlog) and drops work when saturated, so this stays opportunistic
550
+ * exactly like hover prefetching is.
551
+ */
552
+ /**
553
+ * Start slightly before the link is on screen so a short scroll already feels
554
+ * instant, without warming the whole page below the fold.
555
+ */
556
+ const VIEWPORT_PREFETCH_MARGIN = "200px 0px";
557
+ let observer = null;
558
+ const pending = /* @__PURE__ */ new WeakMap();
559
+ function getObserver() {
560
+ if (typeof window === "undefined") return null;
561
+ if (typeof IntersectionObserver === "undefined") return null;
562
+ if (observer) return observer;
563
+ observer = new IntersectionObserver((entries) => {
564
+ for (const entry of entries) {
565
+ if (!entry.isIntersecting) continue;
566
+ const run = pending.get(entry.target);
567
+ if (!run) continue;
568
+ observer?.unobserve(entry.target);
569
+ pending.delete(entry.target);
570
+ run();
571
+ }
572
+ }, { rootMargin: VIEWPORT_PREFETCH_MARGIN });
573
+ return observer;
574
+ }
575
+ /**
576
+ * Watches `element` and invokes `run` once it approaches the viewport.
577
+ *
578
+ * Returns a cleanup function. Safe to call during SSR, where it is a no-op.
579
+ */
580
+ function observeForPrefetch(element, run) {
581
+ if (!element) return () => {};
582
+ const target = getObserver();
583
+ if (!target) return () => {};
584
+ pending.set(element, run);
585
+ target.observe(element);
586
+ return () => {
587
+ target.unobserve(element);
588
+ pending.delete(element);
589
+ };
590
+ }
591
+
567
592
  //#endregion
568
593
  //#region src/client/utils/path.ts
569
594
  /**
@@ -748,74 +773,6 @@ function cn(...inputs) {
748
773
  return twMerge(clsx(inputs));
749
774
  }
750
775
 
751
- //#endregion
752
- //#region src/client/view-transitions.ts
753
- function resolveOptions(options) {
754
- if (options?.enabled === false) return void 0;
755
- return {
756
- enabled: true,
757
- ...options?.types?.length ? { types: options.types } : {}
758
- };
759
- }
760
- function isNativeViewTransitionSupported() {
761
- return typeof document !== "undefined" && typeof document.startViewTransition === "function";
762
- }
763
- /**
764
- * Starts a native document transition when the browser supports it. On older
765
- * browsers, the update still runs normally and the function returns null.
766
- */
767
- function startViewTransition(update, options) {
768
- const resolved = resolveOptions(options);
769
- if (typeof document === "undefined" || resolved?.enabled !== true) {
770
- update();
771
- return null;
772
- }
773
- const start = document.startViewTransition;
774
- if (!start) {
775
- update();
776
- return null;
777
- }
778
- const types = options?.types;
779
- return start.call(document, {
780
- update,
781
- ...types?.length ? { types } : {}
782
- });
783
- }
784
- /**
785
- * Returns a transition-aware runner that follows the project's experimental
786
- * configuration. It is safe to use in custom layouts and external pages.
787
- *
788
- * The returned value is callable for backwards compatibility:
789
- * `transition(() => setState(...))`. It also exposes `run` and `start` aliases
790
- * for discoverability in editor autocomplete.
791
- */
792
- function useViewTransition() {
793
- const configured = useOptionalConfig()?.experimental?.viewTransitions;
794
- const enabled = configured === true || typeof configured === "object" && configured.enabled === true;
795
- const supported = isNativeViewTransitionSupported();
796
- const run = useCallback((update, options) => {
797
- if (!enabled && options?.enabled !== true) {
798
- update();
799
- return null;
800
- }
801
- const configuredTypes = typeof configured === "object" ? configured.types : void 0;
802
- return startViewTransition(update, {
803
- ...options,
804
- types: options?.types || configuredTypes
805
- });
806
- }, [configured, enabled]);
807
- return useMemo(() => Object.assign(run, {
808
- run,
809
- start: run,
810
- enabled,
811
- supported
812
- }), [
813
- enabled,
814
- run,
815
- supported
816
- ]);
817
- }
818
-
819
776
  //#endregion
820
777
  //#region src/client/components/primitives/link.tsx
821
778
  /**
@@ -843,7 +800,7 @@ function Link(props) {
843
800
  }
844
801
  };
845
802
  const handlePrefetch = () => {
846
- if (prefetch === "hover" && localizedHref) prefetchRoute(localizedHref);
803
+ if (prefetch !== "none" && localizedHref) prefetchRoute(localizedHref);
847
804
  };
848
805
  const handleMouseEnter = (e) => {
849
806
  onMouseEnter?.(e);
@@ -853,9 +810,25 @@ function Link(props) {
853
810
  onFocus?.(e);
854
811
  handlePrefetch();
855
812
  };
813
+ const anchorRef = React.useRef(null);
814
+ const setRef = React.useCallback((node) => {
815
+ anchorRef.current = node;
816
+ if (typeof ref === "function") ref(node);
817
+ else if (ref) ref.current = node;
818
+ }, [ref]);
819
+ React.useEffect(() => {
820
+ if (prefetch !== "viewport" || !localizedHref) return;
821
+ return observeForPrefetch(anchorRef.current, () => {
822
+ prefetchRoute(localizedHref);
823
+ });
824
+ }, [
825
+ prefetch,
826
+ localizedHref,
827
+ prefetchRoute
828
+ ]);
856
829
  return /* @__PURE__ */ jsx("a", {
857
830
  ...rest,
858
- ref,
831
+ ref: setRef,
859
832
  href: localizedHref,
860
833
  target: linkTarget,
861
834
  download,
@@ -894,4 +867,4 @@ function NavLink(props) {
894
867
  }
895
868
 
896
869
  //#endregion
897
- export { Info as A, Sun as B, ExternalLink as C, FileText as D, FaceRegular as E, Monitor as F, useConfig as G, X as H, Moon as I, useBoltdocsContext as J, useOptionalConfig as K, MoreVertical as L, Lightbulb as M, Link$1 as N, Hash as O, Menu as P, Pencil as R, CornerDownLeft as S, FaceGood as T, icons_exports as U, TextAlignStart as V, ConfigContext as W, ChevronDown as _, useViewTransition as a, CircleHelp as b, RoutesProvider as c, normalizePath as d, resolvePublicAssetUrl as f, Check as g, ArrowLeft as h, startViewTransition as i, Languages as j, Home as k, createRouteIndex as l, AlertTriangle as m, NavLink as n, cn as o, AlertCircle as p, BoltdocsProvider as q, TransitionLink as r, useLocalizedTo as s, Link as t, useRoutesContext as u, ChevronLeft as v, FaceBad as w, Copy as x, ChevronRight as y, Search as z };
870
+ export { Lightbulb as A, X as B, FaceGood as C, Home as D, Hash as E, MoreVertical as F, BoltdocsProvider as H, Pencil as I, Search as L, Menu as M, Monitor as N, Info as O, Moon as P, Sun as R, FaceBad as S, FileText as T, useBoltdocsContext as U, icons_exports as V, ChevronRight as _, useLocalizedTo as a, CornerDownLeft as b, useRoutesContext as c, AlertCircle as d, AlertTriangle as f, ChevronLeft as g, ChevronDown as h, cn as i, Link$1 as j, Languages as k, normalizePath as l, Check as m, NavLink as n, RoutesProvider as o, ArrowLeft as p, TransitionLink as r, createRouteIndex as s, Link as t, resolvePublicAssetUrl as u, CircleHelp as v, FaceRegular as w, ExternalLink as x, Copy as y, TextAlignStart as z };
@@ -3,8 +3,9 @@
3
3
  * Copyright (c) 2026 Jesus Alcala
4
4
  * Licensed under the MIT License.
5
5
  */
6
- const require_router = require('./router-C3kygdRK.cjs');
6
+ const require_router = require('./router-DKC0Lu0n.cjs');
7
7
  let react = require("react");
8
+ react = require_router.__toESM(react);
8
9
  let react_jsx_runtime = require("react/jsx-runtime");
9
10
  let clsx = require("clsx");
10
11
  let tailwind_merge = require("tailwind-merge");
@@ -22,10 +23,10 @@ function getSavedPrefs() {
22
23
  return {};
23
24
  }
24
25
  }
25
- const globalRegistry$1 = globalThis;
26
- const existingContext = globalRegistry$1[BOLTDOCS_CONTEXT_SYMBOL];
26
+ const globalRegistry = globalThis;
27
+ const existingContext = globalRegistry[BOLTDOCS_CONTEXT_SYMBOL];
27
28
  const BoltdocsContext = existingContext || (0, react.createContext)(void 0);
28
- if (!existingContext) Reflect.set(globalRegistry$1, BOLTDOCS_CONTEXT_SYMBOL, BoltdocsContext);
29
+ if (!existingContext) Reflect.set(globalRegistry, BOLTDOCS_CONTEXT_SYMBOL, BoltdocsContext);
29
30
  function BoltdocsProvider({ children, initialLocale = "", initialVersion = "" }) {
30
31
  const [locale, setLocaleState] = (0, react.useState)(() => {
31
32
  if (initialLocale) return initialLocale;
@@ -48,7 +49,7 @@ function BoltdocsProvider({ children, initialLocale = "", initialVersion = "" })
48
49
  return newL;
49
50
  });
50
51
  if (typeof globalThis !== "undefined") Reflect.set(globalThis, BOLTDOCS_INSTANCE_SYMBOL, {
51
- ...globalRegistry$1[BOLTDOCS_INSTANCE_SYMBOL],
52
+ ...globalRegistry[BOLTDOCS_INSTANCE_SYMBOL],
52
53
  currentLocale: newL
53
54
  });
54
55
  if (typeof window !== "undefined") try {
@@ -66,7 +67,7 @@ function BoltdocsProvider({ children, initialLocale = "", initialVersion = "" })
66
67
  return newV;
67
68
  });
68
69
  if (typeof globalThis !== "undefined") Reflect.set(globalThis, BOLTDOCS_INSTANCE_SYMBOL, {
69
- ...globalRegistry$1[BOLTDOCS_INSTANCE_SYMBOL],
70
+ ...globalRegistry[BOLTDOCS_INSTANCE_SYMBOL],
70
71
  currentVersion: newV
71
72
  });
72
73
  if (typeof window !== "undefined") try {
@@ -105,41 +106,6 @@ function useBoltdocsContext() {
105
106
  return context;
106
107
  }
107
108
 
108
- //#endregion
109
- //#region src/client/app/config-context.tsx
110
- /**
111
- * Context for the global documentation configuration.
112
- * Using a global singleton pattern to survive dual-package or duplicated-code hazards.
113
- */
114
- const CONFIG_CONTEXT_SYMBOL = Symbol.for("__BDOCS_CONFIG_CONTEXT__");
115
- const CONFIG_INSTANCE_SYMBOL = Symbol.for("__BDOCS_CONFIG_INSTANCE__");
116
- const globalRegistry = globalThis;
117
- const existingConfigContext = globalRegistry[CONFIG_CONTEXT_SYMBOL];
118
- const ConfigContext = existingConfigContext || (0, react.createContext)(null);
119
- if (!existingConfigContext) globalRegistry[CONFIG_CONTEXT_SYMBOL] = ConfigContext;
120
- /**
121
- * Hook to access the Boltdocs configuration when one is available.
122
- *
123
- * Low-level primitives such as icons can also be rendered standalone (for
124
- * example in a component preview or a unit test), so they must not be forced
125
- * to mount the full application provider just to render an inline SVG.
126
- */
127
- function useOptionalConfig() {
128
- const context = (0, react.use)(ConfigContext);
129
- if (context) return context;
130
- const globalConfig = globalRegistry[CONFIG_INSTANCE_SYMBOL];
131
- if (globalConfig) return globalConfig;
132
- return null;
133
- }
134
- /**
135
- * Hook to access the Boltdocs configuration.
136
- */
137
- function useConfig() {
138
- const config = useOptionalConfig();
139
- if (!config) throw new Error("useConfig must be used within a ConfigProvider");
140
- return config;
141
- }
142
-
143
109
  //#endregion
144
110
  //#region src/client/components/ui-base/icons.tsx
145
111
  var icons_exports = /* @__PURE__ */ require_router.__exportAll({
@@ -547,6 +513,66 @@ const FaceBad = createIcon("FaceBad", /* @__PURE__ */ (0, react_jsx_runtime.jsxs
547
513
  })
548
514
  ] }));
549
515
 
516
+ //#endregion
517
+ //#region src/client/router/prefetch-viewport.ts
518
+ /**
519
+ * Viewport-triggered route prefetching.
520
+ *
521
+ * Hover prefetching only warms a link once the pointer commits to it, which
522
+ * misses the most common case: a reader scrolls the sidebar, reads a heading,
523
+ * and clicks without ever hovering. Every destination they are plausibly
524
+ * heading for sits on screen, untouched.
525
+ *
526
+ * A single shared `IntersectionObserver` watches anchors registered by
527
+ * `Link` and fires the normal prefetch pipeline when one becomes visible, so
528
+ * the route chunk and its loader data are already cached by the time the click
529
+ * lands. Hover keeps working and still wins: whichever signal arrives first
530
+ * populates `prefetchCache`, and the other is a cache hit.
531
+ *
532
+ * The existing prefetch queue bounds the cost (two in flight, a shallow
533
+ * backlog) and drops work when saturated, so this stays opportunistic
534
+ * exactly like hover prefetching is.
535
+ */
536
+ /**
537
+ * Start slightly before the link is on screen so a short scroll already feels
538
+ * instant, without warming the whole page below the fold.
539
+ */
540
+ const VIEWPORT_PREFETCH_MARGIN = "200px 0px";
541
+ let observer = null;
542
+ const pending = /* @__PURE__ */ new WeakMap();
543
+ function getObserver() {
544
+ if (typeof window === "undefined") return null;
545
+ if (typeof IntersectionObserver === "undefined") return null;
546
+ if (observer) return observer;
547
+ observer = new IntersectionObserver((entries) => {
548
+ for (const entry of entries) {
549
+ if (!entry.isIntersecting) continue;
550
+ const run = pending.get(entry.target);
551
+ if (!run) continue;
552
+ observer?.unobserve(entry.target);
553
+ pending.delete(entry.target);
554
+ run();
555
+ }
556
+ }, { rootMargin: VIEWPORT_PREFETCH_MARGIN });
557
+ return observer;
558
+ }
559
+ /**
560
+ * Watches `element` and invokes `run` once it approaches the viewport.
561
+ *
562
+ * Returns a cleanup function. Safe to call during SSR, where it is a no-op.
563
+ */
564
+ function observeForPrefetch(element, run) {
565
+ if (!element) return () => {};
566
+ const target = getObserver();
567
+ if (!target) return () => {};
568
+ pending.set(element, run);
569
+ target.observe(element);
570
+ return () => {
571
+ target.unobserve(element);
572
+ pending.delete(element);
573
+ };
574
+ }
575
+
550
576
  //#endregion
551
577
  //#region src/client/utils/path.ts
552
578
  /**
@@ -668,7 +694,7 @@ function RoutesProvider({ routes: initialRoutes, children }) {
668
694
  //#endregion
669
695
  //#region src/client/hooks/use-localized-to.ts
670
696
  function useLocalizedTo(to) {
671
- const config = useConfig();
697
+ const config = require_router.useConfig();
672
698
  const routeContext = useRoutesContext();
673
699
  const routeIndex = routeContext.index || {
674
700
  byPath: new Map(routeContext.routes.map((route) => [route.path, route])),
@@ -731,74 +757,6 @@ function cn(...inputs) {
731
757
  return (0, tailwind_merge.twMerge)((0, clsx.clsx)(inputs));
732
758
  }
733
759
 
734
- //#endregion
735
- //#region src/client/view-transitions.ts
736
- function resolveOptions(options) {
737
- if (options?.enabled === false) return void 0;
738
- return {
739
- enabled: true,
740
- ...options?.types?.length ? { types: options.types } : {}
741
- };
742
- }
743
- function isNativeViewTransitionSupported() {
744
- return typeof document !== "undefined" && typeof document.startViewTransition === "function";
745
- }
746
- /**
747
- * Starts a native document transition when the browser supports it. On older
748
- * browsers, the update still runs normally and the function returns null.
749
- */
750
- function startViewTransition(update, options) {
751
- const resolved = resolveOptions(options);
752
- if (typeof document === "undefined" || resolved?.enabled !== true) {
753
- update();
754
- return null;
755
- }
756
- const start = document.startViewTransition;
757
- if (!start) {
758
- update();
759
- return null;
760
- }
761
- const types = options?.types;
762
- return start.call(document, {
763
- update,
764
- ...types?.length ? { types } : {}
765
- });
766
- }
767
- /**
768
- * Returns a transition-aware runner that follows the project's experimental
769
- * configuration. It is safe to use in custom layouts and external pages.
770
- *
771
- * The returned value is callable for backwards compatibility:
772
- * `transition(() => setState(...))`. It also exposes `run` and `start` aliases
773
- * for discoverability in editor autocomplete.
774
- */
775
- function useViewTransition() {
776
- const configured = useOptionalConfig()?.experimental?.viewTransitions;
777
- const enabled = configured === true || typeof configured === "object" && configured.enabled === true;
778
- const supported = isNativeViewTransitionSupported();
779
- const run = (0, react.useCallback)((update, options) => {
780
- if (!enabled && options?.enabled !== true) {
781
- update();
782
- return null;
783
- }
784
- const configuredTypes = typeof configured === "object" ? configured.types : void 0;
785
- return startViewTransition(update, {
786
- ...options,
787
- types: options?.types || configuredTypes
788
- });
789
- }, [configured, enabled]);
790
- return (0, react.useMemo)(() => Object.assign(run, {
791
- run,
792
- start: run,
793
- enabled,
794
- supported
795
- }), [
796
- enabled,
797
- run,
798
- supported
799
- ]);
800
- }
801
-
802
760
  //#endregion
803
761
  //#region src/client/components/primitives/link.tsx
804
762
  /**
@@ -810,7 +768,7 @@ function Link(props) {
810
768
  const target = href ?? to ?? "";
811
769
  const navigate = require_router.useNavigate();
812
770
  const prefetchRoute = require_router.usePrefetch();
813
- const runTransition = useViewTransition();
771
+ const runTransition = require_router.useViewTransition();
814
772
  const localizedHref = useLocalizedTo(target);
815
773
  const handleClick = (e) => {
816
774
  onClick?.(e);
@@ -826,7 +784,7 @@ function Link(props) {
826
784
  }
827
785
  };
828
786
  const handlePrefetch = () => {
829
- if (prefetch === "hover" && localizedHref) prefetchRoute(localizedHref);
787
+ if (prefetch !== "none" && localizedHref) prefetchRoute(localizedHref);
830
788
  };
831
789
  const handleMouseEnter = (e) => {
832
790
  onMouseEnter?.(e);
@@ -836,9 +794,25 @@ function Link(props) {
836
794
  onFocus?.(e);
837
795
  handlePrefetch();
838
796
  };
797
+ const anchorRef = react.default.useRef(null);
798
+ const setRef = react.default.useCallback((node) => {
799
+ anchorRef.current = node;
800
+ if (typeof ref === "function") ref(node);
801
+ else if (ref) ref.current = node;
802
+ }, [ref]);
803
+ react.default.useEffect(() => {
804
+ if (prefetch !== "viewport" || !localizedHref) return;
805
+ return observeForPrefetch(anchorRef.current, () => {
806
+ prefetchRoute(localizedHref);
807
+ });
808
+ }, [
809
+ prefetch,
810
+ localizedHref,
811
+ prefetchRoute
812
+ ]);
839
813
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
840
814
  ...rest,
841
- ref,
815
+ ref: setRef,
842
816
  href: localizedHref,
843
817
  target: linkTarget,
844
818
  download,
@@ -931,12 +905,6 @@ Object.defineProperty(exports, 'CircleHelp', {
931
905
  return CircleHelp;
932
906
  }
933
907
  });
934
- Object.defineProperty(exports, 'ConfigContext', {
935
- enumerable: true,
936
- get: function () {
937
- return ConfigContext;
938
- }
939
- });
940
908
  Object.defineProperty(exports, 'Copy', {
941
909
  enumerable: true,
942
910
  get: function () {
@@ -1123,45 +1091,21 @@ Object.defineProperty(exports, 'resolvePublicAssetUrl', {
1123
1091
  return resolvePublicAssetUrl;
1124
1092
  }
1125
1093
  });
1126
- Object.defineProperty(exports, 'startViewTransition', {
1127
- enumerable: true,
1128
- get: function () {
1129
- return startViewTransition;
1130
- }
1131
- });
1132
1094
  Object.defineProperty(exports, 'useBoltdocsContext', {
1133
1095
  enumerable: true,
1134
1096
  get: function () {
1135
1097
  return useBoltdocsContext;
1136
1098
  }
1137
1099
  });
1138
- Object.defineProperty(exports, 'useConfig', {
1139
- enumerable: true,
1140
- get: function () {
1141
- return useConfig;
1142
- }
1143
- });
1144
1100
  Object.defineProperty(exports, 'useLocalizedTo', {
1145
1101
  enumerable: true,
1146
1102
  get: function () {
1147
1103
  return useLocalizedTo;
1148
1104
  }
1149
1105
  });
1150
- Object.defineProperty(exports, 'useOptionalConfig', {
1151
- enumerable: true,
1152
- get: function () {
1153
- return useOptionalConfig;
1154
- }
1155
- });
1156
1106
  Object.defineProperty(exports, 'useRoutesContext', {
1157
1107
  enumerable: true,
1158
1108
  get: function () {
1159
1109
  return useRoutesContext;
1160
1110
  }
1161
- });
1162
- Object.defineProperty(exports, 'useViewTransition', {
1163
- enumerable: true,
1164
- get: function () {
1165
- return useViewTransition;
1166
- }
1167
1111
  });