@devite/nuxt-sanity 1.5.2 → 2.0.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.
Files changed (53) hide show
  1. package/README.md +3 -3
  2. package/dist/module.d.mts +62 -14
  3. package/dist/module.d.ts +62 -14
  4. package/dist/module.json +3 -3
  5. package/dist/module.mjs +98 -4
  6. package/dist/runtime/client/DefaultSanityClient.d.ts +15 -0
  7. package/dist/runtime/client/DefaultSanityClient.js +44 -0
  8. package/dist/runtime/client/MinimalSanityClient.d.ts +15 -0
  9. package/dist/runtime/client/MinimalSanityClient.js +59 -0
  10. package/dist/runtime/client/SanityClient.d.ts +10 -0
  11. package/dist/runtime/client/SanityClient.js +7 -0
  12. package/dist/runtime/components/SanityComponent.vue +34 -20
  13. package/dist/runtime/components/SanityImageAsset.vue +9 -5
  14. package/dist/runtime/components/SanityLinkExternal.vue +2 -1
  15. package/dist/runtime/components/SanityLinkInternal.vue +5 -7
  16. package/dist/runtime/components/SanityPage.vue +23 -14
  17. package/dist/runtime/components/SanityRichText.vue +14 -18
  18. package/dist/runtime/composables/useLazySanityQuery.d.ts +4 -0
  19. package/dist/runtime/composables/useLazySanityQuery.js +4 -0
  20. package/dist/runtime/composables/useSanityLiveMode.d.ts +1 -0
  21. package/dist/runtime/composables/useSanityLiveMode.js +16 -0
  22. package/dist/runtime/composables/useSanityQuery.d.ts +30 -0
  23. package/dist/runtime/composables/useSanityQuery.js +69 -0
  24. package/dist/runtime/composables/useSanityVisualEditing.d.ts +8 -0
  25. package/dist/runtime/composables/useSanityVisualEditing.js +44 -0
  26. package/dist/runtime/composables/useSanityVisualEditingState.d.ts +4 -0
  27. package/dist/runtime/composables/useSanityVisualEditingState.js +12 -0
  28. package/dist/runtime/plugins/visual-editing.d.ts +2 -0
  29. package/dist/runtime/plugins/visual-editing.js +30 -0
  30. package/dist/runtime/server/routes/preview/disable.d.ts +2 -0
  31. package/dist/runtime/server/routes/preview/disable.js +6 -0
  32. package/dist/runtime/server/routes/preview/enable.d.ts +2 -0
  33. package/dist/runtime/server/routes/preview/enable.js +20 -0
  34. package/dist/runtime/server/routes/proxy.d.ts +2 -0
  35. package/dist/runtime/server/routes/proxy.js +19 -0
  36. package/dist/runtime/server/tsconfig.json +3 -0
  37. package/dist/runtime/server/utils/useSanityClient.d.ts +3 -0
  38. package/dist/runtime/server/utils/useSanityClient.js +17 -0
  39. package/dist/runtime/utils/getOrCreateSanityClient.d.ts +4 -0
  40. package/dist/runtime/utils/getOrCreateSanityClient.js +15 -0
  41. package/dist/runtime/utils/groq.d.ts +8 -0
  42. package/dist/runtime/utils/groq.js +6 -0
  43. package/dist/runtime/utils/projections.d.ts +4 -4
  44. package/dist/runtime/utils/projections.js +1 -1
  45. package/dist/runtime/utils/resolveImageAssetById.d.ts +2 -2
  46. package/dist/runtime/utils/resolveImageAssetById.js +2 -2
  47. package/dist/runtime/utils/resolveInternalLink.d.ts +2 -2
  48. package/dist/runtime/utils/resolveInternalLink.js +2 -2
  49. package/dist/runtime/utils/useSanityClient.d.ts +2 -0
  50. package/dist/runtime/utils/useSanityClient.js +8 -0
  51. package/dist/types.d.mts +1 -7
  52. package/dist/types.d.ts +1 -7
  53. package/package.json +29 -14
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version][npm-version-src]][npm-version-href]
4
4
 
5
- Provides additional helper components and utilities for the [Nuxt Sanity Module][nuxt-sanity].
5
+ Advanced [Sanity](https://www.sanity.io/) integration for Nuxt.js. Based on the official [@nuxtjs/sanity][nuxt-sanity] module.
6
6
 
7
7
  ## Quick Setup
8
8
 
@@ -12,7 +12,7 @@ Install the module to your Nuxt application with one command:
12
12
  npx nuxi module add @devite/nuxt-sanity
13
13
  ```
14
14
 
15
- That's it! You can now use data from Sanity in your Nuxt app ✨
15
+ That's it! You can now use Sanity with your Nuxt app ✨
16
16
 
17
17
 
18
18
  ## Contribution
@@ -22,7 +22,7 @@ That's it! You can now use data from Sanity in your Nuxt app ✨
22
22
 
23
23
  ```bash
24
24
  # Install dependencies
25
- pnpm install && cd playground/cms && pnpm install && cd -
25
+ pnpm install
26
26
 
27
27
  # Generate type stubs
28
28
  pnpm dev:prepare
package/dist/module.d.mts CHANGED
@@ -1,27 +1,56 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
- import { Image, Slug, PortableTextBlock } from '@sanity/types';
2
+ import { VisualEditingOptions as VisualEditingOptions$1, HistoryRefresh } from '@sanity/visual-editing';
3
+ import { ClientConfig } from '@sanity/client';
4
+ import { Slug, ImageAsset, PortableTextBlock } from '@sanity/types';
3
5
 
4
- interface SEO {
5
- _type: 'seo';
6
- indexable: boolean;
7
- title: string;
8
- shortTitle: string;
9
- description: string;
10
- image?: Image;
6
+ type ModuleOptions = ClientConfig & {
7
+ projectId: string;
8
+ /** @default 'production' */
9
+ dataset: string;
10
+ /** @default false */
11
+ minimalClient?: boolean;
12
+ /** @default true */
13
+ useCdn?: boolean;
14
+ /** @default '2024-08-08' */
15
+ apiVersion?: string;
16
+ visualEditing?: VisualEditingOptions;
17
+ };
18
+ interface VisualEditingOptions {
19
+ /** @default { enable: "/_sanity/preview/enable", disable: "/_sanity/preview/disable" } */
20
+ previewMode?: boolean | {
21
+ enable?: string;
22
+ disable?: string;
23
+ };
24
+ previewModeId?: string;
25
+ /** @default 'live-visual-editing' */
26
+ mode?: 'live-visual-editing' | 'visual-editing' | 'custom';
27
+ /** @default '/_sanity/fetch' */
28
+ proxyEndpoint?: string;
29
+ token?: string;
30
+ studioUrl?: string;
31
+ /** @default true */
32
+ stega?: boolean;
33
+ /** This function is only required if `mode` is set to 'visual-editing' */
34
+ refresh?: SanityVisualEditingRefreshHandler;
35
+ /** @default 100 */
36
+ zIndex?: VisualEditingOptions$1['zIndex'];
11
37
  }
38
+ type SanityVisualEditingRefreshHandler = (payload: HistoryRefresh, refreshDefault: () => false | Promise<void>) => false | Promise<void>;
12
39
 
13
40
  interface Page {
14
41
  _id: string;
15
42
  _type: 'page';
16
43
  title: string;
17
44
  slug: Slug;
18
- modules: Array<object>;
45
+ modules: SanityArray<SanityModule>;
19
46
  seo: SEO;
20
47
  }
21
48
 
22
49
  interface GlobalSEO {
23
50
  siteName: string;
24
- image: Image;
51
+ image: {
52
+ asset: ImageAsset;
53
+ };
25
54
  }
26
55
 
27
56
  interface LinkExternal {
@@ -35,20 +64,39 @@ interface LinkInternal {
35
64
  slug: string;
36
65
  }
37
66
 
67
+ interface SEO {
68
+ _type: 'seo';
69
+ indexable: boolean;
70
+ title: string;
71
+ shortTitle: string;
72
+ description: string;
73
+ image?: {
74
+ asset: ImageAsset;
75
+ };
76
+ }
77
+
38
78
  type RichText = PortableTextBlock[];
39
79
 
40
80
  interface Home {
41
81
  _type: 'home';
42
- modules: Array<object>;
82
+ modules: SanityArray<SanityModule>;
43
83
  seo: SEO;
44
84
  }
45
85
 
46
86
  interface NotFound {
47
87
  _type: 'notFound';
48
- modules: Array<object>;
88
+ modules: SanityArray<SanityModule>;
49
89
  seo: SEO;
50
90
  }
51
91
 
52
- declare const _default: _nuxt_schema.NuxtModule<_nuxt_schema.ModuleOptions, _nuxt_schema.ModuleOptions, false>;
92
+ type SanityModule = {
93
+ _type?: string;
94
+ };
95
+
96
+ type SanityArray<T> = Array<T & {
97
+ _key: string;
98
+ }>;
99
+
100
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
53
101
 
54
- export { type GlobalSEO, type Home, type LinkExternal, type LinkInternal, type NotFound, type Page, type RichText, type SEO, _default as default };
102
+ export { type GlobalSEO, type Home, type LinkExternal, type LinkInternal, type ModuleOptions, type NotFound, type Page, type RichText, type SEO, type SanityArray, type SanityModule, type SanityVisualEditingRefreshHandler, type VisualEditingOptions, _default as default };
package/dist/module.d.ts CHANGED
@@ -1,27 +1,56 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
- import { Image, Slug, PortableTextBlock } from '@sanity/types';
2
+ import { VisualEditingOptions as VisualEditingOptions$1, HistoryRefresh } from '@sanity/visual-editing';
3
+ import { ClientConfig } from '@sanity/client';
4
+ import { Slug, ImageAsset, PortableTextBlock } from '@sanity/types';
3
5
 
4
- interface SEO {
5
- _type: 'seo';
6
- indexable: boolean;
7
- title: string;
8
- shortTitle: string;
9
- description: string;
10
- image?: Image;
6
+ type ModuleOptions = ClientConfig & {
7
+ projectId: string;
8
+ /** @default 'production' */
9
+ dataset: string;
10
+ /** @default false */
11
+ minimalClient?: boolean;
12
+ /** @default true */
13
+ useCdn?: boolean;
14
+ /** @default '2024-08-08' */
15
+ apiVersion?: string;
16
+ visualEditing?: VisualEditingOptions;
17
+ };
18
+ interface VisualEditingOptions {
19
+ /** @default { enable: "/_sanity/preview/enable", disable: "/_sanity/preview/disable" } */
20
+ previewMode?: boolean | {
21
+ enable?: string;
22
+ disable?: string;
23
+ };
24
+ previewModeId?: string;
25
+ /** @default 'live-visual-editing' */
26
+ mode?: 'live-visual-editing' | 'visual-editing' | 'custom';
27
+ /** @default '/_sanity/fetch' */
28
+ proxyEndpoint?: string;
29
+ token?: string;
30
+ studioUrl?: string;
31
+ /** @default true */
32
+ stega?: boolean;
33
+ /** This function is only required if `mode` is set to 'visual-editing' */
34
+ refresh?: SanityVisualEditingRefreshHandler;
35
+ /** @default 100 */
36
+ zIndex?: VisualEditingOptions$1['zIndex'];
11
37
  }
38
+ type SanityVisualEditingRefreshHandler = (payload: HistoryRefresh, refreshDefault: () => false | Promise<void>) => false | Promise<void>;
12
39
 
13
40
  interface Page {
14
41
  _id: string;
15
42
  _type: 'page';
16
43
  title: string;
17
44
  slug: Slug;
18
- modules: Array<object>;
45
+ modules: SanityArray<SanityModule>;
19
46
  seo: SEO;
20
47
  }
21
48
 
22
49
  interface GlobalSEO {
23
50
  siteName: string;
24
- image: Image;
51
+ image: {
52
+ asset: ImageAsset;
53
+ };
25
54
  }
26
55
 
27
56
  interface LinkExternal {
@@ -35,20 +64,39 @@ interface LinkInternal {
35
64
  slug: string;
36
65
  }
37
66
 
67
+ interface SEO {
68
+ _type: 'seo';
69
+ indexable: boolean;
70
+ title: string;
71
+ shortTitle: string;
72
+ description: string;
73
+ image?: {
74
+ asset: ImageAsset;
75
+ };
76
+ }
77
+
38
78
  type RichText = PortableTextBlock[];
39
79
 
40
80
  interface Home {
41
81
  _type: 'home';
42
- modules: Array<object>;
82
+ modules: SanityArray<SanityModule>;
43
83
  seo: SEO;
44
84
  }
45
85
 
46
86
  interface NotFound {
47
87
  _type: 'notFound';
48
- modules: Array<object>;
88
+ modules: SanityArray<SanityModule>;
49
89
  seo: SEO;
50
90
  }
51
91
 
52
- declare const _default: _nuxt_schema.NuxtModule<_nuxt_schema.ModuleOptions, _nuxt_schema.ModuleOptions, false>;
92
+ type SanityModule = {
93
+ _type?: string;
94
+ };
95
+
96
+ type SanityArray<T> = Array<T & {
97
+ _key: string;
98
+ }>;
99
+
100
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
53
101
 
54
- export { type GlobalSEO, type Home, type LinkExternal, type LinkInternal, type NotFound, type Page, type RichText, type SEO, _default as default };
102
+ export { type GlobalSEO, type Home, type LinkExternal, type LinkInternal, type ModuleOptions, type NotFound, type Page, type RichText, type SEO, type SanityArray, type SanityModule, type SanityVisualEditingRefreshHandler, type VisualEditingOptions, _default as default };
package/dist/module.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@devite/nuxt-sanity",
3
- "configKey": "@devite/nuxt-sanity",
4
- "version": "1.5.2",
3
+ "version": "2.0.0",
4
+ "configKey": "sanity",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "0.8.4",
7
- "unbuild": "unknown"
7
+ "unbuild": "2.0.0"
8
8
  }
9
9
  }
package/dist/module.mjs CHANGED
@@ -1,14 +1,108 @@
1
- import { defineNuxtModule, createResolver, addComponentsDir, addImportsDir } from '@nuxt/kit';
1
+ import crypto from 'node:crypto';
2
+ import { defineNuxtModule, createResolver, addPlugin, addServerHandler, addImportsDir, addComponentsDir } from '@nuxt/kit';
3
+ import defu from 'defu';
4
+
5
+ const name = "@devite/nuxt-sanity";
6
+ const version = "2.0.0";
2
7
 
3
8
  const module = defineNuxtModule({
4
9
  meta: {
5
- name: "@devite/nuxt-sanity"
10
+ name,
11
+ version,
12
+ configKey: "sanity"
6
13
  },
7
- async setup(_options, _nuxt) {
14
+ defaults: {},
15
+ async setup(options, nuxt) {
8
16
  const { resolve } = createResolver(import.meta.url);
17
+ const moduleConfig = defu(nuxt.options.runtimeConfig.public.sanity, {
18
+ projectId: options.projectId,
19
+ dataset: options.dataset || "production",
20
+ minimalClient: options.minimalClient || false,
21
+ useCdn: options.useCdn || true,
22
+ apiVersion: options.apiVersion || "2024-08-08",
23
+ visualEditing: options.visualEditing || null
24
+ });
25
+ if (options.visualEditing) {
26
+ const previewMode = moduleConfig.visualEditing.previewMode !== false;
27
+ const visualEditingConfig = defu(moduleConfig.visualEditing, {
28
+ mode: "live-visual-editing",
29
+ previewMode: previewMode ? defu(moduleConfig.visualEditing.previewMode, {
30
+ enable: "/_sanity/preview/enable",
31
+ disable: "/_sanity/preview/disable"
32
+ }) : false,
33
+ previewModeId: previewMode ? crypto.randomBytes(16).toString("hex") : "",
34
+ proxyEndpoint: "/_sanity/fetch",
35
+ stega: true,
36
+ zIndex: 100,
37
+ token: ""
38
+ });
39
+ if (!moduleConfig.visualEditing.token?.length)
40
+ console.warn('Visual editing requires a token with "read" access');
41
+ if (!visualEditingConfig.studioUrl)
42
+ console.warn("Visual editing requires a studio URL");
43
+ if (visualEditingConfig.mode === "live-visual-editing" && !visualEditingConfig.stega)
44
+ console.warn('Visual Editing requires "stega" to be enabled in "live-visual-editing" mode');
45
+ nuxt.options.build.transpile.push(
46
+ "async-cache-dedupe",
47
+ "@sanity/core-loader",
48
+ "@sanity/preview-url-secret"
49
+ );
50
+ nuxt.options.vite.resolve = defu(nuxt.options.vite.resolve, {
51
+ dedupe: ["@sanity/client"]
52
+ });
53
+ nuxt.options.vite.optimizeDeps = defu(nuxt.options.vite.optimizeDeps, {
54
+ include: [
55
+ `${name} > @sanity/visual-editing > @sanity/mutate > lodash/groupBy.js`,
56
+ `${name} > @sanity/visual-editing > react`,
57
+ `${name} > @sanity/visual-editing > react/jsx-runtime`,
58
+ `${name} > @sanity/visual-editing > react-dom`,
59
+ `${name} > @sanity/visual-editing > react-dom/client`,
60
+ `${name} > @sanity/visual-editing > react-compiler-runtime`,
61
+ "@sanity/client"
62
+ ]
63
+ });
64
+ addPlugin({ src: resolve("runtime/plugins/visual-editing") });
65
+ if (previewMode) {
66
+ addServerHandler({
67
+ method: "get",
68
+ route: visualEditingConfig.previewMode.enable,
69
+ handler: resolve("runtime/server/routes/preview/enable")
70
+ });
71
+ addServerHandler({
72
+ method: "get",
73
+ route: visualEditingConfig.previewMode.disable,
74
+ handler: resolve("runtime/server/routes/preview/disable")
75
+ });
76
+ }
77
+ addServerHandler({
78
+ method: "post",
79
+ route: visualEditingConfig.proxyEndpoint,
80
+ handler: resolve("runtime/server/routes/proxy")
81
+ });
82
+ moduleConfig.visualEditing = visualEditingConfig;
83
+ }
84
+ nuxt.options.runtimeConfig.sanity = moduleConfig;
85
+ nuxt.options.runtimeConfig.public.sanity = defu(nuxt.options.runtimeConfig.public.sanity, {
86
+ projectId: moduleConfig.projectId,
87
+ dataset: moduleConfig.dataset,
88
+ minimalClient: moduleConfig.minimalClient,
89
+ useCdn: moduleConfig.useCdn,
90
+ apiVersion: moduleConfig.apiVersion,
91
+ perspective: "raw",
92
+ /* Visual Editing */
93
+ token: options.token || "",
94
+ withCredentials: options.withCredentials || false,
95
+ stega: moduleConfig.visualEditing && moduleConfig.visualEditing.stega !== false && moduleConfig.visualEditing.previewMode !== false && { enabled: true, studioUrl: moduleConfig.visualEditing.studioUrl } || {},
96
+ visualEditing: moduleConfig.visualEditing
97
+ });
98
+ addImportsDir(resolve("runtime/client"));
99
+ addImportsDir(resolve("runtime/composables"));
100
+ addImportsDir(resolve("runtime/utils/groq"));
101
+ addImportsDir(resolve("runtime/utils/projections"));
102
+ addImportsDir(resolve("runtime/utils/resolveImageAssetById"));
103
+ addImportsDir(resolve("runtime/utils/resolveInternalLink"));
9
104
  await addComponentsDir({ path: resolve("runtime/components") });
10
105
  await addComponentsDir({ path: "~/sanity", global: true, prefix: "Sanity" });
11
- addImportsDir(resolve("runtime/utils"));
12
106
  }
13
107
  });
14
108
 
@@ -0,0 +1,15 @@
1
+ import { type ClientPerspective, type FilteredResponseQueryOptions, type QueryParams, type SanityClient as SanityClientType } from '@sanity/client';
2
+ import type { ModuleOptions } from '@devite/nuxt-sanity';
3
+ import { type QueryStore } from '@sanity/core-loader';
4
+ import SanityClient from './SanityClient.js';
5
+ declare class DefaultSanityClient extends SanityClient {
6
+ readonly client: SanityClientType;
7
+ queryStore: QueryStore | null;
8
+ constructor(config: ModuleOptions);
9
+ fetch<T = unknown>(query: string, params: QueryParams, options?: {
10
+ perspective?: ClientPerspective;
11
+ } & FilteredResponseQueryOptions): Promise<T>;
12
+ createQueryStore(tag?: string): void;
13
+ clone(): DefaultSanityClient;
14
+ }
15
+ export default DefaultSanityClient;
@@ -0,0 +1,44 @@
1
+ import {
2
+ createClient
3
+ } from "@sanity/client";
4
+ import { createQueryStore as createCoreQueryStore } from "@sanity/core-loader";
5
+ import SanityClient from "./SanityClient.js";
6
+ class DefaultSanityClient extends SanityClient {
7
+ client;
8
+ queryStore = null;
9
+ constructor(config) {
10
+ super(config);
11
+ this.client = createClient(config);
12
+ }
13
+ async fetch(query, params, options) {
14
+ return await this.client.fetch(query, params, options);
15
+ }
16
+ createQueryStore(tag) {
17
+ const queryStore = createCoreQueryStore({
18
+ tag: tag || "nuxt-loader",
19
+ client: false,
20
+ ssr: true
21
+ });
22
+ if (import.meta.server) {
23
+ const serverClient = this.client.withConfig({
24
+ perspective: "previewDrafts",
25
+ token: this.config.token,
26
+ useCdn: false
27
+ });
28
+ queryStore.setServerClient(serverClient);
29
+ }
30
+ this.queryStore = queryStore;
31
+ }
32
+ clone() {
33
+ return new DefaultSanityClient({
34
+ useCdn: this.config.useCdn,
35
+ projectId: this.config.projectId,
36
+ dataset: this.config.dataset,
37
+ apiVersion: this.config.apiVersion,
38
+ withCredentials: this.config.withCredentials,
39
+ token: this.config.token,
40
+ perspective: this.config.perspective
41
+ });
42
+ }
43
+ }
44
+ export default DefaultSanityClient;
@@ -0,0 +1,15 @@
1
+ import type { ClientPerspective, FilteredResponseQueryOptions, QueryParams } from '@sanity/client';
2
+ import type { ModuleOptions } from '@devite/nuxt-sanity';
3
+ import SanityClient from './SanityClient.js';
4
+ declare class MinimalSanityClient extends SanityClient {
5
+ private readonly queryPath;
6
+ private readonly fetchOptions;
7
+ constructor(config: ModuleOptions);
8
+ private getByteLength;
9
+ private toQueryString;
10
+ fetch<T>(query: string, params: QueryParams, _options?: {
11
+ perspective?: ClientPerspective;
12
+ } & FilteredResponseQueryOptions): Promise<T>;
13
+ clone(): MinimalSanityClient;
14
+ }
15
+ export default MinimalSanityClient;
@@ -0,0 +1,59 @@
1
+ import { $fetch } from "ofetch";
2
+ import SanityClient from "./SanityClient.js";
3
+ const API_HOST = "api.sanity.io";
4
+ const API_CDN_HOST = "apicdn.sanity.io";
5
+ class MinimalSanityClient extends SanityClient {
6
+ queryPath;
7
+ fetchOptions;
8
+ constructor(config) {
9
+ super({
10
+ ...config,
11
+ perspective: config.perspective || "raw",
12
+ useCdn: config.perspective === "previewDrafts" ? false : config.useCdn
13
+ });
14
+ this.queryPath = `/v${config.apiVersion}/data/query/${config.dataset}`;
15
+ this.fetchOptions = {
16
+ headers: {
17
+ ...config.token ? { Authorization: `Bearer ${config.token}` } : {},
18
+ Accept: "application/json",
19
+ ...import.meta.server ? { "accept-encoding": "gzip, deflate" } : {}
20
+ }
21
+ };
22
+ if (import.meta.client) {
23
+ this.fetchOptions.credentials = config.withCredentials ? "include" : "omit";
24
+ }
25
+ }
26
+ getByteLength(query) {
27
+ return encodeURI(query).split(/%..|./).length;
28
+ }
29
+ toQueryString(query, params) {
30
+ const baseQueryStr = `?query=${encodeURIComponent(query)}`;
31
+ return Object.keys(params).reduce((acc, paramName) => {
32
+ return acc + `&${encodeURIComponent(`$${paramName}`)}=${encodeURIComponent(JSON.stringify(params[paramName]))}`;
33
+ }, baseQueryStr);
34
+ }
35
+ async fetch(query, params, _options) {
36
+ const perspectiveQueryString = `&perspective=${_options?.perspective || this.config.perspective}`;
37
+ const queryString = this.toQueryString(query, params || {}) + perspectiveQueryString;
38
+ const byteLength = this.getByteLength(queryString);
39
+ const isEligibleForGetRequest = byteLength <= 9e3;
40
+ const queryHost = this.config.useCdn && isEligibleForGetRequest ? API_CDN_HOST : API_HOST;
41
+ return (await $fetch(`https://${this.config.projectId}.${queryHost + this.queryPath}${queryString}`, {
42
+ ...this.fetchOptions,
43
+ method: isEligibleForGetRequest ? "GET" : "POST",
44
+ body: !isEligibleForGetRequest ? { query, params } : void 0
45
+ })).result;
46
+ }
47
+ clone() {
48
+ return new MinimalSanityClient({
49
+ useCdn: this.config.useCdn,
50
+ projectId: this.config.projectId,
51
+ dataset: this.config.dataset,
52
+ apiVersion: this.config.apiVersion,
53
+ withCredentials: this.config.withCredentials,
54
+ token: this.config.token,
55
+ perspective: this.config.perspective
56
+ });
57
+ }
58
+ }
59
+ export default MinimalSanityClient;
@@ -0,0 +1,10 @@
1
+ import type { ClientPerspective, ContentSourceMap, FilteredResponseQueryOptions, QueryParams } from '@sanity/client';
2
+ import type { ModuleOptions } from '@devite/nuxt-sanity';
3
+ export default abstract class SanityClient {
4
+ config: ModuleOptions;
5
+ sourceMap: ContentSourceMap | undefined;
6
+ protected constructor(config: ModuleOptions);
7
+ abstract fetch<T = unknown>(query: string, params: QueryParams, options?: {
8
+ perspective?: ClientPerspective;
9
+ } & FilteredResponseQueryOptions): Promise<T>;
10
+ }
@@ -0,0 +1,7 @@
1
+ export default class SanityClient {
2
+ config;
3
+ sourceMap = void 0;
4
+ constructor(config) {
5
+ this.config = config;
6
+ }
7
+ }
@@ -5,33 +5,47 @@
5
5
  ref="componentRef"
6
6
  v-bind="{ ...$props, ...$attrs }"
7
7
  >
8
- <slot />
8
+ <template
9
+ v-for="(_, slotName) in $slots"
10
+ #[slotName]="slotProps"
11
+ >
12
+ <slot
13
+ :name="slotName"
14
+ v-bind="slotProps ?? {}"
15
+ />
16
+ </template>
9
17
  </component>
10
18
  </template>
11
19
 
12
20
  <script setup lang="ts">
13
- import type { Component } from '@nuxt/schema'
14
- import { computed, ref, resolveComponent } from '#imports'
15
- import { SanityLinkExternal, SanityLinkInternal, SanityRichText } from '#components'
16
-
17
- const { data } = defineProps<{ data?: object }>()
18
-
19
- const component = computed<Component>(() => {
20
- const type = data?._type
21
-
22
- switch (type) {
23
- case 'linkInternal':
24
- return SanityLinkInternal
25
- case 'linkExternal':
26
- return SanityLinkExternal
27
- default:
28
- if (data?.constructor.name === 'Array' && data.every((item) => item._type === 'block'))
29
- return SanityRichText
30
- else if (type) {
21
+ import { type Component, computed, ref, resolveComponent } from 'vue'
22
+ import type { SanityModule } from '@devite/nuxt-sanity'
23
+ import { SanityImageAsset, SanityLinkExternal, SanityLinkInternal, SanityRichText } from '#components'
24
+
25
+ const { data } = defineProps<{ data?: SanityModule | Array<SanityModule> }>()
26
+
27
+ const component = computed<Component | null>(() => {
28
+ if (Array.isArray(data) && data.every((item) => item._type === 'block')) {
29
+ return SanityRichText
30
+ }
31
+
32
+ if (data && typeof data === 'object' && '_type' in data) {
33
+ const type = data._type as string
34
+
35
+ switch (type) {
36
+ case 'linkInternal':
37
+ return SanityLinkInternal
38
+ case 'linkExternal':
39
+ return SanityLinkExternal
40
+ case 'sanity.imageAsset':
41
+ return SanityImageAsset
42
+ default: {
31
43
  const upperCamelCase = type.charAt(0).toUpperCase() + type.slice(1)
44
+ const resolvedComponent = resolveComponent('Sanity' + upperCamelCase)
32
45
 
33
- return resolveComponent('Sanity' + upperCamelCase)
46
+ return resolvedComponent ? (resolvedComponent as Component) : null
34
47
  }
48
+ }
35
49
  }
36
50
 
37
51
  return null
@@ -6,7 +6,7 @@
6
6
  :width="imageAsset.metadata.dimensions.width"
7
7
  :height="imageAsset.metadata.dimensions.height"
8
8
  :alt="imageAsset.altText"
9
- :placeholder="imageAsset.metadata.lqip"
9
+ :placeholder="loading === 'eager' ? undefined : imageAsset.metadata.lqip"
10
10
  :loading="loading"
11
11
  :format="imageAsset.mimeType === 'image/svg+xml' ? undefined : 'webp'"
12
12
  draggable="false"
@@ -15,10 +15,14 @@
15
15
 
16
16
  <script setup lang="ts">
17
17
  import type { ImageAsset, Reference } from '@sanity/types'
18
- import { type Ref, resolveImageAssetById } from '#imports'
18
+ import type { Ref } from 'vue'
19
+ import { resolveImageAssetById } from '../utils/resolveImageAssetById'
19
20
 
20
- const { asset, loading = 'lazy' } = defineProps<{ asset?: ImageAsset | Reference, loading?: 'lazy' | 'eager' }>()
21
- const imageAsset: Ref<ImageAsset | undefined> | ImageAsset | undefined = asset?._ref
21
+ const { asset, loading = 'lazy' } = defineProps<{
22
+ asset?: ImageAsset | Reference
23
+ loading?: 'eager' | 'lazy'
24
+ }>()
25
+ const imageAsset: Ref<ImageAsset | null> | ImageAsset | undefined = asset?._ref
22
26
  ? await resolveImageAssetById((asset as Reference)._ref)
23
- : asset as (ImageAsset | undefined)
27
+ : (asset as ImageAsset | undefined)
24
28
  </script>
@@ -1,7 +1,8 @@
1
1
  <template>
2
2
  <NuxtLink
3
3
  :to="data.url"
4
- :options="{ external: true, target: data.newWindow ? '_blank' : null }"
4
+ :target="data.newWindow ? '_blank' : '_self'"
5
+ external
5
6
  >
6
7
  <slot />
7
8
  </NuxtLink>
@@ -1,19 +1,17 @@
1
1
  <template>
2
- <NuxtLink
3
- v-if="resolvedLink"
4
- :to="resolvedLink.slug"
5
- >
2
+ <NuxtLink :to="resolvedLink?.slug">
6
3
  <slot />
7
4
  </NuxtLink>
8
5
  </template>
9
6
 
10
7
  <script setup lang="ts">
11
- import type { LinkInternal } from '@devite/nuxt-sanity'
12
8
  import type { Reference } from '@sanity/types'
13
- import { type Ref, resolveInternalLink } from '#imports'
9
+ import type { LinkInternal } from '@devite/nuxt-sanity'
10
+ import type { Ref } from 'vue'
11
+ import { resolveInternalLink } from '../utils/resolveInternalLink'
14
12
 
15
13
  const { data } = defineProps<{ data: LinkInternal | { reference: Reference } }>()
16
- const resolvedLink: Ref<LinkInternal | undefined> | LinkInternal = 'reference' in data
14
+ const resolvedLink: Ref<LinkInternal | null> | LinkInternal = 'reference' in data
17
15
  ? await resolveInternalLink(data.reference)
18
16
  : data as LinkInternal
19
17
  </script>