@usecross/docs 0.12.1 → 0.13.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.
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/ssr.js +18 -7
- package/dist/ssr.js.map +1 -1
- package/package.json +1 -1
- package/src/components/ThemeProvider.tsx +5 -0
- package/src/ssr.tsx +5 -2
package/dist/ssr.js
CHANGED
|
@@ -3,10 +3,21 @@ import { createInertiaApp } from "@inertiajs/react";
|
|
|
3
3
|
import createServer from "@inertiajs/react/server";
|
|
4
4
|
import ReactDOMServer from "react-dom/server";
|
|
5
5
|
|
|
6
|
-
// src/
|
|
7
|
-
import { createContext, useContext
|
|
6
|
+
// src/context/ComponentsContext.tsx
|
|
7
|
+
import { createContext, useContext } from "react";
|
|
8
8
|
import { jsx } from "react/jsx-runtime";
|
|
9
|
-
var
|
|
9
|
+
var ComponentsContext = createContext({});
|
|
10
|
+
function ComponentsProvider({
|
|
11
|
+
children,
|
|
12
|
+
components
|
|
13
|
+
}) {
|
|
14
|
+
return /* @__PURE__ */ jsx(ComponentsContext.Provider, { value: { components }, children });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/components/ThemeProvider.tsx
|
|
18
|
+
import { createContext as createContext2, useContext as useContext2, useEffect, useState } from "react";
|
|
19
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
20
|
+
var ThemeContext = createContext2(null);
|
|
10
21
|
var STORAGE_KEY = "cross-docs-theme";
|
|
11
22
|
function getSystemTheme() {
|
|
12
23
|
if (typeof window === "undefined") return "light";
|
|
@@ -66,7 +77,7 @@ function ThemeProvider({
|
|
|
66
77
|
setThemeState(newTheme);
|
|
67
78
|
localStorage.setItem(STORAGE_KEY, newTheme);
|
|
68
79
|
};
|
|
69
|
-
return /* @__PURE__ */
|
|
80
|
+
return /* @__PURE__ */ jsx2(ThemeContext.Provider, { value: { theme, resolvedTheme, setTheme }, children });
|
|
70
81
|
}
|
|
71
82
|
var themeInitScript = `
|
|
72
83
|
(function() {
|
|
@@ -80,9 +91,9 @@ var themeInitScript = `
|
|
|
80
91
|
`.trim();
|
|
81
92
|
|
|
82
93
|
// src/ssr.tsx
|
|
83
|
-
import { jsx as
|
|
94
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
84
95
|
function createDocsServer(config) {
|
|
85
|
-
const { pages, title } = config;
|
|
96
|
+
const { pages, title, components } = config;
|
|
86
97
|
createServer(
|
|
87
98
|
(page) => createInertiaApp({
|
|
88
99
|
page,
|
|
@@ -95,7 +106,7 @@ function createDocsServer(config) {
|
|
|
95
106
|
}
|
|
96
107
|
return pageComponent;
|
|
97
108
|
},
|
|
98
|
-
setup: ({ App, props }) => /* @__PURE__ */
|
|
109
|
+
setup: ({ App, props }) => /* @__PURE__ */ jsx3(ThemeProvider, { children: /* @__PURE__ */ jsx3(ComponentsProvider, { components, children: /* @__PURE__ */ jsx3(App, { ...props }) }) })
|
|
99
110
|
})
|
|
100
111
|
);
|
|
101
112
|
}
|
package/dist/ssr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ssr.tsx","../src/components/ThemeProvider.tsx"],"sourcesContent":["import { createInertiaApp } from '@inertiajs/react'\nimport createServer from '@inertiajs/react/server'\nimport ReactDOMServer from 'react-dom/server'\nimport type { DocsAppConfig } from './types'\nimport { ThemeProvider } from './components/ThemeProvider'\n\n/**\n * Create an SSR server for documentation.\n *\n * @example\n * ```tsx\n * import { createDocsServer, DocsPage } from '@usecross/docs'\n *\n * createDocsServer({\n * pages: {\n * 'docs/DocsPage': DocsPage,\n * },\n * title: (title) => `${title} - My Docs`,\n * })\n * ```\n */\nexport function createDocsServer(config: DocsAppConfig): void {\n const { pages, title } = config\n\n createServer((page) =>\n createInertiaApp({\n page,\n render: ReactDOMServer.renderToString,\n title: title ?? ((pageTitle) => (pageTitle ? `${pageTitle}` : 'Documentation')),\n resolve: (name) => {\n const pageComponent = pages[name]\n if (!pageComponent) {\n throw new Error(`Page component \"${name}\" not found`)\n }\n return pageComponent\n },\n setup: ({ App, props }) => (\n <ThemeProvider>\n <App {...props} />\n </ThemeProvider>\n ),\n })\n )\n}\n","import { createContext, useContext, useEffect, useState, type ReactNode } from 'react'\n\nexport type Theme = 'light' | 'dark' | 'system'\nexport type ResolvedTheme = 'light' | 'dark'\n\ninterface ThemeContextValue {\n theme: Theme\n resolvedTheme: ResolvedTheme\n setTheme: (theme: Theme) => void\n}\n\nconst ThemeContext = createContext<ThemeContextValue | null>(null)\n\nconst STORAGE_KEY = 'cross-docs-theme'\n\nfunction getSystemTheme(): ResolvedTheme {\n if (typeof window === 'undefined') return 'light'\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n}\n\nfunction getStoredTheme(): Theme | null {\n if (typeof window === 'undefined') return null\n const stored = localStorage.getItem(STORAGE_KEY)\n if (stored === 'light' || stored === 'dark' || stored === 'system') {\n return stored\n }\n return null\n}\n\ninterface ThemeProviderProps {\n children: ReactNode\n /** Default theme if no preference is stored. Defaults to 'system'. */\n defaultTheme?: Theme\n /** Force a specific theme, ignoring user preference */\n forcedTheme?: ResolvedTheme\n}\n\nexport function ThemeProvider({\n children,\n defaultTheme = 'system',\n forcedTheme,\n}: ThemeProviderProps) {\n const [theme, setThemeState] = useState<Theme>(() => {\n // During SSR, use defaultTheme\n if (typeof window === 'undefined') return defaultTheme\n return getStoredTheme() ?? defaultTheme\n })\n\n const [resolvedTheme, setResolvedTheme] = useState<ResolvedTheme>(() => {\n if (forcedTheme) return forcedTheme\n if (typeof window === 'undefined') return 'light'\n if (theme === 'system') return getSystemTheme()\n return theme\n })\n\n // Update resolved theme when theme changes or system preference changes\n useEffect(() => {\n if (forcedTheme) {\n setResolvedTheme(forcedTheme)\n return\n }\n\n const updateResolvedTheme = () => {\n if (theme === 'system') {\n setResolvedTheme(getSystemTheme())\n } else {\n setResolvedTheme(theme)\n }\n }\n\n updateResolvedTheme()\n\n // Listen for system preference changes\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n const handleChange = () => {\n if (theme === 'system') {\n setResolvedTheme(getSystemTheme())\n }\n }\n\n mediaQuery.addEventListener('change', handleChange)\n return () => mediaQuery.removeEventListener('change', handleChange)\n }, [theme, forcedTheme])\n\n // Apply theme class to document\n useEffect(() => {\n const root = document.documentElement\n root.classList.remove('light', 'dark')\n root.classList.add(resolvedTheme)\n }, [resolvedTheme])\n\n const setTheme = (newTheme: Theme) => {\n setThemeState(newTheme)\n localStorage.setItem(STORAGE_KEY, newTheme)\n }\n\n return (\n <ThemeContext.Provider value={{ theme, resolvedTheme, setTheme }}>\n {children}\n </ThemeContext.Provider>\n )\n}\n\nexport function useTheme(): ThemeContextValue {\n const context = useContext(ThemeContext)\n if (!context) {\n throw new Error('useTheme must be used within a ThemeProvider')\n }\n return context\n}\n\n/**\n * Script to prevent flash of unstyled content (FOUC) during page load.\n * Include this in your HTML <head> before any stylesheets.\n */\nexport const themeInitScript = `\n(function() {\n try {\n var stored = localStorage.getItem('${STORAGE_KEY}');\n var theme = stored === 'light' || stored === 'dark' ? stored :\n (stored === 'system' || !stored) && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n document.documentElement.classList.add(theme);\n } catch (e) {}\n})();\n`.trim()\n"],"mappings":";AAAA,SAAS,wBAAwB;AACjC,OAAO,kBAAkB;AACzB,OAAO,oBAAoB;;;ACF3B,
|
|
1
|
+
{"version":3,"sources":["../src/ssr.tsx","../src/context/ComponentsContext.tsx","../src/components/ThemeProvider.tsx"],"sourcesContent":["import { createInertiaApp } from '@inertiajs/react'\nimport createServer from '@inertiajs/react/server'\nimport ReactDOMServer from 'react-dom/server'\nimport type { DocsAppConfig } from './types'\nimport { ComponentsProvider } from './context/ComponentsContext'\nimport { ThemeProvider } from './components/ThemeProvider'\n\n/**\n * Create an SSR server for documentation.\n *\n * @example\n * ```tsx\n * import { createDocsServer, DocsPage } from '@usecross/docs'\n *\n * createDocsServer({\n * pages: {\n * 'docs/DocsPage': DocsPage,\n * },\n * title: (title) => `${title} - My Docs`,\n * })\n * ```\n */\nexport function createDocsServer(config: DocsAppConfig): void {\n const { pages, title, components } = config\n\n createServer((page) =>\n createInertiaApp({\n page,\n render: ReactDOMServer.renderToString,\n title: title ?? ((pageTitle) => (pageTitle ? `${pageTitle}` : 'Documentation')),\n resolve: (name) => {\n const pageComponent = pages[name]\n if (!pageComponent) {\n throw new Error(`Page component \"${name}\" not found`)\n }\n return pageComponent\n },\n setup: ({ App, props }) => (\n <ThemeProvider>\n <ComponentsProvider components={components}>\n <App {...props} />\n </ComponentsProvider>\n </ThemeProvider>\n ),\n })\n )\n}\n","import React, { createContext, useContext } from 'react'\n\ninterface ComponentsContextValue {\n components?: Record<string, React.ComponentType<any>>\n}\n\nconst ComponentsContext = createContext<ComponentsContextValue>({})\n\nexport function ComponentsProvider({\n children,\n components,\n}: {\n children: React.ReactNode\n components?: Record<string, React.ComponentType<any>>\n}) {\n return (\n <ComponentsContext.Provider value={{ components }}>\n {children}\n </ComponentsContext.Provider>\n )\n}\n\nexport function useComponents() {\n return useContext(ComponentsContext)\n}\n","import { createContext, useContext, useEffect, useState, type ReactNode } from 'react'\n\nexport type Theme = 'light' | 'dark' | 'system'\nexport type ResolvedTheme = 'light' | 'dark'\n\ninterface ThemeContextValue {\n theme: Theme\n resolvedTheme: ResolvedTheme\n setTheme: (theme: Theme) => void\n}\n\nconst ThemeContext = createContext<ThemeContextValue | null>(null)\n\nconst STORAGE_KEY = 'cross-docs-theme'\n\nfunction getSystemTheme(): ResolvedTheme {\n if (typeof window === 'undefined') return 'light'\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n}\n\nfunction getStoredTheme(): Theme | null {\n if (typeof window === 'undefined') return null\n const stored = localStorage.getItem(STORAGE_KEY)\n if (stored === 'light' || stored === 'dark' || stored === 'system') {\n return stored\n }\n return null\n}\n\ninterface ThemeProviderProps {\n children: ReactNode\n /** Default theme if no preference is stored. Defaults to 'system'. */\n defaultTheme?: Theme\n /** Force a specific theme, ignoring user preference */\n forcedTheme?: ResolvedTheme\n}\n\nexport function ThemeProvider({\n children,\n defaultTheme = 'system',\n forcedTheme,\n}: ThemeProviderProps) {\n const [theme, setThemeState] = useState<Theme>(() => {\n // During SSR, use defaultTheme\n if (typeof window === 'undefined') return defaultTheme\n return getStoredTheme() ?? defaultTheme\n })\n\n const [resolvedTheme, setResolvedTheme] = useState<ResolvedTheme>(() => {\n if (forcedTheme) return forcedTheme\n if (typeof window === 'undefined') return 'light'\n if (theme === 'system') return getSystemTheme()\n return theme\n })\n\n // Update resolved theme when theme changes or system preference changes\n useEffect(() => {\n if (forcedTheme) {\n setResolvedTheme(forcedTheme)\n return\n }\n\n const updateResolvedTheme = () => {\n if (theme === 'system') {\n setResolvedTheme(getSystemTheme())\n } else {\n setResolvedTheme(theme)\n }\n }\n\n updateResolvedTheme()\n\n // Listen for system preference changes\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n const handleChange = () => {\n if (theme === 'system') {\n setResolvedTheme(getSystemTheme())\n }\n }\n\n mediaQuery.addEventListener('change', handleChange)\n return () => mediaQuery.removeEventListener('change', handleChange)\n }, [theme, forcedTheme])\n\n // Apply theme class to document\n useEffect(() => {\n const root = document.documentElement\n root.classList.remove('light', 'dark')\n root.classList.add(resolvedTheme)\n }, [resolvedTheme])\n\n const setTheme = (newTheme: Theme) => {\n setThemeState(newTheme)\n localStorage.setItem(STORAGE_KEY, newTheme)\n }\n\n return (\n <ThemeContext.Provider value={{ theme, resolvedTheme, setTheme }}>\n {children}\n </ThemeContext.Provider>\n )\n}\n\nexport function useTheme(): ThemeContextValue {\n const context = useContext(ThemeContext)\n if (!context) {\n // During SSR, the context may not be available due to module\n // duplication in the bundle. Return safe defaults instead of throwing.\n if (typeof window === 'undefined') {\n return { theme: 'system', resolvedTheme: 'light', setTheme: () => {} }\n }\n throw new Error('useTheme must be used within a ThemeProvider')\n }\n return context\n}\n\n/**\n * Script to prevent flash of unstyled content (FOUC) during page load.\n * Include this in your HTML <head> before any stylesheets.\n */\nexport const themeInitScript = `\n(function() {\n try {\n var stored = localStorage.getItem('${STORAGE_KEY}');\n var theme = stored === 'light' || stored === 'dark' ? stored :\n (stored === 'system' || !stored) && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n document.documentElement.classList.add(theme);\n } catch (e) {}\n})();\n`.trim()\n"],"mappings":"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","names":["createContext","useContext","jsx","jsx"]}
|
package/package.json
CHANGED
|
@@ -104,6 +104,11 @@ export function ThemeProvider({
|
|
|
104
104
|
export function useTheme(): ThemeContextValue {
|
|
105
105
|
const context = useContext(ThemeContext)
|
|
106
106
|
if (!context) {
|
|
107
|
+
// During SSR, the context may not be available due to module
|
|
108
|
+
// duplication in the bundle. Return safe defaults instead of throwing.
|
|
109
|
+
if (typeof window === 'undefined') {
|
|
110
|
+
return { theme: 'system', resolvedTheme: 'light', setTheme: () => {} }
|
|
111
|
+
}
|
|
107
112
|
throw new Error('useTheme must be used within a ThemeProvider')
|
|
108
113
|
}
|
|
109
114
|
return context
|
package/src/ssr.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import { createInertiaApp } from '@inertiajs/react'
|
|
|
2
2
|
import createServer from '@inertiajs/react/server'
|
|
3
3
|
import ReactDOMServer from 'react-dom/server'
|
|
4
4
|
import type { DocsAppConfig } from './types'
|
|
5
|
+
import { ComponentsProvider } from './context/ComponentsContext'
|
|
5
6
|
import { ThemeProvider } from './components/ThemeProvider'
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -20,7 +21,7 @@ import { ThemeProvider } from './components/ThemeProvider'
|
|
|
20
21
|
* ```
|
|
21
22
|
*/
|
|
22
23
|
export function createDocsServer(config: DocsAppConfig): void {
|
|
23
|
-
const { pages, title } = config
|
|
24
|
+
const { pages, title, components } = config
|
|
24
25
|
|
|
25
26
|
createServer((page) =>
|
|
26
27
|
createInertiaApp({
|
|
@@ -36,7 +37,9 @@ export function createDocsServer(config: DocsAppConfig): void {
|
|
|
36
37
|
},
|
|
37
38
|
setup: ({ App, props }) => (
|
|
38
39
|
<ThemeProvider>
|
|
39
|
-
<
|
|
40
|
+
<ComponentsProvider components={components}>
|
|
41
|
+
<App {...props} />
|
|
42
|
+
</ComponentsProvider>
|
|
40
43
|
</ThemeProvider>
|
|
41
44
|
),
|
|
42
45
|
})
|