next-sanity
Advanced tools
Comparing version 0.1.6 to 0.1.7
@@ -152,3 +152,3 @@ 'use strict'; | ||
const _useState3 = React.useState(initialData), | ||
const _useState3 = React.useState(), | ||
data = _useState3[0], | ||
@@ -195,3 +195,3 @@ setData = _useState3[1]; // Use "deep" dependency comparison because params are often not _referentially_ equal, | ||
return { | ||
data, | ||
data: typeof data === 'undefined' ? initialData : data, | ||
loading, | ||
@@ -198,0 +198,0 @@ error |
@@ -1,2 +0,2 @@ | ||
"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}Object.defineProperty(exports,"__esModule",{value:!0});var t=e(require("picosanity")),r=e(require("@sanity/image-url")),n=require("react"),o=e(n),a=require("use-deep-compare-effect"),i=e(require("@sanity/block-content-to-react")),u=e(require("groq"));function c(){return"undefined"==typeof AbortController?{signal:void 0,abort:s}:new AbortController}function s(){}function l(e,t){return fetch("https://"+e+".api.sanity.io/v1/users/me",{credentials:"include",signal:null==t?void 0:t.signal}).then(e=>e.json()).then(e=>(null==e?void 0:e.id)?e:null).catch(e=>"AbortError"===e.name?null:Promise.reject(e))}exports.groq=u,exports.createClient=function(e){return t(e)},exports.createCurrentUserHook=function(e){let t=e.projectId;return()=>function(e){const t=n.useState(),r=t[0],o=t[1],a=n.useState(),i=a[0],u=a[1];return n.useEffect(()=>{const t=c();return l(e,t).then(o).catch(u),()=>t.abort()},[e]),{data:r,error:i,loading:null!==r||!i}}(t)},exports.createImageUrlBuilder=function(e){return r({projectId:e.projectId,dataset:e.dataset})},exports.createPortableTextComponent=function(e){let t=e.projectId,r=e.dataset,n=e.serializers;return function(e){return o.createElement(i,Object.assign({projectId:t,dataset:r,serializers:n},e))}},exports.createPreviewSubscriptionHook=function(e){let t,r=e.projectId,o=e.dataset,i=e.documentLimit,u=void 0===i?3e3:i;return function(e,t){void 0===t&&(t={});const o=t.params;return function(e){const t=e.getStore,r=e.projectId,o=e.query,i=e.params,u=e.initialData,s=e.enabled,d=void 0!==s&&s,f=n.useState(),p=f[0],b=f[1],h=n.useState(!1),m=h[0],v=h[1],g=n.useState(u),j=g[0],y=g[1];return a.useDeepCompareEffectNoCheck(()=>{if(!d)return()=>{};v(!0);const e=c();let n;return l(r,e).then(e=>{if(!e)throw console.warn("Not authenticated - preview not available"),new Error("Not authenticated - preview not available")}).then(t).then(e=>{n=e.subscribe(o,i,(e,t)=>{e?b(e):y(t)})}).catch(b).finally(()=>v(!1)),()=>{n&&n.unsubscribe(),e.abort()}},[t,o,i,d]),{data:j,loading:m,error:p}}({getStore:s,projectId:r,query:e,params:void 0===o?{}:o,initialData:t.initialData,enabled:!!t.enabled&&"undefined"!=typeof window})};function s(){return t||(t=new Promise((function(e){e(function(e){if(e&&e.__esModule)return e;var t={};return e&&Object.keys(e).forEach((function(r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})})),t.default=e,t}(require("@sanity/groq-store")))})).then(e=>(0,e.groqStore)({projectId:r,dataset:o,documentLimit:u,listen:!0,overlayDrafts:!0,subscriptionThrottleMs:10}))),t}}; | ||
"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}Object.defineProperty(exports,"__esModule",{value:!0});var t=e(require("picosanity")),r=e(require("@sanity/image-url")),n=require("react"),o=e(n),i=require("use-deep-compare-effect"),a=e(require("@sanity/block-content-to-react")),u=e(require("groq"));function c(){return"undefined"==typeof AbortController?{signal:void 0,abort:s}:new AbortController}function s(){}function l(e,t){return fetch("https://"+e+".api.sanity.io/v1/users/me",{credentials:"include",signal:null==t?void 0:t.signal}).then(e=>e.json()).then(e=>(null==e?void 0:e.id)?e:null).catch(e=>"AbortError"===e.name?null:Promise.reject(e))}exports.groq=u,exports.createClient=function(e){return t(e)},exports.createCurrentUserHook=function(e){let t=e.projectId;return()=>function(e){const t=n.useState(),r=t[0],o=t[1],i=n.useState(),a=i[0],u=i[1];return n.useEffect(()=>{const t=c();return l(e,t).then(o).catch(u),()=>t.abort()},[e]),{data:r,error:a,loading:null!==r||!a}}(t)},exports.createImageUrlBuilder=function(e){return r({projectId:e.projectId,dataset:e.dataset})},exports.createPortableTextComponent=function(e){let t=e.projectId,r=e.dataset,n=e.serializers;return function(e){return o.createElement(a,Object.assign({projectId:t,dataset:r,serializers:n},e))}},exports.createPreviewSubscriptionHook=function(e){let t,r=e.projectId,o=e.dataset,a=e.documentLimit,u=void 0===a?3e3:a;return function(e,t){void 0===t&&(t={});const o=t.params;return function(e){const t=e.getStore,r=e.projectId,o=e.query,a=e.params,u=e.initialData,s=e.enabled,d=void 0!==s&&s,f=n.useState(),p=f[0],b=f[1],v=n.useState(!1),h=v[0],m=v[1],g=n.useState(),j=g[0],y=g[1];return i.useDeepCompareEffectNoCheck(()=>{if(!d)return()=>{};m(!0);const e=c();let n;return l(r,e).then(e=>{if(!e)throw console.warn("Not authenticated - preview not available"),new Error("Not authenticated - preview not available")}).then(t).then(e=>{n=e.subscribe(o,a,(e,t)=>{e?b(e):y(t)})}).catch(b).finally(()=>m(!1)),()=>{n&&n.unsubscribe(),e.abort()}},[t,o,a,d]),{data:void 0===j?u:j,loading:h,error:p}}({getStore:s,projectId:r,query:e,params:void 0===o?{}:o,initialData:t.initialData,enabled:!!t.enabled&&"undefined"!=typeof window})};function s(){return t||(t=new Promise((function(e){e(function(e){if(e&&e.__esModule)return e;var t={};return e&&Object.keys(e).forEach((function(r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})})),t.default=e,t}(require("@sanity/groq-store")))})).then(e=>(0,e.groqStore)({projectId:r,dataset:o,documentLimit:u,listen:!0,overlayDrafts:!0,subscriptionThrottleMs:10}))),t}}; | ||
//# sourceMappingURL=next-sanity.cjs.production.min.js.map |
@@ -126,3 +126,3 @@ import picoSanity from 'picosanity'; | ||
const _useState3 = useState(initialData), | ||
const _useState3 = useState(), | ||
data = _useState3[0], | ||
@@ -169,3 +169,3 @@ setData = _useState3[1]; // Use "deep" dependency comparison because params are often not _referentially_ equal, | ||
return { | ||
data, | ||
data: typeof data === 'undefined' ? initialData : data, | ||
loading, | ||
@@ -172,0 +172,0 @@ error |
{ | ||
"name": "next-sanity", | ||
"description": "Sanity.io toolkit for Next.js", | ||
"version": "0.1.6", | ||
"version": "0.1.7", | ||
"author": "Sanity.io <hello@sanity.io>", | ||
@@ -6,0 +6,0 @@ "license": "MIT", |
130
README.md
# next-sanity | ||
Sanity.io toolkit for Next.js | ||
[Sanity.io](https://www.sanity.io/?utm_source=github&utm_medium=readme&utm_campaign=next-sanity) toolkit for Next.js. | ||
## Installing | ||
**Features:** | ||
- Client-side live real-time preview for authenticated users | ||
- Light-weight client for fetching data | ||
- URL-helper for Sanity’s image pipeline | ||
- Rich-text component for Portable Text | ||
- GROQ syntax highlighting | ||
## Table of contents | ||
- [Table of contents](#table-of-contents) | ||
- [Installation](#installation) | ||
- [Live real-time preview](#live-real-time-preview) | ||
- [Limits](#limits) | ||
- [Usage](#usage) | ||
- [Example: Minimal blog post template](#example-minimal-blog-post-template) | ||
- [License](#license) | ||
## Installation | ||
```sh | ||
$ npm install next-sanity | ||
// or | ||
$ yarn add next-sanity | ||
``` | ||
## Live real-time preview | ||
You can implement real-time client side preview using `createPreviewSubscriptionHook`. It works by streaming the whole dataset to the browser, which it keeps updated using [listeners](https://www.sanity.io/docs/realtime-updates) and Mendoza patches. When it recieves updates, then the query is run against the client-side datastore using [groq-js](https://github.com/sanity-io/groq-js). This only happens if you're logged in and the hook is configured to run, which means you can use this code in production. | ||
You might want to use Vercel’s approach to previews, which is set up with a serverless functions that takes a preview secret, which in turn redirects you to a page with a `preview` prop set to `true`. | ||
### Limits | ||
The real-time preview isn't optimized and comes with a configured limit of 3000 documents. You can experiment with larger datasets by configuring the hook with `documentLimit: <Integer>`. Be aware that this might significantly affect the preview performance. | ||
We have plans for optimizations in the roadmap. | ||
## Usage | ||
In some file, eg `lib/sanity.js`: | ||
It’s practical to set up a decicated file where you import and set up your client etc. Below is a comprehensive example of the different things you can set up. | ||
```js | ||
// lib/sanity.js | ||
import { | ||
@@ -25,14 +59,39 @@ groq, | ||
const config = { | ||
// Find your project ID and dataset in `sanity.json` in your studio project | ||
/** | ||
* Find your project ID and dataset in `sanity.json` in your studio project. | ||
* These are considered “public”, but you can use environment variables | ||
* if you want differ between local dev and production. | ||
* | ||
* https://nextjs.org/docs/basic-features/environment-variables | ||
**/ | ||
dataset: process.env.NEXT_PUBLIC_SANITY_DATASET || 'production', | ||
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID, | ||
useCdn: process.env.NODE_ENV === 'production', | ||
// useCdn == true gives fast, cheap responses using a globally distributed cache. | ||
// Set this to false if your application require the freshest possible | ||
// data always (potentially slightly slower and a bit more expensive). | ||
/** | ||
* Set useCdn to `false` if your application require the freshest possible | ||
* data always (potentially slightly slower and a bit more expensive). | ||
* Authenticated request (like preview) will always bypass the CDN | ||
**/ | ||
} | ||
export const imageUrlBuilder = createImageUrlBuilder(config) | ||
/** | ||
* Set up a helper function for generating Image URLs with only the asset reference data in your documents. | ||
* Read more: https://www.sanity.io/docs/image-url | ||
**/ | ||
export const urlFor = source => createImageUrlBuilder(config).image(source) | ||
// Set up the live preview subsscription hook | ||
export const usePreviewSubscription = createPreviewSubscriptionHook(config) | ||
// Set up Portable Text serialization | ||
export const PortableText = createPortableTextComponent({ | ||
...config, | ||
// Serializers passed to @sanity/block-content-to-react | ||
// (https://github.com/sanity-io/block-content-to-react) | ||
serializers: {}, | ||
}) | ||
// Set up the client for fetching data in the getProps page functions | ||
export const sanityClient = createClient(config) | ||
// Set up a preview client with serverless authentication for drafts | ||
export const previewClient = createClient({ | ||
@@ -44,19 +103,24 @@ ...config, | ||
// Helper function for easily switching between normal client and preview client | ||
export const getClient = (usePreview) => (usePreview ? previewClient : sanityClient) | ||
export const PortableText = createPortableTextComponent({ | ||
...config, | ||
// Serializers passed to @sanity/block-content-to-react | ||
// (https://github.com/sanity-io/block-content-to-react) | ||
serializers: {}, | ||
}) | ||
// Helper function for using the current logged in user account | ||
export const useCurrentUser = createCurrentUserHook(config) | ||
``` | ||
In a page component, eg `pages/posts/[slug].js`: | ||
## Example: Minimal blog post template | ||
```js | ||
A minimal example for a blog post template using the schema from from the Sanity Studio blog example. Includes the real-time preview using the configuration illustrated above: | ||
```jsx | ||
// pages/posts/[slug].js | ||
import ErrorPage from 'next/error' | ||
import {useRouter} from 'next/router' | ||
import {groq} from 'next-sanity' | ||
import {getClient, PortableText, usePreviewSubscription} from '../../lib/sanity' | ||
import { | ||
getClient, | ||
usePreviewSubscription, | ||
urlFor, | ||
PortableText | ||
} from '../../lib/sanity' | ||
@@ -67,5 +131,8 @@ const postQuery = groq` | ||
title, | ||
excerpt, | ||
content, | ||
coverImage, | ||
body, | ||
mainImage, | ||
categories[]->{ | ||
_id, | ||
title | ||
}, | ||
"slug": slug.current | ||
@@ -87,10 +154,15 @@ } | ||
const {title, mainImage, body} = post | ||
return ( | ||
<div> | ||
<h1>{post.title}</h1> | ||
<p>{post.excerpt}</p> | ||
<div> | ||
<PortableText blocks={post.content || []} /> | ||
</div> | ||
</div> | ||
<article> | ||
<h2>{title}</h2> | ||
<figure> | ||
<img src={urlFor(mainImage).url()}> | ||
</figure> | ||
<PortableText blocks={body} /> | ||
<aside> | ||
</aside> | ||
</article> | ||
) | ||
@@ -124,8 +196,4 @@ } | ||
## Documentation | ||
@todo | ||
## License | ||
MIT-licensed. See LICENSE. |
@@ -65,3 +65,3 @@ import {useState} from 'react' | ||
const [loading, setLoading] = useState(false) | ||
const [data, setData] = useState<R>(initialData) | ||
const [data, setData] = useState<R>() | ||
@@ -113,3 +113,7 @@ // Use "deep" dependency comparison because params are often not _referentially_ equal, | ||
return {data, loading, error} | ||
return { | ||
data: typeof data === 'undefined' ? initialData : data, | ||
loading, | ||
error, | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
60371
627
195