|
1 | 1 | ## Global helper |
2 | 2 |
|
3 | | -This module defines a global `<SanityContent>` component that can turn portable text into HTML. It is a lightweight functional component without an instance. |
| 3 | +This module defines a global `<SanityContent>` component that can turn [portable text](https://www.sanity.io/guides/beginners-guide-to-portable-text) into HTML. It is a lightweight functional component without an instance. |
4 | 4 |
|
5 | | -::alert{icon=💡} |
6 | | -If you want to use the same serializers in multiple places, consider creating your own component (e.g. `<MySanityContent>` which wraps SanityContent, but with your default serializers. By creating `~/components/MySanityContent.vue` you should be able to use this everywhere in your app without importing it. |
| 5 | +As of v2, `<SanityContent>` uses [`@portabletext/vue`](https://github.com/portabletext/vue-portabletext) for rendering portable text. This means features and properties available to `@portabletext/vue` also work with `<SanityContent>`. Please refer to their [Usage guide](https://github.com/portabletext/vue-portabletext?tab=readme-ov-file#basic-usage) for advanced configuration options. |
| 6 | + |
| 7 | +::warning |
| 8 | +This render change introduces **breaking changes** for `<SanityContent>` v2 components. Refer to the following upgrade guide: |
| 9 | +* To reflect `@portabletext/vue`'s props, `blocks` → `value` and `serializers` → `components` attribute name changes have been made. The property types remain the same. |
| 10 | +* Custom components now receive their data nested within a `props.value` object. When defining components, you need to extract your props from this structure using object spreading: `{...props.value}`. This applies to all component types (blocks, marks, styles). |
7 | 11 | :: |
8 | 12 |
|
9 | 13 | ### Example |
10 | 14 |
|
11 | 15 | ```vue |
12 | 16 | <template> |
13 | | - <SanityContent :blocks="content" /> |
| 17 | + <SanityContent :value="content" /> |
14 | 18 | </template> |
15 | 19 | ``` |
16 | 20 |
|
17 | | -### Example with custom serializers |
| 21 | +### Example with custom components |
18 | 22 |
|
19 | 23 | ```vue |
20 | 24 | <template> |
21 | | - <SanityContent :blocks="content" :serializers="serializers" /> |
| 25 | + <SanityContent :value="content" :components="components" /> |
22 | 26 | </template> |
23 | 27 |
|
24 | 28 | <script setup> |
| 29 | +import { defineAsyncComponent, h, resolveComponent } from 'vue' |
25 | 30 | import CustomBlockComponent from '~/components/CustomBlockComponent.vue' |
26 | | -import { resolveComponent } from 'vue' |
27 | 31 |
|
28 | | -const serializers = { |
| 32 | +const components = { |
29 | 33 | types: { |
30 | 34 | // This is how to access a component registered by `@nuxt/components` |
31 | | - lazyRegisteredComponent: resolveComponent('LazyCustomSerializer'), |
| 35 | + lazyRegisteredComponent: props => h(resolveComponent('LazyCustomSerializer'), { |
| 36 | + ...props.value, |
| 37 | + }), |
32 | 38 | // A directly imported component |
33 | | - importedComponent: CustomBlockComponent, |
| 39 | + importedComponent: props => h(CustomBlockComponent, { |
| 40 | + ...props.value, |
| 41 | + }), |
34 | 42 | // Example of a more complex async component |
35 | | - dynamicComponent: defineAsyncComponent({ |
| 43 | + dynamicComponent: props => h(defineAsyncComponent({ |
36 | 44 | loadingComponent: () => 'Loading...', |
37 | 45 | loader: () => import('~/other/component.vue'), |
| 46 | + }), { |
| 47 | + ...props.value, |
38 | 48 | }), |
39 | 49 | }, |
40 | 50 | marks: { |
41 | | - // You can also just pass a string for a custom serializer if it's an HTML element |
42 | | - internalLink: 'a' |
| 51 | + // Custom marks handling |
| 52 | + internalLink: props => h('a', { href: props.value.href }, props.text) |
43 | 53 | } |
44 | 54 | } |
45 | 55 | </script> |
46 | 56 | ``` |
47 | 57 |
|
| 58 | +::warning |
| 59 | +If you want to use the same components in multiple places, consider creating your own component (e.g. `<MySanityContent>`) which wraps SanityContent with your default components. By creating `~/components/MySanityContent.vue` you should be able to use this everywhere in your app without importing it. |
| 60 | +:: |
| 61 | + |
| 62 | +### Advanced Props |
| 63 | + |
| 64 | +The `SanityContent` component accepts all props from `@portabletext/vue`: |
| 65 | + |
| 66 | +```vue |
| 67 | +<template> |
| 68 | + <SanityContent |
| 69 | + :value="content" |
| 70 | + :components="components" |
| 71 | + :onMissingComponent="handleMissingComponent" |
| 72 | + :listNestingMode="'html'" |
| 73 | + /> |
| 74 | +</template> |
| 75 | +
|
| 76 | +<script setup> |
| 77 | +const handleMissingComponent = (message, options) => { |
| 78 | + console.warn(`Missing component: ${options.type} (${options.nodeType})`) |
| 79 | +} |
| 80 | +</script> |
| 81 | +``` |
| 82 | + |
48 | 83 | ## Other resources |
49 | 84 |
|
50 | | -- [sanity-blocks-vue-component](https://github.com/rdunk/sanity-blocks-vue-component){ .text-primary-500 } |
| 85 | +- [@portabletext/vue](https://github.com/portabletext/vue-portabletext){ .text-primary-500 } |
0 commit comments