commonmark / commonmark-spec

CommonMark spec, with reference implementations in C and JavaScript
http://commonmark.org
Other
4.89k stars 317 forks source link

Multi-line custom element support #770

Open keithjgrant opened 5 months ago

keithjgrant commented 5 months ago

related: #239

I have a custom element that has a few very long attribute values, but needs to render without a wrapping <p>. It’s entirely unfeasible to write it all in one line (not to mention doing so would require me to update the component to handle escaped newlines, because it expects newlines in the string).

I get that the parsing question around this is complicated, but there needs to be a way to handle something like:

<my-element
  attr1="very long content
  that might even line wrap"
  attr2="more very long content"
>
</my-element>

This is doubly so now that custom elements are gaining further traction.

There was discussion in #239 and https://talk.commonmark.org/t/raw-html-blocks-proposals-comments-wanted/983/69 includes discussion around the idea of whitelisting vs blacklisting block level elements, but never seemed to resolve that issue. I think, at a bare minimum, there needs to be a way to configure known block level elements, or a flag to treat custom elements as block level (I'm not entirely sure whether that's a spec issue vs. implementation though)

wooorm commented 5 months ago

Custom elements are by definition blocks right, and, by definition include a - in the tag name. That means we could add those tag names to condition 6 and it’ll work:

 6.  **Start condition:** line begins with the string `<` or `</`
 followed by one of the strings (case-insensitive) `address`,
 `article`, `aside`, `base`, `basefont`, `blockquote`, `body`,
 `caption`, `center`, `col`, `colgroup`, `dd`, `details`, `dialog`,
 `dir`, `div`, `dl`, `dt`, `fieldset`, `figcaption`, `figure`,
 `footer`, `form`, `frame`, `frameset`,
 `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `head`, `header`, `hr`,
 `html`, `iframe`, `legend`, `li`, `link`, `main`, `menu`, `menuitem`,
 `nav`, `noframes`, `ol`, `optgroup`, `option`, `p`, `param`,
 `search`, `section`, `summary`, `table`, `tbody`, `td`,
-`tfoot`, `th`, `thead`, `title`, `tr`, `track`, `ul`, followed
+`tfoot`, `th`, `thead`, `title`, `tr`, `track`, `ul`, or
+a [tag name] that includes a dash (`-`), followed
 by a space, a tab, the end of the line, the string `>`, or
 the string `/>`.\
 **End condition:** line is followed by a [blank line].

Example with div, which is included in this list:

https://spec.commonmark.org/dingus/?text=%3Cdiv%0A%20%20attr1%3D%22very%20long%20content%20that%20might%20even%20line%20wrap%22%0A%20%20attr2%3D%22more%20very%20long%20content%22%0A%3E%0A%3C%2Fdiv%3E

keithjgrant commented 5 months ago

Yes, they always include a dash, so I'd be happy with something like that.

I think where the complications have arisen before is they can be inline as well as block (and I believe are actually inline by default according to the spec), even though the vast majority of the time devs set them to block level.

IMO, in the rare instances I'd use an inline custom element, I'd be happy to wrap it in a <p> explicitly since at that point I'm writing markup anyway.

On that note, there is one current workaround where you can manually wrap the custom element in a <div> -- however this can interfere with the CSS on the page by introducing an extra level of nesting (in particular flexbox layouts or sticky positioning).

jgm commented 5 months ago

Could someone point me to documentation for custom elements? I'm not familiar.

For example, something substantiating the claim that they are invariably block-level and invariably contain -? If that's right, then @woorm's solution seems a good one.

keithjgrant commented 5 months ago

They're not invariably block-level, which I think is the problem. They're only set to block level most of the time by developers, but that's not the default behavior per spec. (I think this might be due to the initial value of the CSS display property, which is inline)

As per the hyphen, that's outlined in https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name :

They contain a hyphen, used for namespacing and to ensure forward compatibility (since no elements will be added to HTML, SVG, or MathML with hyphen-containing local names in the future).

taufik-nurrohman commented 5 months ago

Custom elements are by definition blocks right, and, by definition include a - in the tag name. That means we could add those tag names to condition 6 and it’ll work:

 6.  **Start condition:** line begins with the string `<` or `</`
 followed by one of the strings (case-insensitive) `address`,
 `article`, `aside`, `base`, `basefont`, `blockquote`, `body`,
 `caption`, `center`, `col`, `colgroup`, `dd`, `details`, `dialog`,
 `dir`, `div`, `dl`, `dt`, `fieldset`, `figcaption`, `figure`,
 `footer`, `form`, `frame`, `frameset`,
 `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `head`, `header`, `hr`,
 `html`, `iframe`, `legend`, `li`, `link`, `main`, `menu`, `menuitem`,
 `nav`, `noframes`, `ol`, `optgroup`, `option`, `p`, `param`,
 `search`, `section`, `summary`, `table`, `tbody`, `td`,
-`tfoot`, `th`, `thead`, `title`, `tr`, `track`, `ul`, followed
+`tfoot`, `th`, `thead`, `title`, `tr`, `track`, `ul`, or
+a [tag name] that includes a dash (`-`), followed
 by a space, a tab, the end of the line, the string `>`, or
 the string `/>`.\
 **End condition:** line is followed by a [blank line].

Example with div, which is included in this list:

https://spec.commonmark.org/dingus/?text=%3Cdiv%0A%20%20attr1%3D%22very%20long%20content%20that%20might%20even%20line%20wrap%22%0A%20%20attr2%3D%22more%20very%20long%20content%22%0A%3E%0A%3C%2Fdiv%3E

Should go to type 7 to allow it to be treated both as inline and block elements.

wooorm commented 5 months ago

They are indeed not always block — they were added later to html and treated differently by different algorithms and i believe there was a case where they were thus always essentially “block” (even though there is not really such a thing in HTML as block vs inline), but I can‘t find that, and am probably wrong.

Should go to type 7 to allow it to be treated both as inline and block elements.

All block type conditions only parse a single line. Condition 7 is what it would currently “end up” as, but that doesn’t work as the OP sample is not on a line.