boltdocs 2.7.9 → 2.7.11

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 (174) hide show
  1. package/dist/{cache-DorPMFgW.cjs → cache-Ba-DZQNH.cjs} +1 -1
  2. package/dist/{cache-CQKlT4fI.mjs → cache-BuMZ58L5.mjs} +1 -1
  3. package/dist/chunk-CU-zTemE.cjs +6 -0
  4. package/dist/client/index.cjs +1929 -1
  5. package/dist/client/index.js +1880 -1
  6. package/dist/client/mdx.cjs +7 -1
  7. package/dist/client/mdx.js +7 -1
  8. package/dist/client/primitives.cjs +60 -1
  9. package/dist/client/primitives.js +20 -1
  10. package/dist/docs-layout-BXHV0xw_.cjs +1431 -0
  11. package/dist/docs-layout-DwFndmj5.js +1231 -0
  12. package/dist/doctor-Be7Ly1oM.mjs +21 -0
  13. package/dist/{doctor-D4_Y7M4p.cjs → doctor-CrytFkqW.cjs} +1 -1
  14. package/dist/doctor-jMxWZyLJ.cjs +21 -0
  15. package/dist/generator-CHqxiQhF.cjs +21 -0
  16. package/dist/generator-ClVanhvi.mjs +21 -0
  17. package/dist/icons-dev-3cZMyt8r.cjs +1204 -0
  18. package/dist/icons-dev-Df8OQ481.js +839 -0
  19. package/dist/image-DtrI2cw3.cjs +268 -0
  20. package/dist/image-jxPb-2iV.js +214 -0
  21. package/dist/mdx-BdWkJTeB.cjs +523 -0
  22. package/dist/mdx-UTTLFWJq.js +494 -0
  23. package/dist/meta-loader-CWg2gnbY.mjs +6 -0
  24. package/dist/meta-loader-Cv9O0Pzl.cjs +6 -0
  25. package/dist/node/cli-entry.cjs +1 -1
  26. package/dist/node/cli-entry.mjs +1 -1
  27. package/dist/node/index.cjs +1 -1
  28. package/dist/node/index.mjs +1 -1
  29. package/dist/node/routes/worker.cjs +1 -1
  30. package/dist/node/routes/worker.mjs +1 -1
  31. package/dist/node-BSM4qcDK.cjs +111 -0
  32. package/dist/node-BspZN3R2.mjs +111 -0
  33. package/dist/{package-VfQM94VL.cjs → package-DIIrjuWI.cjs} +1 -1
  34. package/dist/{package-B4MD00N3.mjs → package-K0zsjGIz.mjs} +1 -1
  35. package/dist/{parser-Bh11BsdA.cjs → parser-Aq8LoH-0.cjs} +1 -1
  36. package/dist/{parser-DYRzXWmA.cjs → parser-CdNbqN5y.cjs} +1 -1
  37. package/dist/parser-nE792MLO.mjs +6 -0
  38. package/dist/rolldown-runtime-fkIsjY3S.mjs +6 -0
  39. package/dist/{routes-Co1mRM58.cjs → routes-2k3tbUmC.cjs} +1 -1
  40. package/dist/routes-CpxZIsMM.mjs +6 -0
  41. package/dist/{routes-CHf76Ye4.cjs → routes-DP1vmWRj.cjs} +1 -1
  42. package/dist/search-dialog-BHuIiUC6.js +8 -0
  43. package/dist/search-dialog-BNF10tDl.js +375 -0
  44. package/dist/search-dialog-BwkDuI9R.cjs +220 -0
  45. package/dist/search-dialog-C7xuvyNk.cjs +386 -0
  46. package/dist/search-dialog-CIQg6k8c.cjs +8 -0
  47. package/dist/search-dialog-D-DDN7zJ.js +208 -0
  48. package/dist/utils-CG65J0Sc.mjs +7 -0
  49. package/dist/utils-CKunkU96.cjs +7 -0
  50. package/dist/{worker-pool-BwU8ckrg.cjs → worker-pool-Crbqgw5R.cjs} +1 -1
  51. package/package.json +5 -5
  52. package/dist/chunk-Ds5LZdWN.cjs +0 -6
  53. package/dist/docs-layout-KoWNZc8_.js +0 -6
  54. package/dist/docs-layout-x2yKt2cL.cjs +0 -6
  55. package/dist/doctor-BD1BSB03.mjs +0 -23
  56. package/dist/doctor-BHc9ua6r.cjs +0 -23
  57. package/dist/generator-DGW6pkCC.cjs +0 -22
  58. package/dist/generator-Dv3wEmhZ.mjs +0 -22
  59. package/dist/icons-dev-B_RZIyxu.js +0 -6
  60. package/dist/icons-dev-BlV3wWFT.cjs +0 -6
  61. package/dist/image-BHhTvQzr.cjs +0 -6
  62. package/dist/image-CqKzYD8f.js +0 -6
  63. package/dist/mdx-DudBEac0.js +0 -7
  64. package/dist/mdx-r4cDQxWu.cjs +0 -7
  65. package/dist/meta-loader-0gJ4PtBC.cjs +0 -6
  66. package/dist/meta-loader-9IpAHWDS.mjs +0 -6
  67. package/dist/node-DBaH7kat.mjs +0 -111
  68. package/dist/node-t5C3Q85p.cjs +0 -111
  69. package/dist/parser-9cVdK7w9.mjs +0 -6
  70. package/dist/routes-DwrMa5-z.mjs +0 -6
  71. package/dist/search-dialog-B584t9ZF.js +0 -6
  72. package/dist/search-dialog-BvBopRsZ.cjs +0 -6
  73. package/dist/search-dialog-ByvGScjt.js +0 -6
  74. package/dist/search-dialog-Cyko6TJm.cjs +0 -6
  75. package/dist/search-dialog-D6BNohIJ.js +0 -6
  76. package/dist/search-dialog-DuYTIefy.cjs +0 -6
  77. package/dist/utils-BxNAXhZZ.mjs +0 -7
  78. package/dist/utils-Clzu7jvb.cjs +0 -7
  79. package/src/client/app/config-context.tsx +0 -51
  80. package/src/client/app/doc-page.tsx +0 -38
  81. package/src/client/app/docs-layout.tsx +0 -28
  82. package/src/client/app/head.tsx +0 -122
  83. package/src/client/app/helmet-compat.tsx +0 -36
  84. package/src/client/app/mdx-component.tsx +0 -8
  85. package/src/client/app/mdx-components-context.tsx +0 -72
  86. package/src/client/app/routes-context.tsx +0 -34
  87. package/src/client/app/scroll-handler.tsx +0 -74
  88. package/src/client/app/theme-context.tsx +0 -103
  89. package/src/client/app/ui-context.tsx +0 -42
  90. package/src/client/components/docs-layout-default.tsx +0 -85
  91. package/src/client/components/icons-dev.tsx +0 -282
  92. package/src/client/components/mdx/callout.tsx +0 -97
  93. package/src/client/components/mdx/card.tsx +0 -99
  94. package/src/client/components/mdx/cards.tsx +0 -27
  95. package/src/client/components/mdx/code-block.tsx +0 -184
  96. package/src/client/components/mdx/field.tsx +0 -33
  97. package/src/client/components/mdx/image.tsx +0 -44
  98. package/src/client/components/mdx/index.ts +0 -19
  99. package/src/client/components/mdx/table.tsx +0 -54
  100. package/src/client/components/mdx/typographics.tsx +0 -120
  101. package/src/client/components/mdx/use-code-block.ts +0 -34
  102. package/src/client/components/primitives/breadcrumbs.tsx +0 -54
  103. package/src/client/components/primitives/button-group.tsx +0 -54
  104. package/src/client/components/primitives/button.tsx +0 -6
  105. package/src/client/components/primitives/code-block.tsx +0 -120
  106. package/src/client/components/primitives/docs-layout.tsx +0 -125
  107. package/src/client/components/primitives/error-boundary.tsx +0 -107
  108. package/src/client/components/primitives/heading.tsx +0 -128
  109. package/src/client/components/primitives/helpers/observer.ts +0 -141
  110. package/src/client/components/primitives/image.tsx +0 -26
  111. package/src/client/components/primitives/link.tsx +0 -102
  112. package/src/client/components/primitives/menu.tsx +0 -137
  113. package/src/client/components/primitives/navbar.tsx +0 -466
  114. package/src/client/components/primitives/on-this-page.tsx +0 -430
  115. package/src/client/components/primitives/page-nav.tsx +0 -51
  116. package/src/client/components/primitives/popover.tsx +0 -28
  117. package/src/client/components/primitives/search-dialog.tsx +0 -193
  118. package/src/client/components/primitives/sidebar.tsx +0 -423
  119. package/src/client/components/primitives/skeleton.tsx +0 -26
  120. package/src/client/components/primitives/tabs.tsx +0 -70
  121. package/src/client/components/primitives/tooltip.tsx +0 -81
  122. package/src/client/components/primitives/types.ts +0 -11
  123. package/src/client/components/ui-base/banner.tsx +0 -66
  124. package/src/client/components/ui-base/breadcrumbs.tsx +0 -44
  125. package/src/client/components/ui-base/copy-markdown.tsx +0 -107
  126. package/src/client/components/ui-base/error-boundary.tsx +0 -15
  127. package/src/client/components/ui-base/github-stars.tsx +0 -29
  128. package/src/client/components/ui-base/icons.tsx +0 -240
  129. package/src/client/components/ui-base/index.ts +0 -16
  130. package/src/client/components/ui-base/last-updated.tsx +0 -27
  131. package/src/client/components/ui-base/navbar.tsx +0 -266
  132. package/src/client/components/ui-base/not-found.tsx +0 -26
  133. package/src/client/components/ui-base/on-this-page.tsx +0 -57
  134. package/src/client/components/ui-base/page-nav.tsx +0 -50
  135. package/src/client/components/ui-base/search-dialog.tsx +0 -163
  136. package/src/client/components/ui-base/search-highlight.tsx +0 -10
  137. package/src/client/components/ui-base/sidebar.tsx +0 -92
  138. package/src/client/components/ui-base/tabs.tsx +0 -83
  139. package/src/client/components/ui-base/theme-toggle.tsx +0 -130
  140. package/src/client/components/ui-base/version-i18n.tsx +0 -80
  141. package/src/client/hooks/index.ts +0 -13
  142. package/src/client/hooks/use-analytics.ts +0 -272
  143. package/src/client/hooks/use-breadcrumbs.ts +0 -22
  144. package/src/client/hooks/use-i18n.ts +0 -182
  145. package/src/client/hooks/use-localized-to.ts +0 -113
  146. package/src/client/hooks/use-location.ts +0 -5
  147. package/src/client/hooks/use-navbar.ts +0 -130
  148. package/src/client/hooks/use-page-nav.ts +0 -46
  149. package/src/client/hooks/use-routes.ts +0 -108
  150. package/src/client/hooks/use-search-highlight.ts +0 -185
  151. package/src/client/hooks/use-search.ts +0 -118
  152. package/src/client/hooks/use-sidebar.ts +0 -205
  153. package/src/client/hooks/use-tabs.ts +0 -46
  154. package/src/client/hooks/use-version.ts +0 -111
  155. package/src/client/index.ts +0 -31
  156. package/src/client/mdx.ts +0 -2
  157. package/src/client/primitives.ts +0 -19
  158. package/src/client/ssg/boltdocs-shell.tsx +0 -148
  159. package/src/client/ssg/create-routes.tsx +0 -473
  160. package/src/client/ssg/index.ts +0 -4
  161. package/src/client/ssg/mdx-page.tsx +0 -38
  162. package/src/client/store/boltdocs-context.tsx +0 -137
  163. package/src/client/theme/neutral.css +0 -141
  164. package/src/client/theme/reset.css +0 -189
  165. package/src/client/types.ts +0 -116
  166. package/src/client/utils/cn.ts +0 -6
  167. package/src/client/utils/copy-clipboard.ts +0 -22
  168. package/src/client/utils/get-base-file-path.ts +0 -21
  169. package/src/client/utils/github.ts +0 -121
  170. package/src/client/utils/i18n.ts +0 -23
  171. package/src/client/utils/path.ts +0 -9
  172. package/src/client/utils/react-to-text.ts +0 -34
  173. package/src/client/virtual.d.ts +0 -24
  174. /package/dist/{worker-pool-Bd8Y9KDv.mjs → worker-pool-CGn7DrLb.mjs} +0 -0
@@ -1,7 +0,0 @@
1
- /**
2
- * Boltdocs - https://boltdocs.vercel.app
3
- * Copyright (c) 2026 Jesus Alcala
4
- * Licensed under the MIT License.
5
- */
6
- import e from"fs";import t from"isomorphic-dompurify";import{z as n}from"zod";const r=/^[a-zA-Z0-9\-_/.()]+$/,i=n.looseObject({title:n.string().max(200).optional(),description:n.string().max(500).optional(),permalink:n.string().optional(),sidebarPosition:n.number().optional(),sidebarLabel:n.string().max(100).optional(),sidebarHidden:n.boolean().optional(),hidden:n.boolean().optional(),category:n.string().max(50).optional(),order:n.number().optional(),badge:n.union([n.string().max(50),n.object({text:n.string().max(50),expires:n.string().optional()})]).optional(),icon:n.string().max(50).optional(),date:n.union([n.string(),n.date()]).optional(),lastUpdated:n.union([n.string(),n.date()]).optional(),groupTitle:n.string().max(100).optional(),groupPosition:n.number().optional(),seo:n.record(n.any()).optional()});function a(e){let t=e.trim();if(!t.startsWith(`---`))return{data:{},content:e,rawMatter:``};let n=t.indexOf(`---`,3);if(n===-1||n===3)return{data:{},content:e,rawMatter:``};let r=t.slice(3,n).trim(),i=t.slice(n+3).trim();return o(r)?{data:{},content:i,rawMatter:r}:{data:s(r),content:i,rawMatter:r}}function o(e){let t=!1,n=!1;for(let r=0;r<e.length;r++){let i=e[r],a=r>0?e[r-1]:``;i===`'`&&!n&&a!==`\\`?t=!t:i===`"`&&!t&&a!==`\\`&&(n=!n)}return t||n}function s(e){let t=e.split(`
7
- `),n={},r=0;for(;r<t.length;){let e=t[r],i=e.trim();if(!i||i.startsWith(`#`)){r++;continue}let a=i.indexOf(`:`);if(a!==-1){let o=i.slice(0,a).trim(),s=i.slice(a+1).trim();if(s===``){let i=c(t.slice(r+1),e.search(/\S|$/));i.value===void 0?r++:(n[o]=i.value,r+=i.linesConsumed)}else n[o]=l(s),r++}else r++}return n}function c(e,t){if(e.length===0)return{value:void 0,linesConsumed:0};if(e[0].trim().startsWith(`-`)){let n=[],r=0;for(;r<e.length;){let i=e[r],a=i.search(/\S|$/),o=i.trim();if(!o||o.startsWith(`#`)){r++;continue}if(o.startsWith(`-`)){let e=o.slice(1).trim();if(e.includes(`:`)){let t={},r=e.split(/,\s*/);for(let e of r){let n=e.indexOf(`:`);if(n!==-1){let r=e.slice(0,n).trim();t[r]=l(e.slice(n+1).trim())}}n.push(t)}else n.push(e)}else if(a>t&&n.length>0){let e=n[n.length-1];if(typeof e==`object`&&e){let t=e,n=o.indexOf(`:`);if(n!==-1){let e=o.slice(0,n).trim();t[e]=l(o.slice(n+1).trim())}}}else break;r++}return{value:n.length>0?n:void 0,linesConsumed:r}}let n={},r=0;for(;r<e.length;){let i=e[r],a=i.search(/\S|$/),o=i.trim();if(!o||o.startsWith(`#`)){r++;continue}if(a<=t)break;let s=o.indexOf(`:`);if(s!==-1){let e=o.slice(0,s).trim();n[e]=l(o.slice(s+1).trim())}r++}return{value:Object.keys(n).length>0?n:void 0,linesConsumed:r}}function l(e){let t=e.trim();if(t===`true`)return!0;if(t===`false`)return!1;if(t===`null`||t===`~`)return null;if(/^-?\d+(\.\d+)?$/.test(t))return Number(t);if(t.startsWith(`"`)&&t.endsWith(`"`)||t.startsWith(`'`)&&t.endsWith(`'`))return t.slice(1,-1);if(t.startsWith(`{`)&&t.endsWith(`}`)){let e=t.slice(1,-1).trim(),n={},r=e.split(/,\s*/);for(let e of r){let t=e.indexOf(`:`);if(t!==-1){let r=e.slice(0,t).trim();n[r]=l(e.slice(t+1).trim())}}return n}return t}var u=class e extends Error{constructor(t){super(t),this.name=`SecurityViolationError`,Object.setPrototypeOf(this,e.prototype)}},d=class e extends u{constructor(t){super(t),this.name=`PathTraversalError`,Object.setPrototypeOf(this,e.prototype)}},f=class e extends u{constructor(t){super(t),this.name=`EncodingSecurityError`,Object.setPrototypeOf(this,e.prototype)}},p=class e extends u{constructor(t){super(t),this.name=`ValidationError`,Object.setPrototypeOf(this,e.prototype)}};function m(e){return e.replace(/\\/g,`/`)}function h(e){return e.replace(/^\d+\./,``)}function g(e){let t=e.match(/^(\d+)\./);return t?parseInt(t[1],10):void 0}function _(e){return/\.mdx?$/.test(e)}function v(t){try{return e.statSync(t).mtimeMs}catch{return 0}}async function y(t,n=!0){let r=``;try{r=await e.promises.readFile(t,`utf-8`);let{data:o,content:s,rawMatter:c}=a(r);if(c&&c.length>10240)throw D(`FRONTMATTER_TOO_LARGE`,`Frontmatter block exceeds size limit`,{size:c.length,file:t}),new p(`Security breach: Frontmatter size exceeds limit of 10240 bytes`);if(!n)return{data:o,content:s,raw:r};let l=i.safeParse(o),u={...l.success?l.data:{}};return u.lastUpdated||=(await e.promises.stat(t)).mtimeMs,u.title&&=w(u.title).trim(),u.description&&=w(u.description).trim(),{data:u,content:s,raw:r}}catch(e){if(e instanceof p)throw e;return{data:{},content:r,raw:r}}}function b(e){return e.replace(/&/g,`&amp;`).replace(/"/g,`&quot;`).replace(/'/g,`&apos;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}function x(e){return b(e)}function S(e){let t=m(e).split(`/`).map(e=>E(h(e))).join(`/`).replace(/\/$/,``);return t=t.replace(/\.mdx?$/,``),(t===`index`||t.endsWith(`/index`))&&(t=t.replace(/index$/,``)),t.startsWith(`/`)||(t=`/`+t),t.length>1&&t.endsWith(`/`)&&(t=t.slice(0,-1)),t}function C(e){return t.sanitize(e,{ALLOWED_TAGS:`b.i.em.strong.a.p.br.code.pre.span.div.h1.h2.h3.h4.h5.h6.ul.ol.li.table.thead.tbody.tr.th.td.blockquote.hr`.split(`.`),ALLOWED_ATTR:[`href`,`title`,`target`,`class`,`id`,`src`,`alt`,`width`,`height`],FORCE_BODY:!0})}t.addHook(`afterSanitizeAttributes`,e=>{if(e.hasAttribute(`href`)){let t=e.getAttribute(`href`)?.toLowerCase()||``;(t.startsWith(`javascript:`)||t.startsWith(`data:`)||t.startsWith(`vbscript:`))&&e.removeAttribute(`href`)}if(e.hasAttribute(`src`)){let t=e.getAttribute(`src`)?.toLowerCase()||``;(t.startsWith(`javascript:`)||t.startsWith(`data:`)||t.startsWith(`vbscript:`))&&e.removeAttribute(`src`)}});function w(e){return e?e.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,``).replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi,``).replace(/<!--[\s\S]*?-->/g,``).replace(/<[^>]+>/g,` `).replace(/\s+/g,` `).trim():``}function T(e){return e.charAt(0).toUpperCase()+e.slice(1)}function E(e){return e.replace(/[^a-zA-Z0-9\-_/.]/g,``).split(`/`).filter(e=>e!==`..`&&e!==`.`).map(e=>e.replace(/\.\.+/g,`.`)).join(`/`)}function D(e,t,n={}){let r=new Date().toISOString(),i={...n};for(let e in i)typeof i[e]==`string`&&i[e].includes(`:`)&&(i[e]=i[e].split(/[\\/]/).pop()||i[e]);console.error(`[SECURITY][${r}] TYPE: ${e} | MESSAGE: ${t} | DETAILS: ${JSON.stringify(i)}`)}function O(){return{dir:process.env.BOLTDOCS_CACHE_DIR||`.boltdocs`,noCache:process.env.BOLTDOCS_NO_CACHE===`1`,lruLimit:parseInt(process.env.BOLTDOCS_CACHE_LRU_LIMIT||`2000`,10),lruTTL:parseInt(process.env.BOLTDOCS_CACHE_LRU_TTL||`14400000`,10),compress:process.env.BOLTDOCS_CACHE_COMPRESS!==`0`}}export{p as _,O as a,D as c,E as d,C as f,d as g,f as h,S as i,m as l,h as m,x as n,v as o,w as p,g as r,_ as s,T as t,y as u,i as v,r as y};
@@ -1,7 +0,0 @@
1
- /**
2
- * Boltdocs - https://boltdocs.vercel.app
3
- * Copyright (c) 2026 Jesus Alcala
4
- * Licensed under the MIT License.
5
- */
6
- const e=require(`./chunk-Ds5LZdWN.cjs`);let t=require(`fs`);t=e.n(t);let n=require(`isomorphic-dompurify`);n=e.n(n);let r=require(`zod`);const i=/^[a-zA-Z0-9\-_/.()]+$/,a=r.z.looseObject({title:r.z.string().max(200).optional(),description:r.z.string().max(500).optional(),permalink:r.z.string().optional(),sidebarPosition:r.z.number().optional(),sidebarLabel:r.z.string().max(100).optional(),sidebarHidden:r.z.boolean().optional(),hidden:r.z.boolean().optional(),category:r.z.string().max(50).optional(),order:r.z.number().optional(),badge:r.z.union([r.z.string().max(50),r.z.object({text:r.z.string().max(50),expires:r.z.string().optional()})]).optional(),icon:r.z.string().max(50).optional(),date:r.z.union([r.z.string(),r.z.date()]).optional(),lastUpdated:r.z.union([r.z.string(),r.z.date()]).optional(),groupTitle:r.z.string().max(100).optional(),groupPosition:r.z.number().optional(),seo:r.z.record(r.z.any()).optional()});function o(e){let t=e.trim();if(!t.startsWith(`---`))return{data:{},content:e,rawMatter:``};let n=t.indexOf(`---`,3);if(n===-1||n===3)return{data:{},content:e,rawMatter:``};let r=t.slice(3,n).trim(),i=t.slice(n+3).trim();return s(r)?{data:{},content:i,rawMatter:r}:{data:c(r),content:i,rawMatter:r}}function s(e){let t=!1,n=!1;for(let r=0;r<e.length;r++){let i=e[r],a=r>0?e[r-1]:``;i===`'`&&!n&&a!==`\\`?t=!t:i===`"`&&!t&&a!==`\\`&&(n=!n)}return t||n}function c(e){let t=e.split(`
7
- `),n={},r=0;for(;r<t.length;){let e=t[r],i=e.trim();if(!i||i.startsWith(`#`)){r++;continue}let a=i.indexOf(`:`);if(a!==-1){let o=i.slice(0,a).trim(),s=i.slice(a+1).trim();if(s===``){let i=l(t.slice(r+1),e.search(/\S|$/));i.value===void 0?r++:(n[o]=i.value,r+=i.linesConsumed)}else n[o]=u(s),r++}else r++}return n}function l(e,t){if(e.length===0)return{value:void 0,linesConsumed:0};if(e[0].trim().startsWith(`-`)){let n=[],r=0;for(;r<e.length;){let i=e[r],a=i.search(/\S|$/),o=i.trim();if(!o||o.startsWith(`#`)){r++;continue}if(o.startsWith(`-`)){let e=o.slice(1).trim();if(e.includes(`:`)){let t={},r=e.split(/,\s*/);for(let e of r){let n=e.indexOf(`:`);if(n!==-1){let r=e.slice(0,n).trim();t[r]=u(e.slice(n+1).trim())}}n.push(t)}else n.push(e)}else if(a>t&&n.length>0){let e=n[n.length-1];if(typeof e==`object`&&e){let t=e,n=o.indexOf(`:`);if(n!==-1){let e=o.slice(0,n).trim();t[e]=u(o.slice(n+1).trim())}}}else break;r++}return{value:n.length>0?n:void 0,linesConsumed:r}}let n={},r=0;for(;r<e.length;){let i=e[r],a=i.search(/\S|$/),o=i.trim();if(!o||o.startsWith(`#`)){r++;continue}if(a<=t)break;let s=o.indexOf(`:`);if(s!==-1){let e=o.slice(0,s).trim();n[e]=u(o.slice(s+1).trim())}r++}return{value:Object.keys(n).length>0?n:void 0,linesConsumed:r}}function u(e){let t=e.trim();if(t===`true`)return!0;if(t===`false`)return!1;if(t===`null`||t===`~`)return null;if(/^-?\d+(\.\d+)?$/.test(t))return Number(t);if(t.startsWith(`"`)&&t.endsWith(`"`)||t.startsWith(`'`)&&t.endsWith(`'`))return t.slice(1,-1);if(t.startsWith(`{`)&&t.endsWith(`}`)){let e=t.slice(1,-1).trim(),n={},r=e.split(/,\s*/);for(let e of r){let t=e.indexOf(`:`);if(t!==-1){let r=e.slice(0,t).trim();n[r]=u(e.slice(t+1).trim())}}return n}return t}var d=class e extends Error{constructor(t){super(t),this.name=`SecurityViolationError`,Object.setPrototypeOf(this,e.prototype)}},f=class e extends d{constructor(t){super(t),this.name=`PathTraversalError`,Object.setPrototypeOf(this,e.prototype)}},p=class e extends d{constructor(t){super(t),this.name=`EncodingSecurityError`,Object.setPrototypeOf(this,e.prototype)}},m=class e extends d{constructor(t){super(t),this.name=`ValidationError`,Object.setPrototypeOf(this,e.prototype)}};function h(e){return e.replace(/\\/g,`/`)}function g(e){return e.replace(/^\d+\./,``)}function _(e){let t=e.match(/^(\d+)\./);return t?parseInt(t[1],10):void 0}function v(e){return/\.mdx?$/.test(e)}function y(e){try{return t.default.statSync(e).mtimeMs}catch{return 0}}async function b(e,n=!0){let r=``;try{r=await t.default.promises.readFile(e,`utf-8`);let{data:i,content:s,rawMatter:c}=o(r);if(c&&c.length>10240)throw O(`FRONTMATTER_TOO_LARGE`,`Frontmatter block exceeds size limit`,{size:c.length,file:e}),new m(`Security breach: Frontmatter size exceeds limit of 10240 bytes`);if(!n)return{data:i,content:s,raw:r};let l=a.safeParse(i),u={...l.success?l.data:{}};return u.lastUpdated||=(await t.default.promises.stat(e)).mtimeMs,u.title&&=T(u.title).trim(),u.description&&=T(u.description).trim(),{data:u,content:s,raw:r}}catch(e){if(e instanceof m)throw e;return{data:{},content:r,raw:r}}}function x(e){return e.replace(/&/g,`&amp;`).replace(/"/g,`&quot;`).replace(/'/g,`&apos;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}function S(e){return x(e)}function C(e){let t=h(e).split(`/`).map(e=>D(g(e))).join(`/`).replace(/\/$/,``);return t=t.replace(/\.mdx?$/,``),(t===`index`||t.endsWith(`/index`))&&(t=t.replace(/index$/,``)),t.startsWith(`/`)||(t=`/`+t),t.length>1&&t.endsWith(`/`)&&(t=t.slice(0,-1)),t}function w(e){return n.default.sanitize(e,{ALLOWED_TAGS:`b.i.em.strong.a.p.br.code.pre.span.div.h1.h2.h3.h4.h5.h6.ul.ol.li.table.thead.tbody.tr.th.td.blockquote.hr`.split(`.`),ALLOWED_ATTR:[`href`,`title`,`target`,`class`,`id`,`src`,`alt`,`width`,`height`],FORCE_BODY:!0})}n.default.addHook(`afterSanitizeAttributes`,e=>{if(e.hasAttribute(`href`)){let t=e.getAttribute(`href`)?.toLowerCase()||``;(t.startsWith(`javascript:`)||t.startsWith(`data:`)||t.startsWith(`vbscript:`))&&e.removeAttribute(`href`)}if(e.hasAttribute(`src`)){let t=e.getAttribute(`src`)?.toLowerCase()||``;(t.startsWith(`javascript:`)||t.startsWith(`data:`)||t.startsWith(`vbscript:`))&&e.removeAttribute(`src`)}});function T(e){return e?e.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,``).replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi,``).replace(/<!--[\s\S]*?-->/g,``).replace(/<[^>]+>/g,` `).replace(/\s+/g,` `).trim():``}function E(e){return e.charAt(0).toUpperCase()+e.slice(1)}function D(e){return e.replace(/[^a-zA-Z0-9\-_/.]/g,``).split(`/`).filter(e=>e!==`..`&&e!==`.`).map(e=>e.replace(/\.\.+/g,`.`)).join(`/`)}function O(e,t,n={}){let r=new Date().toISOString(),i={...n};for(let e in i)typeof i[e]==`string`&&i[e].includes(`:`)&&(i[e]=i[e].split(/[\\/]/).pop()||i[e]);console.error(`[SECURITY][${r}] TYPE: ${e} | MESSAGE: ${t} | DETAILS: ${JSON.stringify(i)}`)}function k(){return{dir:process.env.BOLTDOCS_CACHE_DIR||`.boltdocs`,noCache:process.env.BOLTDOCS_NO_CACHE===`1`,lruLimit:parseInt(process.env.BOLTDOCS_CACHE_LRU_LIMIT||`2000`,10),lruTTL:parseInt(process.env.BOLTDOCS_CACHE_LRU_TTL||`14400000`,10),compress:process.env.BOLTDOCS_CACHE_COMPRESS!==`0`}}Object.defineProperty(exports,`_`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`v`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`y`,{enumerable:!0,get:function(){return i}});
@@ -1,51 +0,0 @@
1
- import { createContext, use } from 'react'
2
- import type { BoltdocsConfig } from '../../shared/types'
3
-
4
- /**
5
- * Context for the global documentation configuration.
6
- * Using a global singleton pattern to survive dual-package or duplicated-code hazards.
7
- */
8
- const CONFIG_CONTEXT_SYMBOL = Symbol.for('__BDOCS_CONFIG_CONTEXT__')
9
- const CONFIG_INSTANCE_SYMBOL = Symbol.for('__BDOCS_CONFIG_INSTANCE__')
10
-
11
- export const ConfigContext =
12
- (globalThis as any)[CONFIG_CONTEXT_SYMBOL] ||
13
- ((globalThis as any)[CONFIG_CONTEXT_SYMBOL] =
14
- createContext<BoltdocsConfig | null>(null))
15
-
16
- export function ConfigProvider({
17
- config,
18
- children,
19
- }: {
20
- config: BoltdocsConfig
21
- children: React.ReactNode
22
- }) {
23
- // Sync with global registry for dual-package fallback
24
- if (typeof globalThis !== 'undefined') {
25
- ;(globalThis as any)[CONFIG_INSTANCE_SYMBOL] = config
26
- }
27
-
28
- return (
29
- <ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>
30
- )
31
- }
32
-
33
- /**
34
- * Hook to access the Boltdocs configuration.
35
- */
36
- export function useConfig() {
37
- const context = use(ConfigContext)
38
-
39
- // Fallback to global registry if context is missing (dual-package hazard safety net)
40
- if (
41
- !context &&
42
- typeof globalThis !== 'undefined' &&
43
- (globalThis as any)[CONFIG_INSTANCE_SYMBOL]
44
- ) {
45
- return (globalThis as any)[CONFIG_INSTANCE_SYMBOL] as BoltdocsConfig
46
- }
47
-
48
- if (!context)
49
- throw new Error('useConfig must be used within a ConfigProvider')
50
- return context as BoltdocsConfig
51
- }
@@ -1,38 +0,0 @@
1
- import { useMdxComponents } from './mdx-components-context'
2
- import { useMemo } from 'react'
3
- import { LastUpdated as DefaultLastUpdated } from '../components/ui-base'
4
-
5
- /**
6
- * DocPage renders the MDX content and page-specific metadata.
7
- * It is rendered inside the Outlet of DocsLayout.
8
- */
9
- export function DocPage({
10
- route,
11
- content: Content,
12
- mdxComponents: propComponents,
13
- }: any) {
14
- // Access global MDX components (defaults + plugins + virtuals) from context
15
- const contextComponents = useMdxComponents()
16
-
17
- // Merge components: Prop components (from loader) take priority,
18
- // then context components (globals).
19
- const allComponents = useMemo(
20
- () => ({
21
- LastUpdated: DefaultLastUpdated,
22
- ...contextComponents,
23
- ...propComponents,
24
- }),
25
- [contextComponents, propComponents],
26
- )
27
-
28
- const LastUpdated = allComponents.LastUpdated || DefaultLastUpdated
29
-
30
- if (!Content) return null
31
-
32
- return (
33
- <>
34
- <Content components={allComponents} />
35
- {route?.lastUpdated && <LastUpdated date={route.lastUpdated} />}
36
- </>
37
- )
38
- }
@@ -1,28 +0,0 @@
1
- import { Outlet } from 'react-router-dom'
2
- import UserLayout from 'virtual:boltdocs-layout'
3
- import { useRoutes } from '../hooks/use-routes'
4
- import { useConfig } from './config-context'
5
- import { Head } from './head'
6
-
7
- /**
8
- * Wraps the docs Outlet with the user's (or default) layout component.
9
- * The Layout receives the routed page as `children`.
10
- * We use useRoutes to pass the current route context to the persistent layout.
11
- */
12
- export function DocsLayout() {
13
- const config = useConfig()
14
- const { currentRoute, allRoutes } = useRoutes()
15
-
16
- return (
17
- <>
18
- <Head
19
- siteTitle={config.theme?.title}
20
- siteDescription={config.theme?.description}
21
- routes={allRoutes || []}
22
- />
23
- <UserLayout route={currentRoute}>
24
- <Outlet />
25
- </UserLayout>
26
- </>
27
- )
28
- }
@@ -1,122 +0,0 @@
1
- import { useMemo } from 'react'
2
- import { useLocation } from 'react-router-dom'
3
- import { Helmet } from './helmet-compat'
4
- import { useConfig } from './config-context'
5
- import { getTranslated } from '../utils/i18n'
6
- import { useRoutes } from '../hooks/use-routes'
7
-
8
- interface HeadProps {
9
- siteTitle?: string | Record<string, string>
10
- siteDescription?: string | Record<string, string>
11
- routes: Array<{
12
- path: string
13
- title: string
14
- description?: string
15
- seo?: Record<string, unknown>
16
- }>
17
- }
18
-
19
- export function Head({ siteTitle, siteDescription, routes }: HeadProps) {
20
- const location = useLocation()
21
- const config = useConfig()
22
- const { currentLocale } = useRoutes()
23
-
24
- // Find the current route's metadata — memoized so the O(n) search only
25
- // re-runs when the routes array or the current URL changes, not on every render.
26
- const currentRoute = useMemo(
27
- () => routes?.find?.((r) => r.path === location.pathname),
28
- [routes, location.pathname],
29
- )
30
- const pageTitle = currentRoute?.title
31
- const translatedSiteDescription = getTranslated(
32
- siteDescription,
33
- currentLocale,
34
- )
35
- const pageDescription =
36
- currentRoute?.description || translatedSiteDescription || ''
37
-
38
- const translatedSiteTitle = getTranslated(siteTitle, currentLocale)
39
- const finalTitle = pageTitle
40
- ? `${pageTitle} | ${translatedSiteTitle}`
41
- : translatedSiteTitle
42
-
43
- const seo = currentRoute?.seo || {}
44
-
45
- // Merge custom global metatags
46
- const globalMetatags = config?.seo?.metatags || {}
47
-
48
- // Calculate specific ones
49
- const defaultOgImage = config?.seo?.thumbnails?.background
50
- const ogImage = (seo['og:image'] || defaultOgImage) as string | undefined
51
-
52
- return (
53
- <Helmet>
54
- <title>{finalTitle}</title>
55
- <meta name="description" content={pageDescription} />
56
-
57
- {/* Default OG Tags */}
58
- <meta property="og:title" content={finalTitle} />
59
- <meta property="og:description" content={pageDescription} />
60
- <meta property="og:type" content="article" />
61
- {/* Canonical URL for both <link> and og:url */}
62
- {typeof window !== 'undefined' && (
63
- <meta property="og:url" content={window.location.href} />
64
- )}
65
- {typeof window !== 'undefined' && (
66
- <link
67
- rel="canonical"
68
- href={window.location.origin + location.pathname}
69
- />
70
- )}
71
-
72
- {/* Default Twitter Card */}
73
- <meta name="twitter:card" content="summary" />
74
- <meta name="twitter:title" content={finalTitle} />
75
- <meta name="twitter:description" content={pageDescription} />
76
- {ogImage && <meta name="twitter:image" content={ogImage} />}
77
- {ogImage && <meta property="og:image" content={ogImage} />}
78
-
79
- {/* Generator */}
80
- <meta name="generator" content="Boltdocs" />
81
-
82
- {/* User-defined global metatags */}
83
- {Object.entries(globalMetatags).map(([key, value]) => {
84
- const isProperty =
85
- key.startsWith('og:') ||
86
- key.startsWith('music:') ||
87
- key.startsWith('video:') ||
88
- key.startsWith('article:') ||
89
- key.startsWith('book:') ||
90
- key.startsWith('profile:')
91
- return isProperty ? (
92
- <meta key={key} property={key} content={value as string} />
93
- ) : (
94
- <meta key={key} name={key} content={value as string} />
95
- )
96
- })}
97
-
98
- {/* Page granular SEO tags (override global) */}
99
- {Object.entries(seo).map(([key, value]) => {
100
- if (key === 'noindex' && value === true)
101
- return <meta key="noindex" name="robots" content="noindex" />
102
- if (key === 'robots')
103
- return <meta key="robots" name="robots" content={value as string} />
104
- if (key === 'canonical')
105
- return <link key="canonical" rel="canonical" href={value as string} />
106
-
107
- const isProperty =
108
- key.startsWith('og:') ||
109
- key.startsWith('music:') ||
110
- key.startsWith('video:') ||
111
- key.startsWith('article:') ||
112
- key.startsWith('book:') ||
113
- key.startsWith('profile:')
114
- return isProperty ? (
115
- <meta key={key} property={key} content={value as string} />
116
- ) : (
117
- <meta key={key} name={key} content={value as string} />
118
- )
119
- })}
120
- </Helmet>
121
- )
122
- }
@@ -1,36 +0,0 @@
1
- /**
2
- * Shared Helmet module compatibility helpers.
3
- *
4
- * react-helmet-async ships different module shapes depending on whether it is
5
- * loaded via CJS or ESM. Instead of duplicating the same detection logic in
6
- * every component that needs Helmet/HelmetProvider, we centralise it here.
7
- */
8
- import type { ComponentType, ReactNode } from 'react'
9
- import * as ReactHelmetAsync from 'react-helmet-async'
10
-
11
- type HelmetModule = {
12
- Helmet?: ComponentType<{ children?: ReactNode }>
13
- HelmetProvider?: ComponentType<{ children?: ReactNode }>
14
- default?: {
15
- Helmet?: ComponentType<{ children?: ReactNode }>
16
- HelmetProvider?: ComponentType<{ children?: ReactNode }>
17
- }
18
- }
19
-
20
- const mod = ReactHelmetAsync as unknown as HelmetModule
21
-
22
- /**
23
- * The `<Helmet>` component, resolved across CJS/ESM module shapes.
24
- * Falls back to a transparent fragment wrapper if the module cannot be resolved.
25
- */
26
- export const Helmet: ComponentType<{ children?: ReactNode }> =
27
- mod.Helmet || mod.default?.Helmet || (({ children }) => <>{children}</>)
28
-
29
- /**
30
- * The `<HelmetProvider>` component, resolved across CJS/ESM module shapes.
31
- * Falls back to a transparent fragment wrapper if the module cannot be resolved.
32
- */
33
- export const HelmetProvider: ComponentType<{ children?: ReactNode }> =
34
- mod.HelmetProvider ||
35
- mod.default?.HelmetProvider ||
36
- (({ children }) => <>{children}</>)
@@ -1,8 +0,0 @@
1
- import { NotFound } from '../components/ui-base/not-found'
2
- import { mdx_components_default } from '../components/mdx'
3
-
4
- export const mdxComponentsDefault = {
5
- ...mdx_components_default,
6
- NotFound,
7
- '404': NotFound,
8
- }
@@ -1,72 +0,0 @@
1
- import { createContext, use, useMemo } from 'react'
2
- import type { BoltdocsMdxComponents } from '../../shared/types'
3
-
4
- export type MdxComponentsType = {
5
- [key: string]: React.ComponentType<any>
6
- } & {
7
- Frontmatter?: Record<string, React.ComponentType<any>>
8
- }
9
-
10
- const MDX_COMPONENTS_CONTEXT_SYMBOL = Symbol.for(
11
- '__BDOCS_MDX_COMPONENTS_CONTEXT__',
12
- )
13
- const MDX_COMPONENTS_INSTANCE_SYMBOL = Symbol.for(
14
- '__BDOCS_MDX_COMPONENTS_INSTANCE__',
15
- )
16
-
17
- const MdxComponentsContext =
18
- (globalThis as any)[MDX_COMPONENTS_CONTEXT_SYMBOL] ||
19
- ((globalThis as any)[MDX_COMPONENTS_CONTEXT_SYMBOL] =
20
- createContext<MdxComponentsType>({}))
21
-
22
- export function useMdxComponents(): BoltdocsMdxComponents {
23
- const context = use(MdxComponentsContext)
24
-
25
- // Fallback to global registry for dual-package hazards
26
- if (
27
- (!context || Object.keys(context).length === 0) &&
28
- (globalThis as any)[MDX_COMPONENTS_INSTANCE_SYMBOL]
29
- ) {
30
- return (globalThis as any)[
31
- MDX_COMPONENTS_INSTANCE_SYMBOL
32
- ] as BoltdocsMdxComponents
33
- }
34
-
35
- return context as any as BoltdocsMdxComponents
36
- }
37
-
38
- export function MdxComponentsProvider({
39
- components,
40
- children,
41
- }: {
42
- components: Record<string, React.ComponentType<any>>
43
- children: React.ReactNode
44
- }) {
45
- const processedComponents = useMemo(() => {
46
- const processed: Record<string, any> = {}
47
- const frontmatter: Record<string, React.ComponentType<any>> = {}
48
-
49
- Object.entries(components).forEach(([key, value]) => {
50
- if (key.startsWith('Frontmatter_')) {
51
- const cleanKey = key.slice('Frontmatter_'.length)
52
- frontmatter[cleanKey] = value
53
- } else {
54
- processed[key] = value
55
- }
56
- })
57
-
58
- processed.Frontmatter = frontmatter
59
- return processed as MdxComponentsType
60
- }, [components])
61
-
62
- // Sync with global registry
63
- if (typeof globalThis !== 'undefined') {
64
- ;(globalThis as any)[MDX_COMPONENTS_INSTANCE_SYMBOL] = processedComponents
65
- }
66
-
67
- return (
68
- <MdxComponentsContext.Provider value={processedComponents}>
69
- {children}
70
- </MdxComponentsContext.Provider>
71
- )
72
- }
@@ -1,34 +0,0 @@
1
- import { createContext, use } from 'react'
2
- import type { ComponentRoute } from '../types'
3
-
4
- interface RoutesContextType {
5
- routes: ComponentRoute[]
6
- }
7
-
8
- const RoutesContext = createContext<RoutesContextType>({
9
- routes: [],
10
- })
11
-
12
- /**
13
- * Hook to access the processed routes list from the closest provider.
14
- */
15
- export function useRoutesContext() {
16
- return use(RoutesContext)
17
- }
18
-
19
- /**
20
- * Provider component for the documentation routes.
21
- */
22
- export function RoutesProvider({
23
- routes,
24
- children,
25
- }: {
26
- routes: ComponentRoute[]
27
- children: React.ReactNode
28
- }) {
29
- return (
30
- <RoutesContext.Provider value={{ routes }}>
31
- {children}
32
- </RoutesContext.Provider>
33
- )
34
- }
@@ -1,74 +0,0 @@
1
- import { useEffect, useLayoutEffect } from 'react'
2
- import { useLocation } from 'react-router-dom'
3
-
4
- /**
5
- * Handles scroll restoration and hash scrolling on navigation.
6
- * It ensures the page scrolls to top on pathname changes,
7
- * or specifically to an anchor element if a hash is present.
8
- */
9
- export function ScrollHandler() {
10
- const { pathname, hash } = useLocation()
11
-
12
- // Helper to handle scroll logic
13
- const handleScroll = (behavior: ScrollBehavior = 'auto') => {
14
- const container = document.querySelector('.boltdocs-content') || window
15
-
16
- const getScrollTop = () => {
17
- if (container === window) return window.scrollY
18
- return (container as HTMLElement).scrollTop
19
- }
20
-
21
- const scrollTo = (top: number, scrollBehavior: ScrollBehavior) => {
22
- if (container === window) {
23
- window.scrollTo({ top, behavior: scrollBehavior })
24
- } else {
25
- ;(container as HTMLElement).scrollTo({ top, behavior: scrollBehavior })
26
- }
27
- }
28
-
29
- if (hash) {
30
- const id = hash.replace('#', '')
31
- const element = document.getElementById(id)
32
- if (element) {
33
- const offset = 80
34
- const containerTop =
35
- container === window
36
- ? 0
37
- : (container as HTMLElement).getBoundingClientRect().top
38
- const elementRect = element.getBoundingClientRect().top
39
- const elementPosition = elementRect - containerTop
40
- const offsetPosition = elementPosition - offset + getScrollTop()
41
-
42
- scrollTo(offsetPosition, behavior)
43
- return true
44
- }
45
- }
46
-
47
- scrollTo(0, behavior)
48
- return false
49
- }
50
-
51
- // 1. Immediate sync scroll before paint
52
- // biome-ignore lint/correctness/useExhaustiveDependencies: pathname is used as a trigger for scroll-to-top on navigation
53
- useLayoutEffect(() => {
54
- handleScroll('auto')
55
- }, [pathname, hash])
56
-
57
- // 2. Delayed async scroll as fallback/stabilizer after paint & passive effects
58
- useEffect(() => {
59
- // Immediate run after paint (helps override old component unmount/revert side effects)
60
- handleScroll('auto')
61
-
62
- // Double-check inside requestAnimationFrame to catch concurrent renders or dynamic layout recalculations
63
- const rafId = requestAnimationFrame(() => {
64
- handleScroll('auto')
65
- // Dispatch resize event so external components/scroll libraries (like GSAP ScrollTrigger) recalculate trigger offsets
66
- window.dispatchEvent(new Event('resize'))
67
- })
68
-
69
- return () => cancelAnimationFrame(rafId)
70
- }, [pathname, hash])
71
-
72
- return null
73
- }
74
-
@@ -1,103 +0,0 @@
1
- import { createContext, use, useState, useEffect } from 'react'
2
-
3
- export type Theme = 'light' | 'dark' | 'system'
4
- export type ResolvedTheme = 'light' | 'dark'
5
-
6
- interface ThemeContextType {
7
- theme: Theme
8
- resolvedTheme: ResolvedTheme
9
- setTheme: (theme: Theme) => void
10
- }
11
-
12
- const THEME_CONTEXT_SYMBOL = Symbol.for('__BDOCS_THEME_CONTEXT__')
13
- const THEME_INSTANCE_SYMBOL = Symbol.for('__BDOCS_THEME_INSTANCE__')
14
- const THEME_EVENT = 'boltdocs-theme-change'
15
-
16
- const ThemeContext =
17
- (globalThis as any)[THEME_CONTEXT_SYMBOL] ||
18
- ((globalThis as any)[THEME_CONTEXT_SYMBOL] = createContext<
19
- ThemeContextType | undefined
20
- >(undefined))
21
-
22
- export function ThemeProvider({ children }: { children: React.ReactNode }) {
23
- const [theme, setThemeState] = useState<Theme>('system')
24
- const [resolvedTheme, setResolvedTheme] = useState<ResolvedTheme>('dark')
25
-
26
- const applyTheme = (targetTheme: Theme) => {
27
- const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
28
- const isDark =
29
- targetTheme === 'dark' || (targetTheme === 'system' && mediaQuery.matches)
30
-
31
- const root = window.document.documentElement
32
- root.classList.toggle('dark', isDark)
33
- root.dataset.theme = isDark ? 'dark' : 'light'
34
- setResolvedTheme(isDark ? 'dark' : 'light')
35
- }
36
-
37
- useEffect(() => {
38
- const savedTheme = localStorage.getItem('boltdocs-theme') as Theme | null
39
- if (savedTheme) {
40
- setThemeState(savedTheme)
41
- applyTheme(savedTheme)
42
- } else {
43
- applyTheme('system')
44
- }
45
-
46
- const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
47
- const listener = () => {
48
- const current =
49
- (localStorage.getItem('boltdocs-theme') as Theme) || 'system'
50
- if (current === 'system') applyTheme('system')
51
- }
52
-
53
- mediaQuery.addEventListener('change', listener)
54
- return () => mediaQuery.removeEventListener('change', listener)
55
- }, [])
56
-
57
- const setTheme = (newTheme: Theme) => {
58
- setThemeState(newTheme)
59
- localStorage.setItem('boltdocs-theme', newTheme)
60
- applyTheme(newTheme)
61
-
62
- // Notify external listeners (dual-package hazard)
63
- if (typeof window !== 'undefined') {
64
- window.dispatchEvent(new CustomEvent(THEME_EVENT, { detail: newTheme }))
65
- }
66
- }
67
-
68
- const value = { theme, resolvedTheme, setTheme }
69
-
70
- // Sync with global registry
71
- if (typeof globalThis !== 'undefined') {
72
- ;(globalThis as any)[THEME_INSTANCE_SYMBOL] = value
73
- }
74
-
75
- return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
76
- }
77
-
78
- export function useTheme() {
79
- const context = use(ThemeContext)
80
- const [, forceUpdate] = useState({})
81
-
82
- useEffect(() => {
83
- if (context) return
84
-
85
- const handler = () => forceUpdate({})
86
- window.addEventListener(THEME_EVENT, handler)
87
- return () => window.removeEventListener(THEME_EVENT, handler)
88
- }, [context])
89
-
90
- // Fallback to global registry for dual-package hazards
91
- if (
92
- !context &&
93
- typeof globalThis !== 'undefined' &&
94
- (globalThis as any)[THEME_INSTANCE_SYMBOL]
95
- ) {
96
- return (globalThis as any)[THEME_INSTANCE_SYMBOL] as ThemeContextType
97
- }
98
-
99
- if (context === undefined) {
100
- throw new Error('useTheme must be used within a ThemeProvider')
101
- }
102
- return context as ThemeContextType
103
- }
@@ -1,42 +0,0 @@
1
- import { createContext, useContext, useState, useEffect } from 'react'
2
- import { useLocation } from 'react-router-dom'
3
-
4
- interface UIContextType {
5
- isSidebarOpen: boolean
6
- toggleSidebar: () => void
7
- closeSidebar: () => void
8
- }
9
-
10
- const UIContext = createContext<UIContextType | undefined>(undefined)
11
-
12
- export function UIProvider({ children }: { children: React.ReactNode }) {
13
- const [isSidebarOpen, setIsSidebarOpen] = useState(false)
14
- const location = useLocation()
15
-
16
- const toggleSidebar = () => setIsSidebarOpen((prev) => !prev)
17
- const closeSidebar = () => setIsSidebarOpen(false)
18
-
19
- // Close sidebar on navigation
20
- useEffect(() => {
21
- setIsSidebarOpen(false)
22
- }, [location.pathname])
23
-
24
- return (
25
- <UIContext.Provider value={{ isSidebarOpen, toggleSidebar, closeSidebar }}>
26
- {children}
27
- </UIContext.Provider>
28
- )
29
- }
30
-
31
- export function useUI() {
32
- const context = useContext(UIContext)
33
- if (context === undefined) {
34
- // Safe fallback for split bundles, independent component renders, or during SSR
35
- return {
36
- isSidebarOpen: false,
37
- toggleSidebar: () => {},
38
- closeSidebar: () => {},
39
- }
40
- }
41
- return context
42
- }