nuxt-modules / sanity

Sanity integration for Nuxt
https://sanity.nuxtjs.org
MIT License
217 stars 33 forks source link

Portable Text: Nested lists / bullets render wrong HTML #690

Open marco-land opened 1 year ago

marco-land commented 1 year ago

Version

module: 1.6.0 nuxt: 3.2.2

What is expected?

Nested lists HTML format such as

<ul>
  <li>Bullet
    <ul>
      <li>Bullet 2</li>
    </ul>
  </li>
</ul>

What is actually happening?

<ul>
  <li>Bullet</li>
  <li>
    <ul>
      <li>Bullet 2</li>
    </ul>
  </li>
</ul>

Steps to reproduce

Standard blocks with list markDefs

Additional information

Checklist

wojtekpiskorz commented 1 year ago

Confirmed I have the same issue.

danielroe commented 1 year ago

Would you be able to provide some portable text that renders wrongly? 🙏

wojtekpiskorz commented 1 year ago

documentFile.ts

 defineField({
      name: 'tableOfContent',
      title: 'Table of Content',
      type: 'blockContent',
      hidden: ({ document }) => !document?.isGuidebook,
      description: 'The table of content for the guidebook',
    }),

blockContent.ts is a default one from sanity blog template

import { defineType, defineArrayMember } from 'sanity'

/**
 * This is the schema definition for the rich text fields used for
 * for this blog studio. When you import it in schemas.js it can be
 * reused in other parts of the studio with:
 *  {
 *    name: 'someName',
 *    title: 'Some title',
 *    type: 'blockContent'
 *  }
 */
export default defineType({
  title: 'Block Content',
  name: 'blockContent',
  type: 'array',
  of: [
    defineArrayMember({
      title: 'Block',
      type: 'block',
      // Styles let you set what your user can mark up blocks with. These
      // correspond with HTML tags, but you can set any title or value
      // you want and decide how you want to deal with it where you want to
      // use your content.
      styles: [
        { title: 'Normal', value: 'normal' },
        { title: 'H1', value: 'h1' },
        { title: 'H2', value: 'h2' },
        { title: 'H3', value: 'h3' },
        { title: 'H4', value: 'h4' },
        { title: 'Quote', value: 'blockquote' },
      ],
      lists: [{ title: 'Bullet', value: 'bullet' }, { title: 'Number', value: 'number' }],
      // Marks let you mark up inline text in the block editor.
      marks: {
        // Decorators usually describe a single property – e.g. a typographic
        // preference or highlighting by editors.
        decorators: [
          { title: 'Strong', value: 'strong' },
          { title: 'Emphasis', value: 'em' },
        ],
        // Annotations can be any object structure – e.g. a link or a footnote.
        annotations: [
          {
            title: 'URL',
            name: 'link',
            type: 'object',
            fields: [
              {
                title: 'URL',
                name: 'href',
                type: 'url',
              },
            ],
          },
        ],
      },
    }),
    // You can add additional types here. Note that you can't use
    // primitive types such as 'string' and 'number' in the same array
    // as a block type.
    defineArrayMember({
      type: 'image',
      options: {
        hotspot: true,
      },
      fields: [
        {
          name: 'alt',
          title: 'Alternative text',
          type: 'string',
          options: {
            isHighlighted: true,
          },
        },
      ],
    }),
  ],
})

If I just try to copy-paste from sanity studio body input here it removes all list and it's a plain paragraphs:

Wstęp: o mnie

Przygotowanie do zmiany administratora

Wybór właściwego przewodnika

Metoda 5 kroków

Forma zarządzania nieruchomością wspólną. Dwa rodzaje zarządu we Wspólnocie Mieszkaniowej – od tego trzeba zacząć?

(...)

[1 min video from my sanity studio](https://komododecks.com/recordings/BQooB3WJBWHe832Niq2n)

danielroe commented 1 year ago

I think you should be able to copy-paste the JSON by inspecting your document within the studio.

wojtekpiskorz commented 1 year ago

"tableOfContent": [ { "_key": "5d4d93dc892d", "_type": "block", "children": [ { "_key": "df7b8b9c4e310", "_type": "span", "marks": [], "text": "Wstęp: o mnie" } ], "level": 1, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "907a62afe950", "_type": "block", "children": [ { "_key": "62adc9e9b87b0", "_type": "span", "marks": [], "text": "Przygotowanie do zmiany administratora" } ], "level": 1, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "c70b758344cb", "_type": "block", "children": [ { "_key": "ef692a14b7310", "_type": "span", "marks": [], "text": "Wybór właściwego przewodnika" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "9df9bf2e5591", "_type": "block", "children": [ { "_key": "e4671c062ed4", "_type": "span", "marks": [], "text": "Metoda 5 kroków" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "de691db0d765", "_type": "block", "children": [ { "_key": "5edd66833aee", "_type": "span", "marks": [], "text": "Forma zarządzania nieruchomością wspólną. Dwa rodzaje zarządu we Wspólnocie Mieszkaniowej – od tego trzeba zacząć?" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "e1b1f2d03e46", "_type": "block", "children": [ { "_key": "ce79d7745b100", "_type": "span", "marks": [], "text": "Zmiana administratora – czy w ogóle trzeba przygotowywać te wszystkie dokumenty?" } ], "level": 1, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "20a199b44517", "_type": "block", "children": [ { "_key": "3277e57ddb600", "_type": "span", "marks": [], "text": "Odwołanie administratora w uchwale podjętej w trybie indywidualnego zbierania głosów" } ], "level": 1, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "a7bc5bad5b93", "_type": "block", "children": [ { "_key": "f89c3d5c47600", "_type": "span", "marks": [], "text": "Czy można odwołać administratora uchwałą zbieraną w trybie obiegowym?" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "5d10ba7f53be", "_type": "block", "children": [ { "_key": "31a44cb68f820", "_type": "span", "marks": [], "text": "W jaki sposób odwołać administratora w trybie indywidualnego zbierania głosów?" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "874dfb025742", "_type": "block", "children": [ { "_key": "2d0d612db0230", "_type": "span", "marks": [], "text": "Podpowiedzi, kiedy lokal może być przedmiotem współwłasności" } ], "level": 3, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "9c773f441756", "_type": "block", "children": [ { "_key": "78c7a9d1d8d20", "_type": "span", "marks": [], "text": "Głosowanie nad uchwałą w trybie indywidualnego zbierania głosów" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "01dec1e04a6c", "_type": "block", "children": [ { "_key": "4d8f092719eb0", "_type": "span", "marks": [], "text": "Checklista głosowania w trybie indywidualnym" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "afcf7039fdab", "_type": "block", "children": [ { "_key": "e1a9edbed3d50", "_type": "span", "marks": [], "text": "Uchwała rozwiązująca umowę z administratorem podjęta w drodze indywidualnego zbierania głosów a metoda 5 kroków" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "6a5303b84fe9", "_type": "block", "children": [ { "_key": "0c27e86d9e840", "_type": "span", "marks": [], "text": "Odwołanie administratora na zebraniu wspólnoty mieszkaniowej" } ], "level": 1, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "064037ad40d4", "_type": "block", "children": [ { "_key": "5f853d6361f10", "_type": "span", "marks": [], "text": "Czy warto przygotować pełnomocnictwo?" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "d38a940b757b", "_type": "block", "children": [ { "_key": "e2bd9fb1e1ed0", "_type": "span", "marks": [], "text": "Głosowanie 1 właściciel 1 głos." } ], "level": 3, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "93e99822e427", "_type": "block", "children": [ { "_key": "e30519fe3f1b0", "_type": "span", "marks": [], "text": "Zebranie wspólnoty mieszkaniowej" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "39231bb1043e", "_type": "block", "children": [ { "_key": "33daa202164d0", "_type": "span", "marks": [], "text": "Kto może zwołać zebranie wspólnoty mieszkaniowej?" } ], "level": 3, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "8fe8a033a686", "_type": "block", "children": [ { "_key": "ff01a723dd4e0", "_type": "span", "marks": [], "text": "Planowe zebranie roczne" } ], "level": 3, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "f03059b716cb", "_type": "block", "children": [ { "_key": "40b18a2a712b0", "_type": "span", "marks": [], "text": "Złożenie wniosku do administratora o zwołanie zebrania." } ], "level": 3, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "58b792e52a14", "_type": "block", "children": [ { "_key": "d424026611150", "_type": "span", "marks": [], "text": "Podjęcie uchwały" } ], "level": 3, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "09284ef526ba", "_type": "block", "children": [ { "_key": "da207bba61d10", "_type": "span", "marks": [], "text": "Jak złożyć wypowiedzenie administratorowi?" } ], "level": 1, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "25dd7da79b93", "_type": "block", "children": [ { "_key": "4c2fbdbdc6aa0", "_type": "span", "marks": [], "text": "Wzory dokumentów" } ], "level": 1, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "8b3ba2eb5420", "_type": "block", "children": [ { "_key": "030e98c21b8f0", "_type": "span", "marks": [], "text": "Pełnomocnictwo" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "c1e6f3cd3a07", "_type": "block", "children": [ { "_key": "fb54244f98310", "_type": "span", "marks": [], "text": "Wniosek o rozszerzenie porządku obrad zebrania wspólnoty mieszkaniowej" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "38cdd64b043b", "_type": "block", "children": [ { "_key": "98fa08c9f32e0", "_type": "span", "marks": [], "text": "Wniosek o zwołanie zebrania wspólnoty mieszkaniowej" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "fe79c33278ce", "_type": "block", "children": [ { "_key": "73a6d66b65250", "_type": "span", "marks": [], "text": "Uchwała wspólnoty mieszkaniowej w sprawie odwołania administratora" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" }, { "_key": "f3434219c8b2", "_type": "block", "children": [ { "_key": "663ba23514cf0", "_type": "span", "marks": [], "text": "Wypowiedzenie" } ], "level": 2, "listItem": "number", "markDefs": [], "style": "normal" } ],

joelisfar commented 1 year ago

I'm having the same issue. In case it's of any use, here's a small example of the data and its output:

Nested list JSON output

  "body": [
    {
      "_key": "6910ab1aa5dc",
      "_type": "block",
      "children": [
        {
          "_key": "e1a144d0eb80",
          "_type": "span",
          "marks": [],
          "text": "Item 1 of the Level 1 list"
        }
      ],
      "level": 1,
      "listItem": "bullet",
      "markDefs": [],
      "style": "normal"
    },
    {
      "_key": "56f41e061efa",
      "_type": "block",
      "children": [
        {
          "_key": "82534a0b5bb6",
          "_type": "span",
          "marks": [],
          "text": "Item 1 of the Level 2 list"
        }
      ],
      "level": 2,
      "listItem": "bullet",
      "markDefs": [],
      "style": "normal"
    },
    {
      "_key": "3d6b701f6f7f",
      "_type": "block",
      "children": [
        {
          "_key": "328ea9751c4d",
          "_type": "span",
          "marks": [],
          "text": "Item 2 of the Level 1 list"
        }
      ],
      "level": 1,
      "listItem": "bullet",
      "markDefs": [],
      "style": "normal"
    }
  ],

Nested list HTML output

<ul>
    <li>Item 1 of the Level 1 list</li>
    <li>
        <ul>
            <li>Item 1 of the Level 2 list</li>
        </ul>
    </li>
    <li>Item 2 of the Level 1 list</li>
</ul>

Desired HTML output

<ul>
    <li>Item 1 of the Level 1 list
        <ul>
            <li>Item 1 of the Level 2 list</li>
        </ul>
    </li>
    <li>Item 2 of the Level 1 list</li>
</ul>

Screenshot of "double bullets" issue

Screenshot 2023-06-23 at 6 39 25 PM
adalmagro-rs commented 3 weeks ago

Hi, not sure if this is something related to this bug but I am experiencing issues with lists rendering with Nuxt3. I am passing the following serializer to the SanityContent:

const serializers = {
    types: {
        code: Code,
        callout: Callout,
        seoImage: SeoImage,
        video: VideoImage
    },
    list: {
        // Ex. 1: customizing common list types
        bullet: List,
        number: NumberedList,
        // bullet: (_, { slots }) => h('ul', { class: 'simple-list' }, slots.default?.()),
        // number: (_, { slots }) => h('ol', { class: 'digit-list' }, slots.default?.()),
    },
    listItem: {
        // Ex. 1: customizing common list types
        // bullet: ({ slots }) => h('li', { class: 'list-item' }, slots),
        // number: ({ slots }) => h('li', { class: 'list-item' }, slots),
        bullet: ListItem,
        number: ListItem
    },
    styles: {
        'blockquote': BlockQuote,
    },
    marks: {
        'externalLink': Link,
        'internalLink': InternalLink,
        'strike-through': 's',
        'keyboard': 'kbd',
        'highlight': 'mark'
    }
}

I have some custom types, styles and marks that renders fine, but list and listItem do not render as pointed out at all. I have tried the two ways shown in the code: as a Vue Component and as inline definition (commented) but none of both work. In fact, it does not show the list on the rendered HTML.

Is this bug still open? Is this behaviour related o is a new bug?

I am using: "@nuxtjs/sanity@^1.11.3": version "1.11.3"