svelte-portabletext icon indicating copy to clipboard operation
svelte-portabletext copied to clipboard

Passing non-Sanity props to custom components

Open rscheuer opened this issue 3 years ago • 2 comments

In the react docs, it seems possible to render custom components with external props, as seen here in the docs :

const components = {
  types: {
    code: props => (
      <pre data-language={props.node.language}>
        <code>{props.node.code}</code>
      </pre>
    )
  }
}

However, in the svelte implementation, the docs suggest that we just pass the name of the Svelte component in the serializer:

<script>
   let page={
      interviewName: "Ryan"
   }
</script>

<PortableText
    value={value}
    components={{
    types: {
        image: ImageBlock,
        doubleImage: DoubleImage,
        story: Story,
        interview: <InterviewItem name={page.interviewName} />,  // What I'd like to do.
    },
    marks: {
        link: Link,
    },
    block:{
        normal: ArticleText,
    }
    }}
/>

I'd like to be able to pass external props (in this case from the field's parent document) into a PortableText block. So far, I'm able to get by with Svelte stores, but it feels more like a workaround.

rscheuer avatar Aug 04 '22 19:08 rscheuer

Running into the exact same "problem"! +1

multiplehats avatar Aug 30 '22 09:08 multiplehats

Actually @rscheuer , I just found out this is possible by first looking through the source code, and then the documentation.

See this reference: https://github.com/portabletext/svelte-portabletext/blob/35511cf7043aeb529bad8d2080c7e26b4241bca8/README.md#customizing-rendering

Here's my code:

<script lang="ts">
	import { PortableText } from '@portabletext/svelte';
	import type { InputValue } from '@portabletext/svelte/ptTypes';
	import Block from './Blocks/Block.svelte';
	import BlockImage from './Blocks/BlockImage.svelte';
	import BlockHeadings from './Blocks/BlockHeadings.svelte';
	import AnnotationLinkExternal from './Annotations/AnnotationLinkExternal.svelte';
	import AnnotationLinkInternal from './Annotations/AnnotationLinkInternal.svelte';
	import AnnotationLinkEmail from './Annotations/AnnotationLinkEmail.svelte';
	import NormalListItem from './ListItem/NormalListItem.svelte';

	export let blocks: InputValue;
	export let isBlog = false;
</script>

<div {...$$restProps}>
	<PortableText
		context={{ isBlog }}
		components={{
			types: {
				blockImage: BlockImage,
			},
			marks: {
				annotationLinkExternal: AnnotationLinkExternal,
				annotationLinkInternal: AnnotationLinkInternal,
				annotationLinkEmail: AnnotationLinkEmail,
			},
			listItem: {
				normal: NormalListItem,
			},
			block: {
				normal: Block,
				h2: BlockHeadings,
				h3: BlockHeadings,
				h4: BlockHeadings,
			},
		}}
		value={blocks}
	/>
</div>

Then in the Block.svelte, you can access portableText.

<script lang="ts">
	import type { BlockComponentProps } from '@portabletext/svelte';

	export let portableText: BlockComponentProps<{ _key: string; style: string }>;

	$: console.log(portableText,global.context.isBlog);
</script>

<p class="relative mb-3 text-lg font-normal leading-7"><slot /></p>

multiplehats avatar Aug 30 '22 09:08 multiplehats