Skip to content

Commit

Permalink
Preserve whitespace in slots (#770)
Browse files Browse the repository at this point in the history
* Preserve whitespace in slots

* Don't print default slots of there are named and the default is only whitespace
  • Loading branch information
matthewp authored Apr 7, 2023
1 parent 0a9b303 commit e0baa85
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changeset/smart-ties-punch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/compiler': patch
---

Preserve whitespace in slots
31 changes: 29 additions & 2 deletions internal/printer/print-to-js.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,17 @@ func expressionOnlyHasCommentBlock(n *Node) bool {
len(clean) == 0
}

func emptyTextNodeWithoutSiblings(n *Node) bool {
if strings.TrimSpace(n.Data) != "" {
return false
}
if n.PrevSibling == nil {
return n.NextSibling == nil || n.NextSibling.Expression
} else {
return n.PrevSibling.Expression
}
}

func render1(p *printer, n *Node, opts RenderOptions) {
depth := opts.depth

Expand Down Expand Up @@ -587,7 +598,7 @@ func render1(p *printer, n *Node, opts RenderOptions) {

// Only slot ElementNodes or non-empty TextNodes!
// CommentNode and others should not be slotted
if c.Type == ElementNode || (c.Type == TextNode && strings.TrimSpace(c.Data) != "") {
if c.Type == ElementNode || (c.Type == TextNode && !emptyTextNodeWithoutSiblings(c)) {
slottedChildren[slotProp] = append(slottedChildren[slotProp], c)
}
}
Expand All @@ -601,10 +612,26 @@ func render1(p *printer, n *Node, opts RenderOptions) {
p.print(`$$mergeSlots(`)
}
p.print(`{`)
if len(slottedKeys) > 0 {
numberOfSlots := len(slottedKeys)
if numberOfSlots > 0 {
childrenLoop:
for _, slotProp := range slottedKeys {
children := slottedChildren[slotProp]

// If there are named slots, the default slot cannot be only whitespace
if numberOfSlots > 1 && slotProp == "\"default\"" {
// Loop over the children and verify that at least one non-whitespace node exists.
foundNonWhitespace := false
for _, child := range children {
if child.Type != TextNode || strings.TrimSpace(child.Data) != "" {
foundNonWhitespace = true
}
}
if !foundNonWhitespace {
continue childrenLoop
}
}

// If selected, pass through result object on the Astro side
if opts.opts.ResultScopedSlot {
p.print(fmt.Sprintf(`%s: ($$result) => `, slotProp))
Expand Down
33 changes: 29 additions & 4 deletions internal/printer/printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,18 @@ func TestPrinter(t *testing.T) {
code: `${$$maybeRenderHead($$result)}<div>${$$renderSlot($$result,$$slots["test"],$$render` + BACKTICK + `<p>Fallback</p>` + BACKTICK + `)}</div>`,
},
},
{
name: "Preserve slot whitespace",
source: `<Component>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</Component>`,
want: want{
code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + BACKTICK + `
${$$maybeRenderHead($$result)}<p>Paragraph 1</p>
<p>Paragraph 2</p>` + BACKTICK + `,})}`,
},
},
{
name: "text only",
source: "Hello!",
Expand Down Expand Up @@ -913,7 +925,7 @@ import Component from "test";
want: want{
frontmatter: []string{`import Component from "test";`},
metadata: metadata{modules: []string{`{ module: $$module1, specifier: 'test', assert: {} }`}},
code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + "`" + `${$$maybeRenderHead($$result)}<div>Default</div>` + "`" + `,"named": () => $$render` + "`" + `<div>Named</div>` + "`" + `,})}`,
code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + "`" + ` ${$$maybeRenderHead($$result)}<div>Default</div>` + "`" + `,"named": () => $$render` + "`" + `<div>Named</div>` + "`" + `,})}`,
},
},
{
Expand All @@ -929,7 +941,7 @@ import Component from 'test';
want: want{
frontmatter: []string{`import Component from 'test';`},
metadata: metadata{modules: []string{`{ module: $$module1, specifier: 'test', assert: {} }`}},
code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + "`" + `${$$maybeRenderHead($$result)}<div>Default</div>` + "`" + `,"named": () => $$render` + "`" + `<div>Named</div>` + "`" + `,})}`,
code: `${$$renderComponent($$result,'Component',Component,{},{"default": () => $$render` + "`" + ` ${$$maybeRenderHead($$result)}<div>Default</div>` + "`" + `,"named": () => $$render` + "`" + `<div>Named</div>` + "`" + `,})}`,
},
},
{
Expand Down Expand Up @@ -1148,7 +1160,9 @@ const someProps = {
` + RENDER_HEAD_RESULT + `</head>
<body class="astro-HMNNHVCQ">
<main class="astro-HMNNHVCQ">
${$$renderComponent($$result,'Counter',Counter,{...(someProps),"client:visible":true,"client:component-hydration":"visible","client:component-path":("../components/Counter.jsx"),"client:component-export":("default"),"class":"astro-HMNNHVCQ"},{"default": () => $$render` + "`" + `<h1 class="astro-HMNNHVCQ">Hello React!</h1>` + "`" + `,})}
${$$renderComponent($$result,'Counter',Counter,{...(someProps),"client:visible":true,"client:component-hydration":"visible","client:component-path":("../components/Counter.jsx"),"client:component-export":("default"),"class":"astro-HMNNHVCQ"},{"default": () => $$render` + "`" + `
<h1 class="astro-HMNNHVCQ">Hello React!</h1>
` + "`" + `,})}
</main>
</body></html>
`,
Expand Down Expand Up @@ -1259,6 +1273,17 @@ const name = 'named';
code: `${$$renderComponent($$result,'Component',Component,{},{[name]: () => $$render` + "`" + `${$$maybeRenderHead($$result)}<div>Named</div>` + "`" + `,})}`,
},
},
{
name: "slots (named only)",
source: `<Slotted>
<span slot="a">A</span>
<span slot="b">B</span>
<span slot="c">C</span>
</Slotted>`,
want: want{
code: `${$$renderComponent($$result,'Slotted',Slotted,{},{"a": () => $$render` + BACKTICK + `${$$maybeRenderHead($$result)}<span>A</span>` + BACKTICK + `,"b": () => $$render` + BACKTICK + `<span>B</span>` + BACKTICK + `,"c": () => $$render` + BACKTICK + `<span>C</span>` + BACKTICK + `,})}`,
},
},
{
name: "condition expressions at the top-level",
source: `{cond && <span></span>}{cond && <strong></strong>}`,
Expand Down Expand Up @@ -1615,7 +1640,7 @@ import { Container, Col, Row } from 'react-bootstrap';
want: want{
frontmatter: []string{`import { Container, Col, Row } from 'react-bootstrap';`},
metadata: metadata{modules: []string{`{ module: $$module1, specifier: 'react-bootstrap', assert: {} }`}},
code: "${$$renderComponent($$result,'Container',Container,{},{\"default\": () => $$render`${$$renderComponent($$result,'Row',Row,{},{\"default\": () => $$render`${$$renderComponent($$result,'Col',Col,{},{\"default\": () => $$render`${$$maybeRenderHead($$result)}<h1>Hi!</h1>`,})}`,})}`,})}",
code: "${$$renderComponent($$result,'Container',Container,{},{\"default\": () => $$render`\n ${$$renderComponent($$result,'Row',Row,{},{\"default\": () => $$render`\n ${$$renderComponent($$result,'Col',Col,{},{\"default\": () => $$render`\n ${$$maybeRenderHead($$result)}<h1>Hi!</h1>\n `,})}\n `,})}`,})}",
},
},
{
Expand Down

0 comments on commit e0baa85

Please sign in to comment.