Skip to content

Commit 0b18069

Browse files
committed
fix: rework nested list handling
resolves #266
1 parent 8a5b918 commit 0b18069

File tree

3 files changed

+267
-16
lines changed

3 files changed

+267
-16
lines changed

src/runtime/components/sanity-content.ts

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ const validAttrs = [
100100
]
101101

102102
function findSerializer (item: Block | undefined, serializers: Required<Serializers>): Serializer | undefined {
103-
if (item?.listItem) {
103+
if (item?.listItem && item._type !== 'list') {
104104
return serializers.listItem || 'li'
105105
}
106106

@@ -141,26 +141,32 @@ function renderMarks (
141141

142142
function walkList (blocks: Array<Block>, block: Block) {
143143
// Not a list item
144-
if (!block.level) {
144+
if (!block.listItem) {
145145
blocks.push(block)
146146
return blocks
147147
}
148148

149-
const { _type, children, level } = blocks[blocks.length - 1] || {}
150-
if (_type === 'list' && children) {
151-
if (level === block.level) {
152-
children.push(block)
153-
} else {
154-
walkList(children, block)
155-
}
156-
} else {
149+
const lastBlock = blocks[blocks.length - 1] || {}
150+
151+
// Start a new list
152+
if (lastBlock._type !== 'list' || !lastBlock.children || (block.level === 1 && block.listItem !== lastBlock.listItem)) {
157153
blocks.push({
158154
_type: 'list',
159-
children: [block],
155+
listItem: block.listItem,
160156
level: block.level,
157+
children: [block],
161158
})
159+
return blocks
162160
}
163161

162+
// Add as child of previous list
163+
if (block.level === lastBlock.level && block.listItem === lastBlock.listItem) {
164+
lastBlock.children.push(block)
165+
return blocks
166+
}
167+
168+
walkList(lastBlock.children, block)
169+
164170
return blocks
165171
}
166172

@@ -229,10 +235,21 @@ const createListSerializer = (serializers: Required<Serializers>) => {
229235
type: Array as () => Array<PortableTextBlock | PortableTextListItemBlock>,
230236
default: () => [],
231237
},
238+
level: {
239+
type: Number,
240+
default: 1,
241+
},
232242
},
233243
setup (props) {
234244
return () => {
235245
const isOrdered = props.children[0]?.listItem === 'number'
246+
if (props.level > 1) {
247+
return h(serializers.listItem as string || 'li', [h(isOrdered ? 'ol' : 'ul', {}, isVue2
248+
? renderBlocks(props.children, serializers)
249+
: {
250+
default: () => renderBlocks(props.children, serializers),
251+
})])
252+
}
236253
return h(isOrdered ? 'ol' : 'ul', {}, isVue2
237254
? renderBlocks(props.children, serializers)
238255
: {

test/unit/__snapshots__/sanity-content.test.ts.snap

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,45 @@
11
// Vitest Snapshot v1
22

3+
exports[`SanityContent > should render adjacentLists blocks 1`] = `
4+
"<ul>
5+
<li>item</li>
6+
<li>item</li>
7+
<li>item</li>
8+
</ul>
9+
<ol>
10+
<li>item</li>
11+
<li>item</li>
12+
<li>item</li>
13+
</ol>"
14+
`;
15+
316
exports[`SanityContent > should render blockquote blocks 1`] = `"<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>"`;
417
518
exports[`SanityContent > should render customBlockTypes blocks 1`] = `"<p>An example of <i>custom</i> block types.</p>"`;
619
20+
exports[`SanityContent > should render evenMoreNestedList blocks 1`] = `
21+
"<ol>
22+
<li>1. Top level</li>
23+
<li>
24+
<ol>
25+
<li>a. Second level</li>
26+
<li>
27+
<ol>
28+
<li>i. Third level</li>
29+
</ol>
30+
</li>
31+
<li>b. Second level</li>
32+
</ol>
33+
</li>
34+
<li>2. Top level</li>
35+
<li>
36+
<ol>
37+
<li>a. Second level</li>
38+
</ol>
39+
</li>
40+
</ol>"
41+
`;
42+
743
exports[`SanityContent > should render exampleMarkDefs blocks 1`] = `
844
"<ul>
945
<li><strong>Google Analytics</strong>: The Sites use Google Analytics. Further information is available at <a href=\\"https://tools.google.com/dlpage/gaoptout/\\">https://tools.google.com/dlpage/gaoptout/</a>.</li>
@@ -26,10 +62,12 @@ exports[`SanityContent > should render nestedList blocks 1`] = `
2662
<ol>
2763
<li>test</li>
2864
<li>thing</li>
29-
<ul>
30-
<li>nested</li>
31-
<li>list</li>
32-
</ul>
65+
<li>
66+
<ul>
67+
<li>nested</li>
68+
<li>list</li>
69+
</ul>
70+
</li>
3371
</ol>"
3472
`;
3573

test/unit/sanity-content.test.ts

Lines changed: 197 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,202 @@ const exampleBlocks: Record<string, ExampleBlock | ExampleBlock[]> = {
137137
listItem: 'bullet',
138138
},
139139
],
140+
evenMoreNestedList: [
141+
{
142+
_key: 'ef73df2f2879',
143+
_type: 'block',
144+
children: [
145+
{
146+
_key: 'c6e5d952a160',
147+
_type: 'span',
148+
marks: [],
149+
text: '1. Top level',
150+
},
151+
],
152+
level: 1,
153+
listItem: 'number',
154+
markDefs: [],
155+
style: 'normal',
156+
},
157+
{
158+
_key: 'de0a206f4585',
159+
_type: 'block',
160+
children: [
161+
{
162+
_key: '37e2c4f12734',
163+
_type: 'span',
164+
marks: [],
165+
text: 'a. Second level',
166+
},
167+
],
168+
level: 2,
169+
listItem: 'number',
170+
markDefs: [],
171+
style: 'normal',
172+
},
173+
{
174+
_key: 'ff34dfbe4cef',
175+
_type: 'block',
176+
children: [
177+
{
178+
_key: '00c289997101',
179+
_type: 'span',
180+
marks: [],
181+
text: 'i. Third level',
182+
},
183+
],
184+
level: 3,
185+
listItem: 'number',
186+
markDefs: [],
187+
style: 'normal',
188+
},
189+
{
190+
_key: 'e79ba2560bba',
191+
_type: 'block',
192+
children: [
193+
{
194+
_key: 'cedad6fc0ce3',
195+
_type: 'span',
196+
marks: [],
197+
text: 'b. Second level',
198+
},
199+
],
200+
level: 2,
201+
listItem: 'number',
202+
markDefs: [],
203+
style: 'normal',
204+
},
205+
{
206+
_key: 'ef1ceb2dbd53',
207+
_type: 'block',
208+
children: [
209+
{
210+
_key: '68c7856c32c9',
211+
_type: 'span',
212+
marks: [],
213+
text: '2. Top level',
214+
},
215+
],
216+
level: 1,
217+
listItem: 'number',
218+
markDefs: [],
219+
style: 'normal',
220+
},
221+
{
222+
_key: 'f6995c48f359',
223+
_type: 'block',
224+
children: [
225+
{
226+
_key: 'a011caafa3df',
227+
_type: 'span',
228+
marks: [],
229+
text: 'a. Second level',
230+
},
231+
],
232+
level: 2,
233+
listItem: 'number',
234+
markDefs: [],
235+
style: 'normal',
236+
},
237+
],
238+
adjacentLists: [
239+
{
240+
_type: 'block',
241+
_key: 'eaaff9001d58',
242+
style: 'normal',
243+
markDefs: [],
244+
children: [
245+
{
246+
_type: 'span',
247+
_key: '4440ea891a28',
248+
text: 'item',
249+
marks: [],
250+
},
251+
],
252+
level: 1,
253+
listItem: 'bullet',
254+
},
255+
{
256+
_type: 'block',
257+
_key: '6a09faddaaa7',
258+
style: 'normal',
259+
markDefs: [],
260+
children: [
261+
{
262+
_type: 'span',
263+
_key: 'b75282293981',
264+
text: 'item',
265+
marks: [],
266+
},
267+
],
268+
level: 1,
269+
listItem: 'bullet',
270+
},
271+
{
272+
_type: 'block',
273+
_key: '52869db6c040',
274+
style: 'normal',
275+
markDefs: [],
276+
children: [
277+
{
278+
_type: 'span',
279+
_key: 'edcc77e18c09',
280+
text: 'item',
281+
marks: [],
282+
},
283+
],
284+
level: 1,
285+
listItem: 'bullet',
286+
},
287+
{
288+
_type: 'block',
289+
_key: '15f5136c8810',
290+
style: 'normal',
291+
markDefs: [],
292+
children: [
293+
{
294+
_type: 'span',
295+
_key: '0c0897ad8490',
296+
text: 'item',
297+
marks: [],
298+
},
299+
],
300+
level: 1,
301+
listItem: 'number',
302+
},
303+
{
304+
_type: 'block',
305+
_key: '8d9673a59e12',
306+
style: 'normal',
307+
markDefs: [],
308+
children: [
309+
{
310+
_type: 'span',
311+
_key: 'b00c2547a438',
312+
text: 'item',
313+
marks: [],
314+
},
315+
],
316+
level: 1,
317+
listItem: 'number',
318+
},
319+
{
320+
_type: 'block',
321+
_key: 'ef73df2f2879',
322+
style: 'normal',
323+
markDefs: [],
324+
children: [
325+
{
326+
_type: 'span',
327+
_key: 'c6e5d952a160',
328+
text: 'item',
329+
marks: [],
330+
},
331+
],
332+
level: 1,
333+
listItem: 'number',
334+
},
335+
],
140336
blockquote: {
141337
_key: 'd810da8ac845',
142338
_type: 'block',
@@ -269,7 +465,7 @@ const exampleBlocks: Record<string, ExampleBlock | ExampleBlock[]> = {
269465
text: '.',
270466
},
271467
],
272-
level: 2,
468+
level: 1,
273469
listItem: 'bullet',
274470
markDefs: [
275471
{

0 commit comments

Comments
 (0)