@dispatchcms/react 0.0.7 → 0.0.8
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/README.md +11 -0
- package/dist/index.d.mts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +24 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -13
- package/src/index.ts +26 -0
package/README.md
CHANGED
|
@@ -125,6 +125,17 @@ export default function PostPage({ slug }) {
|
|
|
125
125
|
}
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
+
## Images
|
|
129
|
+
|
|
130
|
+
An image field is a URL until an editor drags a point, then `{ url, focus }`. `imageProps` reads both. It only changes which part of the photo stays in view when your frame crops it.
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
import { imageProps } from "@dispatchcms/react";
|
|
134
|
+
|
|
135
|
+
const photo = imageProps(entry.data.hero);
|
|
136
|
+
photo ? <img src={photo.src} alt="" className="h-full w-full" style={photo.style} /> : null
|
|
137
|
+
```
|
|
138
|
+
|
|
128
139
|
## License
|
|
129
140
|
|
|
130
141
|
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -39,4 +39,12 @@ type UseEntriesResult = {
|
|
|
39
39
|
};
|
|
40
40
|
declare function useEntries(collection: string | undefined): UseEntriesResult;
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
declare function imageProps(value: unknown): {
|
|
43
|
+
src: string;
|
|
44
|
+
style: {
|
|
45
|
+
objectFit: "cover";
|
|
46
|
+
objectPosition: string;
|
|
47
|
+
};
|
|
48
|
+
} | null;
|
|
49
|
+
|
|
50
|
+
export { DispatchProvider, type Entry, type UseEntriesResult, type UseEntryResult, imageProps, useDispatchContext, useEntries, useEntry };
|
package/dist/index.d.ts
CHANGED
|
@@ -39,4 +39,12 @@ type UseEntriesResult = {
|
|
|
39
39
|
};
|
|
40
40
|
declare function useEntries(collection: string | undefined): UseEntriesResult;
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
declare function imageProps(value: unknown): {
|
|
43
|
+
src: string;
|
|
44
|
+
style: {
|
|
45
|
+
objectFit: "cover";
|
|
46
|
+
objectPosition: string;
|
|
47
|
+
};
|
|
48
|
+
} | null;
|
|
49
|
+
|
|
50
|
+
export { DispatchProvider, type Entry, type UseEntriesResult, type UseEntryResult, imageProps, useDispatchContext, useEntries, useEntry };
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
22
22
|
var index_exports = {};
|
|
23
23
|
__export(index_exports, {
|
|
24
24
|
DispatchProvider: () => DispatchProvider,
|
|
25
|
+
imageProps: () => imageProps,
|
|
25
26
|
useDispatchContext: () => useDispatchContext,
|
|
26
27
|
useEntries: () => useEntries,
|
|
27
28
|
useEntry: () => useEntry
|
|
@@ -169,9 +170,33 @@ function useEntries(collection) {
|
|
|
169
170
|
}, [collection, ctx?.siteKey, ctx?.apiBase]);
|
|
170
171
|
return { entries, isLoading, error };
|
|
171
172
|
}
|
|
173
|
+
|
|
174
|
+
// src/index.ts
|
|
175
|
+
function imageProps(value) {
|
|
176
|
+
let src = "";
|
|
177
|
+
let x = 0.5;
|
|
178
|
+
let y = 0.5;
|
|
179
|
+
if (typeof value === "string") {
|
|
180
|
+
src = value;
|
|
181
|
+
} else if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
182
|
+
const row = value;
|
|
183
|
+
if (typeof row.url !== "string") return null;
|
|
184
|
+
src = row.url;
|
|
185
|
+
if (row.focus && typeof row.focus === "object" && !Array.isArray(row.focus)) {
|
|
186
|
+
const focus = row.focus;
|
|
187
|
+
if (typeof focus.x === "number" && Number.isFinite(focus.x)) x = Math.min(1, Math.max(0, focus.x));
|
|
188
|
+
if (typeof focus.y === "number" && Number.isFinite(focus.y)) y = Math.min(1, Math.max(0, focus.y));
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
if (!src) return null;
|
|
194
|
+
return { src, style: { objectFit: "cover", objectPosition: `${x * 100}% ${y * 100}%` } };
|
|
195
|
+
}
|
|
172
196
|
// Annotate the CommonJS export names for ESM import in node:
|
|
173
197
|
0 && (module.exports = {
|
|
174
198
|
DispatchProvider,
|
|
199
|
+
imageProps,
|
|
175
200
|
useDispatchContext,
|
|
176
201
|
useEntries,
|
|
177
202
|
useEntry
|
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 { Entry } from \"./types\";\nexport { DispatchProvider, useDispatchContext } from \"./context\";\nexport { useEntry, useEntries } from \"./hooks\";\nexport type { UseEntryResult, UseEntriesResult } 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 { Entry } from \"./types\";\nimport { useDispatchContext } from \"./context\";\n\nexport type UseEntryResult = {\n entry: Entry | null;\n isLoading: boolean;\n error?: string;\n};\n\nexport function useEntry(collection: string | undefined, slug: string | undefined): UseEntryResult {\n const ctx = useDispatchContext();\n const [entry, setEntry] = useState<Entry | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!collection?.trim() || !slug?.trim()) {\n setEntry(null);\n setIsLoading(false);\n setError(undefined);\n return;\n }\n\n if (!ctx?.siteKey) {\n setEntry(null);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setEntry(null);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/content/${encodeURIComponent(collection.trim())}/${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 setEntry(null);\n setIsLoading(false);\n return;\n }\n if (!res.ok) {\n setEntry(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled || data == null) return;\n setEntry(data as Entry);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setEntry(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [collection, slug, ctx?.siteKey, ctx?.apiBase]);\n\n return { entry, isLoading, error };\n}\n\nexport type UseEntriesResult = {\n entries: Entry[];\n isLoading: boolean;\n error?: string;\n};\n\nexport function useEntries(collection: string | undefined): UseEntriesResult {\n const ctx = useDispatchContext();\n const [entries, setEntries] = useState<Entry[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!collection?.trim()) {\n setEntries([]);\n setIsLoading(false);\n setError(undefined);\n return;\n }\n\n if (!ctx?.siteKey) {\n setEntries([]);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setEntries([]);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/content/${encodeURIComponent(collection.trim())}`;\n fetch(url, {\n headers: { \"X-Site-Key\": ctx.siteKey },\n })\n .then((res) => {\n if (cancelled) return;\n if (!res.ok) {\n setEntries([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled || data == null) return;\n setEntries(Array.isArray(data) ? data : []);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setEntries([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [collection, ctx?.siteKey, ctx?.apiBase]);\n\n return { entries, isLoading, error };\n}\n"],"mappings":"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","names":["import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/context.tsx","../src/config.ts","../src/hooks.ts"],"sourcesContent":["export type { Entry } from \"./types\";\nexport { DispatchProvider, useDispatchContext } from \"./context\";\nexport { useEntry, useEntries } from \"./hooks\";\nexport type { UseEntryResult, UseEntriesResult } from \"./hooks\";\n\n// ponytail: percentage object-position. Measure the image against the frame if a subject still clips.\nexport function imageProps(value: unknown): {\n src: string;\n style: { objectFit: \"cover\"; objectPosition: string };\n} | null {\n let src = \"\";\n let x = 0.5;\n let y = 0.5;\n if (typeof value === \"string\") {\n src = value;\n } else if (value && typeof value === \"object\" && !Array.isArray(value)) {\n const row = value as Record<string, unknown>;\n if (typeof row.url !== \"string\") return null;\n src = row.url;\n if (row.focus && typeof row.focus === \"object\" && !Array.isArray(row.focus)) {\n const focus = row.focus as Record<string, unknown>;\n if (typeof focus.x === \"number\" && Number.isFinite(focus.x)) x = Math.min(1, Math.max(0, focus.x));\n if (typeof focus.y === \"number\" && Number.isFinite(focus.y)) y = Math.min(1, Math.max(0, focus.y));\n }\n } else {\n return null;\n }\n if (!src) return null;\n return { src, style: { objectFit: \"cover\", objectPosition: `${x * 100}% ${y * 100}%` } };\n}\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 { Entry } from \"./types\";\nimport { useDispatchContext } from \"./context\";\n\nexport type UseEntryResult = {\n entry: Entry | null;\n isLoading: boolean;\n error?: string;\n};\n\nexport function useEntry(collection: string | undefined, slug: string | undefined): UseEntryResult {\n const ctx = useDispatchContext();\n const [entry, setEntry] = useState<Entry | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!collection?.trim() || !slug?.trim()) {\n setEntry(null);\n setIsLoading(false);\n setError(undefined);\n return;\n }\n\n if (!ctx?.siteKey) {\n setEntry(null);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setEntry(null);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/content/${encodeURIComponent(collection.trim())}/${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 setEntry(null);\n setIsLoading(false);\n return;\n }\n if (!res.ok) {\n setEntry(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled || data == null) return;\n setEntry(data as Entry);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setEntry(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [collection, slug, ctx?.siteKey, ctx?.apiBase]);\n\n return { entry, isLoading, error };\n}\n\nexport type UseEntriesResult = {\n entries: Entry[];\n isLoading: boolean;\n error?: string;\n};\n\nexport function useEntries(collection: string | undefined): UseEntriesResult {\n const ctx = useDispatchContext();\n const [entries, setEntries] = useState<Entry[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!collection?.trim()) {\n setEntries([]);\n setIsLoading(false);\n setError(undefined);\n return;\n }\n\n if (!ctx?.siteKey) {\n setEntries([]);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setEntries([]);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/content/${encodeURIComponent(collection.trim())}`;\n fetch(url, {\n headers: { \"X-Site-Key\": ctx.siteKey },\n })\n .then((res) => {\n if (cancelled) return;\n if (!res.ok) {\n setEntries([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled || data == null) return;\n setEntries(Array.isArray(data) ? data : []);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setEntries([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [collection, ctx?.siteKey, ctx?.apiBase]);\n\n return { entries, isLoading, error };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,mBAAiD;;;ACFjD,IAAM,mBAAmB;AAElB,SAAS,aAAqB;AACnC,SAAO;AACT;;;ADqCI;AA/BJ,IAAM,sBAAkB,4BAA2C,IAAI;AAEhE,SAAS,qBAAkD;AAChE,aAAO,yBAAW,eAAe;AACnC;AAQO,SAAS,iBAAiB;AAAA,EAC/B,UAAU;AAAA,EACV,UAAU,WAAW;AAAA,EACrB;AACF,GAA0B;AACxB,QAAM,QAA8B;AAAA,IAClC,SAAS,SAAS,KAAK,KAAK;AAAA,IAC5B;AAAA,EACF;AAEA,MAAI,CAAC,MAAM,SAAS;AAClB,QAAI,OAAO,YAAY,eAAe,QAAQ,MAAM;AAClD,cAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SACE,4CAAC,gBAAgB,UAAhB,EAAyB,OACvB,UACH;AAEJ;;;AE3CA,IAAAA,gBAAoC;AAU7B,SAAS,SAAS,YAAgC,MAA0C;AACjG,QAAM,MAAM,mBAAmB;AAC/B,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuB,IAAI;AACrD,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,IAAI;AAC/C,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAA6B,MAAS;AAEhE,+BAAU,MAAM;AACd,QAAI,CAAC,YAAY,KAAK,KAAK,CAAC,MAAM,KAAK,GAAG;AACxC,eAAS,IAAI;AACb,mBAAa,KAAK;AAClB,eAAS,MAAS;AAClB;AAAA,IACF;AAEA,QAAI,CAAC,KAAK,SAAS;AACjB,eAAS,IAAI;AACb,mBAAa,KAAK;AAClB,eAAS,kBAAkB;AAC3B;AAAA,IACF;AAEA,QAAI,YAAY;AAChB,aAAS,IAAI;AACb,aAAS,MAAS;AAClB,iBAAa,IAAI;AAEjB,UAAM,MAAM,GAAG,IAAI,OAAO,gBAAgB,mBAAmB,WAAW,KAAK,CAAC,CAAC,IAAI,mBAAmB,KAAK,KAAK,CAAC,CAAC;AAClH,UAAM,KAAK;AAAA,MACT,SAAS,EAAE,cAAc,IAAI,QAAQ;AAAA,IACvC,CAAC,EACE,KAAK,CAAC,QAAQ;AACb,UAAI,UAAW;AACf,UAAI,IAAI,WAAW,KAAK;AACtB,iBAAS,IAAI;AACb,qBAAa,KAAK;AAClB;AAAA,MACF;AACA,UAAI,CAAC,IAAI,IAAI;AACX,iBAAS,IAAI;AACb,qBAAa,KAAK;AAClB,iBAAS,gBAAgB;AACzB;AAAA,MACF;AACA,aAAO,IAAI,KAAK;AAAA,IAClB,CAAC,EACA,KAAK,CAAC,SAAS;AACd,UAAI,aAAa,QAAQ,KAAM;AAC/B,eAAS,IAAa;AACtB,mBAAa,KAAK;AAAA,IACpB,CAAC,EACA,MAAM,MAAM;AACX,UAAI,UAAW;AACf,eAAS,IAAI;AACb,mBAAa,KAAK;AAClB,eAAS,gBAAgB;AAAA,IAC3B,CAAC;AAEH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,YAAY,MAAM,KAAK,SAAS,KAAK,OAAO,CAAC;AAEjD,SAAO,EAAE,OAAO,WAAW,MAAM;AACnC;AAQO,SAAS,WAAW,YAAkD;AAC3E,QAAM,MAAM,mBAAmB;AAC/B,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAkB,CAAC,CAAC;AAClD,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,IAAI;AAC/C,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAA6B,MAAS;AAEhE,+BAAU,MAAM;AACd,QAAI,CAAC,YAAY,KAAK,GAAG;AACvB,iBAAW,CAAC,CAAC;AACb,mBAAa,KAAK;AAClB,eAAS,MAAS;AAClB;AAAA,IACF;AAEA,QAAI,CAAC,KAAK,SAAS;AACjB,iBAAW,CAAC,CAAC;AACb,mBAAa,KAAK;AAClB,eAAS,kBAAkB;AAC3B;AAAA,IACF;AAEA,QAAI,YAAY;AAChB,eAAW,CAAC,CAAC;AACb,aAAS,MAAS;AAClB,iBAAa,IAAI;AAEjB,UAAM,MAAM,GAAG,IAAI,OAAO,gBAAgB,mBAAmB,WAAW,KAAK,CAAC,CAAC;AAC/E,UAAM,KAAK;AAAA,MACT,SAAS,EAAE,cAAc,IAAI,QAAQ;AAAA,IACvC,CAAC,EACE,KAAK,CAAC,QAAQ;AACb,UAAI,UAAW;AACf,UAAI,CAAC,IAAI,IAAI;AACX,mBAAW,CAAC,CAAC;AACb,qBAAa,KAAK;AAClB,iBAAS,gBAAgB;AACzB;AAAA,MACF;AACA,aAAO,IAAI,KAAK;AAAA,IAClB,CAAC,EACA,KAAK,CAAC,SAAS;AACd,UAAI,aAAa,QAAQ,KAAM;AAC/B,iBAAW,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,CAAC;AAC1C,mBAAa,KAAK;AAAA,IACpB,CAAC,EACA,MAAM,MAAM;AACX,UAAI,UAAW;AACf,iBAAW,CAAC,CAAC;AACb,mBAAa,KAAK;AAClB,eAAS,gBAAgB;AAAA,IAC3B,CAAC;AAEH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,YAAY,KAAK,SAAS,KAAK,OAAO,CAAC;AAE3C,SAAO,EAAE,SAAS,WAAW,MAAM;AACrC;;;AHvIO,SAAS,WAAW,OAGlB;AACP,MAAI,MAAM;AACV,MAAI,IAAI;AACR,MAAI,IAAI;AACR,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM;AAAA,EACR,WAAW,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AACtE,UAAM,MAAM;AACZ,QAAI,OAAO,IAAI,QAAQ,SAAU,QAAO;AACxC,UAAM,IAAI;AACV,QAAI,IAAI,SAAS,OAAO,IAAI,UAAU,YAAY,CAAC,MAAM,QAAQ,IAAI,KAAK,GAAG;AAC3E,YAAM,QAAQ,IAAI;AAClB,UAAI,OAAO,MAAM,MAAM,YAAY,OAAO,SAAS,MAAM,CAAC,EAAG,KAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC,CAAC;AACjG,UAAI,OAAO,MAAM,MAAM,YAAY,OAAO,SAAS,MAAM,CAAC,EAAG,KAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC,CAAC;AAAA,IACnG;AAAA,EACF,OAAO;AACL,WAAO;AAAA,EACT;AACA,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,EAAE,KAAK,OAAO,EAAE,WAAW,SAAS,gBAAgB,GAAG,IAAI,GAAG,KAAK,IAAI,GAAG,IAAI,EAAE;AACzF;","names":["import_react"]}
|
package/dist/index.mjs
CHANGED
|
@@ -141,8 +141,32 @@ function useEntries(collection) {
|
|
|
141
141
|
}, [collection, ctx?.siteKey, ctx?.apiBase]);
|
|
142
142
|
return { entries, isLoading, error };
|
|
143
143
|
}
|
|
144
|
+
|
|
145
|
+
// src/index.ts
|
|
146
|
+
function imageProps(value) {
|
|
147
|
+
let src = "";
|
|
148
|
+
let x = 0.5;
|
|
149
|
+
let y = 0.5;
|
|
150
|
+
if (typeof value === "string") {
|
|
151
|
+
src = value;
|
|
152
|
+
} else if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
153
|
+
const row = value;
|
|
154
|
+
if (typeof row.url !== "string") return null;
|
|
155
|
+
src = row.url;
|
|
156
|
+
if (row.focus && typeof row.focus === "object" && !Array.isArray(row.focus)) {
|
|
157
|
+
const focus = row.focus;
|
|
158
|
+
if (typeof focus.x === "number" && Number.isFinite(focus.x)) x = Math.min(1, Math.max(0, focus.x));
|
|
159
|
+
if (typeof focus.y === "number" && Number.isFinite(focus.y)) y = Math.min(1, Math.max(0, focus.y));
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
if (!src) return null;
|
|
165
|
+
return { src, style: { objectFit: "cover", objectPosition: `${x * 100}% ${y * 100}%` } };
|
|
166
|
+
}
|
|
144
167
|
export {
|
|
145
168
|
DispatchProvider,
|
|
169
|
+
imageProps,
|
|
146
170
|
useDispatchContext,
|
|
147
171
|
useEntries,
|
|
148
172
|
useEntry
|
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. 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 { Entry } from \"./types\";\nimport { useDispatchContext } from \"./context\";\n\nexport type UseEntryResult = {\n entry: Entry | null;\n isLoading: boolean;\n error?: string;\n};\n\nexport function useEntry(collection: string | undefined, slug: string | undefined): UseEntryResult {\n const ctx = useDispatchContext();\n const [entry, setEntry] = useState<Entry | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!collection?.trim() || !slug?.trim()) {\n setEntry(null);\n setIsLoading(false);\n setError(undefined);\n return;\n }\n\n if (!ctx?.siteKey) {\n setEntry(null);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setEntry(null);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/content/${encodeURIComponent(collection.trim())}/${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 setEntry(null);\n setIsLoading(false);\n return;\n }\n if (!res.ok) {\n setEntry(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled || data == null) return;\n setEntry(data as Entry);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setEntry(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [collection, slug, ctx?.siteKey, ctx?.apiBase]);\n\n return { entry, isLoading, error };\n}\n\nexport type UseEntriesResult = {\n entries: Entry[];\n isLoading: boolean;\n error?: string;\n};\n\nexport function useEntries(collection: string | undefined): UseEntriesResult {\n const ctx = useDispatchContext();\n const [entries, setEntries] = useState<Entry[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!collection?.trim()) {\n setEntries([]);\n setIsLoading(false);\n setError(undefined);\n return;\n }\n\n if (!ctx?.siteKey) {\n setEntries([]);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setEntries([]);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/content/${encodeURIComponent(collection.trim())}`;\n fetch(url, {\n headers: { \"X-Site-Key\": ctx.siteKey },\n })\n .then((res) => {\n if (cancelled) return;\n if (!res.ok) {\n setEntries([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled || data == null) return;\n setEntries(Array.isArray(data) ? data : []);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setEntries([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [collection, ctx?.siteKey, ctx?.apiBase]);\n\n return { entries, isLoading, error };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx","../src/config.ts","../src/hooks.ts","../src/index.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 { Entry } from \"./types\";\nimport { useDispatchContext } from \"./context\";\n\nexport type UseEntryResult = {\n entry: Entry | null;\n isLoading: boolean;\n error?: string;\n};\n\nexport function useEntry(collection: string | undefined, slug: string | undefined): UseEntryResult {\n const ctx = useDispatchContext();\n const [entry, setEntry] = useState<Entry | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!collection?.trim() || !slug?.trim()) {\n setEntry(null);\n setIsLoading(false);\n setError(undefined);\n return;\n }\n\n if (!ctx?.siteKey) {\n setEntry(null);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setEntry(null);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/content/${encodeURIComponent(collection.trim())}/${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 setEntry(null);\n setIsLoading(false);\n return;\n }\n if (!res.ok) {\n setEntry(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled || data == null) return;\n setEntry(data as Entry);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setEntry(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [collection, slug, ctx?.siteKey, ctx?.apiBase]);\n\n return { entry, isLoading, error };\n}\n\nexport type UseEntriesResult = {\n entries: Entry[];\n isLoading: boolean;\n error?: string;\n};\n\nexport function useEntries(collection: string | undefined): UseEntriesResult {\n const ctx = useDispatchContext();\n const [entries, setEntries] = useState<Entry[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!collection?.trim()) {\n setEntries([]);\n setIsLoading(false);\n setError(undefined);\n return;\n }\n\n if (!ctx?.siteKey) {\n setEntries([]);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setEntries([]);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/content/${encodeURIComponent(collection.trim())}`;\n fetch(url, {\n headers: { \"X-Site-Key\": ctx.siteKey },\n })\n .then((res) => {\n if (cancelled) return;\n if (!res.ok) {\n setEntries([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled || data == null) return;\n setEntries(Array.isArray(data) ? data : []);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setEntries([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [collection, ctx?.siteKey, ctx?.apiBase]);\n\n return { entries, isLoading, error };\n}\n","export type { Entry } from \"./types\";\nexport { DispatchProvider, useDispatchContext } from \"./context\";\nexport { useEntry, useEntries } from \"./hooks\";\nexport type { UseEntryResult, UseEntriesResult } from \"./hooks\";\n\n// ponytail: percentage object-position. Measure the image against the frame if a subject still clips.\nexport function imageProps(value: unknown): {\n src: string;\n style: { objectFit: \"cover\"; objectPosition: string };\n} | null {\n let src = \"\";\n let x = 0.5;\n let y = 0.5;\n if (typeof value === \"string\") {\n src = value;\n } else if (value && typeof value === \"object\" && !Array.isArray(value)) {\n const row = value as Record<string, unknown>;\n if (typeof row.url !== \"string\") return null;\n src = row.url;\n if (row.focus && typeof row.focus === \"object\" && !Array.isArray(row.focus)) {\n const focus = row.focus as Record<string, unknown>;\n if (typeof focus.x === \"number\" && Number.isFinite(focus.x)) x = Math.min(1, Math.max(0, focus.x));\n if (typeof focus.y === \"number\" && Number.isFinite(focus.y)) y = Math.min(1, Math.max(0, focus.y));\n }\n } else {\n return null;\n }\n if (!src) return null;\n return { src, style: { objectFit: \"cover\", objectPosition: `${x * 100}% ${y * 100}%` } };\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.8",
|
|
4
4
|
"description": "React hooks and provider for Dispatch CMS entries",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
"require": "./dist/index.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup"
|
|
17
|
+
},
|
|
15
18
|
"peerDependencies": {
|
|
16
19
|
"react": ">=18.0.0"
|
|
17
20
|
},
|
|
@@ -24,15 +27,6 @@
|
|
|
24
27
|
"engines": {
|
|
25
28
|
"node": ">=20.9"
|
|
26
29
|
},
|
|
27
|
-
"keywords": [
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"react",
|
|
31
|
-
"nextjs",
|
|
32
|
-
"content"
|
|
33
|
-
],
|
|
34
|
-
"license": "MIT",
|
|
35
|
-
"scripts": {
|
|
36
|
-
"build": "tsup"
|
|
37
|
-
}
|
|
38
|
-
}
|
|
30
|
+
"keywords": ["dispatch", "cms", "react", "nextjs", "content"],
|
|
31
|
+
"license": "MIT"
|
|
32
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -2,3 +2,29 @@ export type { Entry } from "./types";
|
|
|
2
2
|
export { DispatchProvider, useDispatchContext } from "./context";
|
|
3
3
|
export { useEntry, useEntries } from "./hooks";
|
|
4
4
|
export type { UseEntryResult, UseEntriesResult } from "./hooks";
|
|
5
|
+
|
|
6
|
+
// ponytail: percentage object-position. Measure the image against the frame if a subject still clips.
|
|
7
|
+
export function imageProps(value: unknown): {
|
|
8
|
+
src: string;
|
|
9
|
+
style: { objectFit: "cover"; objectPosition: string };
|
|
10
|
+
} | null {
|
|
11
|
+
let src = "";
|
|
12
|
+
let x = 0.5;
|
|
13
|
+
let y = 0.5;
|
|
14
|
+
if (typeof value === "string") {
|
|
15
|
+
src = value;
|
|
16
|
+
} else if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
17
|
+
const row = value as Record<string, unknown>;
|
|
18
|
+
if (typeof row.url !== "string") return null;
|
|
19
|
+
src = row.url;
|
|
20
|
+
if (row.focus && typeof row.focus === "object" && !Array.isArray(row.focus)) {
|
|
21
|
+
const focus = row.focus as Record<string, unknown>;
|
|
22
|
+
if (typeof focus.x === "number" && Number.isFinite(focus.x)) x = Math.min(1, Math.max(0, focus.x));
|
|
23
|
+
if (typeof focus.y === "number" && Number.isFinite(focus.y)) y = Math.min(1, Math.max(0, focus.y));
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
if (!src) return null;
|
|
29
|
+
return { src, style: { objectFit: "cover", objectPosition: `${x * 100}% ${y * 100}%` } };
|
|
30
|
+
}
|