@dispatchcms/react 0.0.4 → 0.0.6
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/.turbo/turbo-build.log +8 -8
- package/README.md +131 -0
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/config.ts +2 -5
- package/src/context.tsx +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
> @dispatchcms/react@0.0.
|
|
3
|
+
> @dispatchcms/react@0.0.5 build /Users/jamescalmus/Documents/dispatch/packages/react
|
|
4
4
|
> tsup
|
|
5
5
|
|
|
6
6
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
[34mCLI[39m Cleaning output folder
|
|
12
12
|
[34mCJS[39m Build start
|
|
13
13
|
[34mESM[39m Build start
|
|
14
|
-
[
|
|
15
|
-
[
|
|
16
|
-
[
|
|
17
|
-
[
|
|
18
|
-
[
|
|
19
|
-
[
|
|
14
|
+
[32mCJS[39m [1mdist/index.js [22m[32m4.80 KB[39m
|
|
15
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m7.38 KB[39m
|
|
16
|
+
[32mCJS[39m ⚡️ Build success in 12ms
|
|
17
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m3.49 KB[39m
|
|
18
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m7.08 KB[39m
|
|
19
|
+
[32mESM[39m ⚡️ Build success in 12ms
|
|
20
20
|
DTS Build start
|
|
21
|
-
DTS ⚡️ Build success in
|
|
21
|
+
DTS ⚡️ Build success in 442ms
|
|
22
22
|
DTS dist/index.d.ts 1.10 KB
|
|
23
23
|
DTS dist/index.d.mts 1.10 KB
|
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# @dispatchcms/react
|
|
2
|
+
|
|
3
|
+
React hooks and provider for [Dispatch](https://dispatch-cms.vercel.app) CMS. Use `DispatchProvider` and `usePost` / `usePosts` to fetch published posts in any React app (Next.js, Vite, etc.).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @dispatchcms/react
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @dispatchcms/react
|
|
11
|
+
# or
|
|
12
|
+
yarn add @dispatchcms/react
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Setup
|
|
16
|
+
|
|
17
|
+
Wrap your app with `DispatchProvider` and pass your site key (from [Dispatch](https://dispatch-cms.vercel.app) → Sites → your site). Read the key from your app’s config or environment (e.g. in Vite use `import.meta.env.VITE_DISPATCH_SITE_KEY`, or pass a literal in development):
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { DispatchProvider } from "@dispatchcms/react";
|
|
21
|
+
|
|
22
|
+
export default function App({ children }) {
|
|
23
|
+
return (
|
|
24
|
+
<DispatchProvider siteKey={import.meta.env.VITE_DISPATCH_SITE_KEY}>
|
|
25
|
+
{children}
|
|
26
|
+
</DispatchProvider>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
To use a different API base URL, pass the `apiBase` prop to the provider.
|
|
32
|
+
|
|
33
|
+
## API
|
|
34
|
+
|
|
35
|
+
### `usePost(slug)`
|
|
36
|
+
|
|
37
|
+
Fetches a single published post by slug.
|
|
38
|
+
|
|
39
|
+
- **Returns:** `{ post: Post | null, isLoading: boolean, error?: string }`
|
|
40
|
+
- On failure or missing site key, does not throw; returns `post: null`, `isLoading: false`, and `error` set.
|
|
41
|
+
|
|
42
|
+
### `usePosts()`
|
|
43
|
+
|
|
44
|
+
Fetches all published posts for the site.
|
|
45
|
+
|
|
46
|
+
- **Returns:** `{ posts: Post[], isLoading: boolean, error?: string }`
|
|
47
|
+
- On failure or missing site key, does not throw; returns `posts: []`, `isLoading: false`, and `error` set.
|
|
48
|
+
|
|
49
|
+
### Graceful failure
|
|
50
|
+
|
|
51
|
+
- If the API request fails, hooks return `post: null` / `posts: []`, `isLoading: false`, and `error: "Failed to load"`. The React tree is never crashed.
|
|
52
|
+
- If no `siteKey` is provided to the provider, `console.warn` is logged and hooks return the same safe empty/error state with `error: "Missing site key"`.
|
|
53
|
+
|
|
54
|
+
## Types
|
|
55
|
+
|
|
56
|
+
- **`Post`** – Post from the CMS. Fields include `id`, `title`, `slug`, `content`, `excerpt`, `featured_image`, `published`, `published_at`, `created_at`, `updated_at`, `site_id`. The `content` field is **TipTap (ProseMirror) JSON**.
|
|
57
|
+
- **`UsePostResult`** / **`UsePostsResult`** – Return types of the hooks.
|
|
58
|
+
|
|
59
|
+
## Rendering content
|
|
60
|
+
|
|
61
|
+
Post content is stored as TipTap (ProseMirror) JSON. Render it with TipTap’s static renderer so formatting, links, and images match the CMS:
|
|
62
|
+
|
|
63
|
+
- **React:** Use `renderToReactElement` from `@tiptap/static-renderer/pm/react` with the same extensions as the CMS (e.g. `StarterKit`, or Document, Paragraph, Heading, Bold, Italic, Blockquote, BulletList, ListItem, Link, Image). No `dangerouslySetInnerHTML` needed.
|
|
64
|
+
- **HTML string:** Use `renderToHTMLString` from `@tiptap/static-renderer/pm/html-string` (e.g. for SSR or non-React output).
|
|
65
|
+
|
|
66
|
+
For full parity with the CMS editor, use the same extensions (Document, Paragraph, Text, Heading, Bold, Italic, Blockquote, BulletList, ListItem, Link, Image). See [TipTap static renderer docs](https://tiptap.dev/docs/editor/api/utilities/static-renderer).
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
import { renderToReactElement } from "@tiptap/static-renderer/pm/react";
|
|
70
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
71
|
+
|
|
72
|
+
function TipTapContent({ content }: { content: unknown }) {
|
|
73
|
+
if (content == null || typeof content !== "object") return null;
|
|
74
|
+
return renderToReactElement({
|
|
75
|
+
extensions: [StarterKit],
|
|
76
|
+
content: content as { type: string; content?: unknown[] },
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// In your post page:
|
|
81
|
+
<TipTapContent content={post.content} />
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Example
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
// List posts (e.g. homepage)
|
|
88
|
+
import { usePosts } from "@dispatchcms/react";
|
|
89
|
+
|
|
90
|
+
export default function HomePage() {
|
|
91
|
+
const { posts, isLoading, error } = usePosts();
|
|
92
|
+
|
|
93
|
+
if (isLoading) return <p>Loading…</p>;
|
|
94
|
+
if (error) return <p>{error}</p>;
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<ul>
|
|
98
|
+
{posts.map((post) => (
|
|
99
|
+
<li key={post.id}>
|
|
100
|
+
<a href={`/blog/${post.slug}`}>{post.title}</a>
|
|
101
|
+
</li>
|
|
102
|
+
))}
|
|
103
|
+
</ul>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
// Single post page (e.g. /blog/:slug)
|
|
110
|
+
import { usePost } from "@dispatchcms/react";
|
|
111
|
+
import { TipTapContent } from "./TipTapContent"; // or inline renderToReactElement
|
|
112
|
+
|
|
113
|
+
export default function PostPage({ slug }) {
|
|
114
|
+
const { post, isLoading, error } = usePost(slug);
|
|
115
|
+
|
|
116
|
+
if (isLoading) return <p>Loading…</p>;
|
|
117
|
+
if (error || !post) return <p>{error ?? "Not found"}</p>;
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<article>
|
|
121
|
+
<h1>{post.title}</h1>
|
|
122
|
+
{post.excerpt && <p>{post.excerpt}</p>}
|
|
123
|
+
<TipTapContent content={post.content} />
|
|
124
|
+
</article>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -32,9 +32,9 @@ module.exports = __toCommonJS(index_exports);
|
|
|
32
32
|
var import_react = require("react");
|
|
33
33
|
|
|
34
34
|
// src/config.ts
|
|
35
|
-
var
|
|
35
|
+
var DEFAULT_API_BASE = "https://dispatch-cms.vercel.app";
|
|
36
36
|
function getApiBase() {
|
|
37
|
-
return
|
|
37
|
+
return DEFAULT_API_BASE;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
// src/context.tsx
|
|
@@ -55,7 +55,7 @@ function DispatchProvider({
|
|
|
55
55
|
if (!value.siteKey) {
|
|
56
56
|
if (typeof console !== "undefined" && console.warn) {
|
|
57
57
|
console.warn(
|
|
58
|
-
"[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider
|
|
58
|
+
"[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider. Hooks will return empty/error state."
|
|
59
59
|
);
|
|
60
60
|
}
|
|
61
61
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/context.tsx","../src/config.ts","../src/hooks.ts"],"sourcesContent":["export type { Post } from \"./types\";\nexport { DispatchProvider, useDispatchContext } from \"./context\";\nexport { usePost, usePosts } from \"./hooks\";\nexport type { UsePostResult, UsePostsResult } from \"./hooks\";\n","\"use client\";\n\nimport React, { createContext, useContext } from \"react\";\nimport { getApiBase } from \"./config\";\n\ntype DispatchContextValue = {\n siteKey: string | null;\n apiBase: string;\n};\n\nconst DispatchContext = createContext<DispatchContextValue | null>(null);\n\nexport function useDispatchContext(): DispatchContextValue | null {\n return useContext(DispatchContext);\n}\n\ntype DispatchProviderProps = {\n siteKey?: string | null;\n apiBase?: string;\n children?: unknown;\n};\n\nexport function DispatchProvider({\n siteKey = null,\n apiBase = getApiBase(),\n children,\n}: DispatchProviderProps) {\n const value: DispatchContextValue = {\n siteKey: siteKey?.trim() || null,\n apiBase,\n };\n\n if (!value.siteKey) {\n if (typeof console !== \"undefined\" && console.warn) {\n console.warn(\n \"[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/context.tsx","../src/config.ts","../src/hooks.ts"],"sourcesContent":["export type { Post } from \"./types\";\nexport { DispatchProvider, useDispatchContext } from \"./context\";\nexport { usePost, usePosts } from \"./hooks\";\nexport type { UsePostResult, UsePostsResult } from \"./hooks\";\n","\"use client\";\n\nimport React, { createContext, useContext } from \"react\";\nimport { getApiBase } from \"./config\";\n\ntype DispatchContextValue = {\n siteKey: string | null;\n apiBase: string;\n};\n\nconst DispatchContext = createContext<DispatchContextValue | null>(null);\n\nexport function useDispatchContext(): DispatchContextValue | null {\n return useContext(DispatchContext);\n}\n\ntype DispatchProviderProps = {\n siteKey?: string | null;\n apiBase?: string;\n children?: unknown;\n};\n\nexport function DispatchProvider({\n siteKey = null,\n apiBase = getApiBase(),\n children,\n}: DispatchProviderProps) {\n const value: DispatchContextValue = {\n siteKey: siteKey?.trim() || null,\n apiBase,\n };\n\n if (!value.siteKey) {\n if (typeof console !== \"undefined\" && console.warn) {\n console.warn(\n \"[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider. Hooks will return empty/error state.\"\n );\n }\n }\n\n return (\n <DispatchContext.Provider value={value}>\n {children as React.ReactNode}\n </DispatchContext.Provider>\n );\n}\n","const DEFAULT_API_BASE = \"https://dispatch-cms.vercel.app\";\n\nexport function getApiBase(): string {\n return DEFAULT_API_BASE;\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { Post } from \"./types\";\nimport { useDispatchContext } from \"./context\";\n\nexport type UsePostResult = {\n post: Post | null;\n isLoading: boolean;\n error?: string;\n};\n\nexport function usePost(slug: string | undefined): UsePostResult {\n const ctx = useDispatchContext();\n const [post, setPost] = useState<Post | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!slug?.trim()) {\n setPost(null);\n setIsLoading(false);\n setError(undefined);\n return;\n }\n\n if (!ctx?.siteKey) {\n setPost(null);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setPost(null);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/posts/${encodeURIComponent(slug.trim())}`;\n fetch(url, {\n headers: { \"X-Site-Key\": ctx.siteKey },\n })\n .then((res) => {\n if (cancelled) return;\n if (res.status === 404) {\n setPost(null);\n setIsLoading(false);\n return;\n }\n if (!res.ok) {\n setPost(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled) return;\n setPost(data as Post);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setPost(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [slug, ctx?.siteKey, ctx?.apiBase]);\n\n return { post, isLoading, error };\n}\n\nexport type UsePostsResult = {\n posts: Post[];\n isLoading: boolean;\n error?: string;\n};\n\nexport function usePosts(): UsePostsResult {\n const ctx = useDispatchContext();\n const [posts, setPosts] = useState<Post[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!ctx?.siteKey) {\n setPosts([]);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setPosts([]);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/posts`;\n fetch(url, {\n headers: { \"X-Site-Key\": ctx.siteKey },\n })\n .then((res) => {\n if (cancelled) return;\n if (!res.ok) {\n setPosts([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled) return;\n setPosts(Array.isArray(data) ? data : []);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setPosts([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [ctx?.siteKey, ctx?.apiBase]);\n\n return { posts, isLoading, error };\n}\n"],"mappings":"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","names":["import_react"]}
|
package/dist/index.mjs
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
import { createContext, useContext } from "react";
|
|
5
5
|
|
|
6
6
|
// src/config.ts
|
|
7
|
-
var
|
|
7
|
+
var DEFAULT_API_BASE = "https://dispatch-cms.vercel.app";
|
|
8
8
|
function getApiBase() {
|
|
9
|
-
return
|
|
9
|
+
return DEFAULT_API_BASE;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
// src/context.tsx
|
|
@@ -27,7 +27,7 @@ function DispatchProvider({
|
|
|
27
27
|
if (!value.siteKey) {
|
|
28
28
|
if (typeof console !== "undefined" && console.warn) {
|
|
29
29
|
console.warn(
|
|
30
|
-
"[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider
|
|
30
|
+
"[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider. Hooks will return empty/error state."
|
|
31
31
|
);
|
|
32
32
|
}
|
|
33
33
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.tsx","../src/config.ts","../src/hooks.ts"],"sourcesContent":["\"use client\";\n\nimport React, { createContext, useContext } from \"react\";\nimport { getApiBase } from \"./config\";\n\ntype DispatchContextValue = {\n siteKey: string | null;\n apiBase: string;\n};\n\nconst DispatchContext = createContext<DispatchContextValue | null>(null);\n\nexport function useDispatchContext(): DispatchContextValue | null {\n return useContext(DispatchContext);\n}\n\ntype DispatchProviderProps = {\n siteKey?: string | null;\n apiBase?: string;\n children?: unknown;\n};\n\nexport function DispatchProvider({\n siteKey = null,\n apiBase = getApiBase(),\n children,\n}: DispatchProviderProps) {\n const value: DispatchContextValue = {\n siteKey: siteKey?.trim() || null,\n apiBase,\n };\n\n if (!value.siteKey) {\n if (typeof console !== \"undefined\" && console.warn) {\n console.warn(\n \"[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx","../src/config.ts","../src/hooks.ts"],"sourcesContent":["\"use client\";\n\nimport React, { createContext, useContext } from \"react\";\nimport { getApiBase } from \"./config\";\n\ntype DispatchContextValue = {\n siteKey: string | null;\n apiBase: string;\n};\n\nconst DispatchContext = createContext<DispatchContextValue | null>(null);\n\nexport function useDispatchContext(): DispatchContextValue | null {\n return useContext(DispatchContext);\n}\n\ntype DispatchProviderProps = {\n siteKey?: string | null;\n apiBase?: string;\n children?: unknown;\n};\n\nexport function DispatchProvider({\n siteKey = null,\n apiBase = getApiBase(),\n children,\n}: DispatchProviderProps) {\n const value: DispatchContextValue = {\n siteKey: siteKey?.trim() || null,\n apiBase,\n };\n\n if (!value.siteKey) {\n if (typeof console !== \"undefined\" && console.warn) {\n console.warn(\n \"[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider. Hooks will return empty/error state.\"\n );\n }\n }\n\n return (\n <DispatchContext.Provider value={value}>\n {children as React.ReactNode}\n </DispatchContext.Provider>\n );\n}\n","const DEFAULT_API_BASE = \"https://dispatch-cms.vercel.app\";\n\nexport function getApiBase(): string {\n return DEFAULT_API_BASE;\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { Post } from \"./types\";\nimport { useDispatchContext } from \"./context\";\n\nexport type UsePostResult = {\n post: Post | null;\n isLoading: boolean;\n error?: string;\n};\n\nexport function usePost(slug: string | undefined): UsePostResult {\n const ctx = useDispatchContext();\n const [post, setPost] = useState<Post | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!slug?.trim()) {\n setPost(null);\n setIsLoading(false);\n setError(undefined);\n return;\n }\n\n if (!ctx?.siteKey) {\n setPost(null);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setPost(null);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/posts/${encodeURIComponent(slug.trim())}`;\n fetch(url, {\n headers: { \"X-Site-Key\": ctx.siteKey },\n })\n .then((res) => {\n if (cancelled) return;\n if (res.status === 404) {\n setPost(null);\n setIsLoading(false);\n return;\n }\n if (!res.ok) {\n setPost(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled) return;\n setPost(data as Post);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setPost(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [slug, ctx?.siteKey, ctx?.apiBase]);\n\n return { post, isLoading, error };\n}\n\nexport type UsePostsResult = {\n posts: Post[];\n isLoading: boolean;\n error?: string;\n};\n\nexport function usePosts(): UsePostsResult {\n const ctx = useDispatchContext();\n const [posts, setPosts] = useState<Post[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!ctx?.siteKey) {\n setPosts([]);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setPosts([]);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/posts`;\n fetch(url, {\n headers: { \"X-Site-Key\": ctx.siteKey },\n })\n .then((res) => {\n if (cancelled) return;\n if (!res.ok) {\n setPosts([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled) return;\n setPosts(Array.isArray(data) ? data : []);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setPosts([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [ctx?.siteKey, ctx?.apiBase]);\n\n return { posts, isLoading, error };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dispatchcms/react",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "React hooks and provider for Dispatch CMS",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"typescript": "^5.7.2"
|
|
26
26
|
},
|
|
27
27
|
"engines": {
|
|
28
|
-
"node": ">=
|
|
28
|
+
"node": ">=20.9"
|
|
29
29
|
},
|
|
30
30
|
"keywords": ["dispatch", "cms", "react", "nextjs", "content"],
|
|
31
31
|
"license": "MIT"
|
package/src/config.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
const
|
|
2
|
-
typeof process !== "undefined" && process.env?.NEXT_PUBLIC_DISPATCH_API_URL
|
|
3
|
-
? process.env.NEXT_PUBLIC_DISPATCH_API_URL
|
|
4
|
-
: "https://dispatch-cms.vercel.app";
|
|
1
|
+
const DEFAULT_API_BASE = "https://dispatch-cms.vercel.app";
|
|
5
2
|
|
|
6
3
|
export function getApiBase(): string {
|
|
7
|
-
return
|
|
4
|
+
return DEFAULT_API_BASE;
|
|
8
5
|
}
|
package/src/context.tsx
CHANGED
|
@@ -33,7 +33,7 @@ export function DispatchProvider({
|
|
|
33
33
|
if (!value.siteKey) {
|
|
34
34
|
if (typeof console !== "undefined" && console.warn) {
|
|
35
35
|
console.warn(
|
|
36
|
-
"[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider
|
|
36
|
+
"[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider. Hooks will return empty/error state."
|
|
37
37
|
);
|
|
38
38
|
}
|
|
39
39
|
}
|