Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 28 additions & 17 deletions src/runtime/components/sanity-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const validAttrs = [
'charset',
'checked',
'cite',
'class',
'cols',
'colspan',
'command',
Expand Down Expand Up @@ -107,9 +108,13 @@ function findSerializer (item: Block | undefined, serializers: Required<Serializ
return item?._type ? serializers.types[item._type] || serializers.marks[item._type] : undefined
}

function renderStyle ({ style, listItem }: Block, serializers: Required<Serializers>, children?: () => Children) {
if (!listItem && style && serializers.styles[style]) {
return h(serializers.styles[style] as any, null, isVue2 ? children?.() : { default: children })
function renderStyle (item: Block, serializers: Required<Serializers>, children?: () => Children) {
const serializer = item.style && serializers.styles[item.style]
const isElement = typeof serializer === 'string'
const props = extractProps(item, isElement)

if (!item.listItem && item.style && serializer) {
return h(serializer as any, props, isVue2 ? children?.() : { default: children })
}

return children?.()
Expand Down Expand Up @@ -176,13 +181,7 @@ function render (serializers: Required<Serializers>, item?: Block, children?: ()
}

const isElement = typeof serializer === 'string'
const props = Object.fromEntries(Object.entries(item).filter(([key]) => key !== '_type').map(
([key, value]) => {
if (key === '_key') return ['key', value || null]
if (!isElement || validAttrs.includes(key)) return [key, value]
return []
},
))
const props = extractProps(item, isElement)

// Forgive me, TypeScript gods...
if (isElement) {
Expand All @@ -192,11 +191,25 @@ function render (serializers: Required<Serializers>, item?: Block, children?: ()
return h(serializer, props, isVue2 ? children?.() : { default: () => children?.() })
}

function extractProps (item: Block, isElement: boolean) {
return Object.fromEntries(
Object.entries(item)
.filter(([key]) => key !== '_type' && key !== 'markDefs')
.map(
([key, value]) => {
if (key === '_key') return ['key', value || null]
if (!isElement || validAttrs.includes(key)) return [key, value]
return []
},
),
)
}

function renderBlocks (blocks: Array<Block>, serializers: Required<Serializers>) {
return blocks.map((block) => {
const node = renderStyle(block, serializers, () => renderInSerializer(block, serializers))
if (process.env.NODE_ENV === 'development' && (!node || (Array.isArray(node) && !node.length))) {
// eslint-disable-next-line no-console
// eslint-disable-next-line no-console
console.warn(`No serializer found for block type "${block._type}".`, block)
}
return node
Expand Down Expand Up @@ -243,15 +256,13 @@ const createListSerializer = (serializers: Required<Serializers>) => {
if (props.level > 1) {
return h(serializers.listItem as string || 'li', [h(isOrdered ? 'ol' : 'ul', {}, isVue2
? renderBlocks(props.children, serializers)
: {
default: () => renderBlocks(props.children, serializers),
})])
: { default: () => renderBlocks(props.children, serializers) },
)])
}
return h(isOrdered ? 'ol' : 'ul', {}, isVue2
? renderBlocks(props.children, serializers)
: {
default: () => renderBlocks(props.children, serializers),
})
: { default: () => renderBlocks(props.children, serializers) },
)
}
},
})
Expand Down
5 changes: 5 additions & 0 deletions test/unit/__snapshots__/sanity-content.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,9 @@ exports[`SanityContent > should render nestedList blocks 1`] = `

exports[`SanityContent > should render strong blocks 1`] = `"<p>An example of <strong>bold</strong> text and <strong>another</strong>.</p>"`;

exports[`SanityContent > should render textWithProps blocks 1`] = `
"<div>hello worldI’m a heading!</div>
<blockquote class=\\"blockquote\\">Build your next Vue.js application with confidence using <a href=\\"https://nuxtjs.org\\">NuxtJS</a>. An open source framework making web development simple and powerful.</blockquote>"
`;

exports[`SanityContent > should render with no props 1`] = `""`;
1 change: 1 addition & 0 deletions test/unit/fixture/portable-text/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export * from './mark-defs'
export * from './nested-list'
export * from './nested-list-2'
export * from './strong'
export * from './text-with-props'

export const link = {
_type: 'link',
Expand Down
51 changes: 51 additions & 0 deletions test/unit/fixture/portable-text/text-with-props.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
export const textWithProps = [
{
_key: 'd810da8ac842',
_type: 'block',
exampleProp: 'hello world',
children: [
{
_key: 'd810da8ac8450',
_type: 'span',
marks: [],
text: 'I’m a heading!',
},
],
style: 'customStyle1',
},
{
_key: 'd810da8ac843',
_type: 'block',
class: 'blockquote',
children: [
{
_key: 'd810da8ac8450',
_type: 'span',
marks: [],
text: 'Build your next Vue.js application with confidence using ',
},
{
_key: 'd810da8ac8451',
_type: 'span',
marks: [
'c9c6224401ba',
],
text: 'NuxtJS',
},
{
_key: 'd810da8ac8452',
_type: 'span',
marks: [],
text: '. An open source framework making web development simple and powerful.',
},
],
markDefs: [
{
_key: 'c9c6224401ba',
_type: 'link',
href: 'https://nuxtjs.org',
},
],
style: 'blockquote',
},
]
3 changes: 3 additions & 0 deletions test/unit/sanity-content.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ describe('SanityContent', () => {
loader: () => Promise.resolve(CustomBlockComponent),
}),
},
styles: {
customStyle1: CustomBlockComponent,
},
}),
},
})
Expand Down