Skip to content

Commit fc4283c

Browse files
Slot is fill and fill is slot
1 parent 96ff607 commit fc4283c

17 files changed

+73
-74
lines changed

examples/dist/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ <h1 class="display-1 fw-bold mb-4">Build the web with PostHTML</h1>
8383
</div>
8484
</div>
8585
</footer>
86-
<div class="modal fade custom-modal" id="modalWithComponents" data-bs-backdrop="true" data-bs-keyboard="true" aria-labelledby="modalWithComponents" tabindex="-1" aria-hidden="true" aria-modal="true" role="dialog">
86+
<div class="modal fade" id="modalWithComponents" data-bs-backdrop="true" data-bs-keyboard="true" aria-labelledby="modalWithComponents" tabindex="-1" aria-hidden="true" aria-modal="true" role="dialog">
8787
<div class="modal-dialog modal-lg modal-fullscreen-lg-down modal-dialog-centered modal-dialog-custom">
8888
<div class="modal-content modal-content-custom">
8989
<div class="modal-header">

examples/src/components/modal/index.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,18 @@
4646
<yield></yield>
4747
<if condition="$slots.header?.filled">
4848
<x-modal.header>
49-
<!-- Alternative way to <fill:header></fill:header> -->
49+
<!-- Alternative way to <slot:header></slot:header> -->
5050
{{{ $slots.header?.source }}}
5151
</x-modal.header>
5252
</if>
5353
<if condition="$slots.body?.filled">
5454
<x-modal.body>
55-
<fill:body></fill:body>
55+
<slot:body></slot:body>
5656
</x-modal.body>
5757
</if>
5858
<if condition="$slots.footer?.filled">
5959
<x-modal.footer close="{{ $slots.footer?.locals.close }}">
60-
<fill:footer></fill:footer>
60+
<slot:footer></slot:footer>
6161
</x-modal.footer>
6262
</if>
6363
</div><!-- /.modal-content -->

src/index.js

+8-9
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,7 @@ module.exports = (options = {}) => tree => {
9797
* @return {Object} PostHTML tree
9898
*/
9999
function processTree(options) {
100-
// rename to pushes and slots
101-
const slotContent = {};
100+
const filledSlots = {};
102101

103102
let processCounter = 0;
104103

@@ -127,15 +126,15 @@ function processTree(options) {
127126
let nextNode = parser(readFileSync(componentPath, 'utf8'));
128127

129128
// Set filled slots
130-
setFilledSlots(currentNode, slotContent, options);
129+
setFilledSlots(currentNode, filledSlots, options);
131130

132131
// Reset previous locals with passed global and keep aware locals
133132
options.expressions.locals = {...options.locals, ...options.aware};
134133

135-
const {attributes, locals} = processLocals(currentNode, nextNode, slotContent, options);
134+
const {attributes, locals} = processLocals(currentNode, nextNode, filledSlots, options);
136135

137136
options.expressions.locals = attributes;
138-
options.expressions.locals.$slots = slotContent;
137+
options.expressions.locals.$slots = filledSlots;
139138
// const plugins = [...options.plugins, expressions(options.expressions)];
140139
nextNode = expressions(options.expressions)(nextNode);
141140

@@ -145,11 +144,11 @@ function processTree(options) {
145144
return currentNode.content || nextNode.content || '';
146145
});
147146

148-
// Process <slot> tags
149-
processSlotContent(nextNode, slotContent, options);
150-
151147
// Process <fill> tags
152-
processFillContent(nextNode, slotContent, options);
148+
processFillContent(nextNode, filledSlots, options);
149+
150+
// Process <slot> tags
151+
processSlotContent(nextNode, filledSlots, options);
153152

154153
// Remove component tag and replace content with <yield>
155154
currentNode.tag = false;

src/slots.js

+36-36
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ const {render} = require('posthtml-render');
77
* Set filled slots
88
*
99
* @param {Object} currentNode PostHTML tree
10-
* @param {Object} slots
10+
* @param {Object} filledSlots
1111
* @param {Object} options Plugin options
1212
* @return {void}
1313
*/
14-
function setFilledSlots(currentNode, slots, {slot}) {
15-
match.call(currentNode, {tag: slot}, fillNode => {
14+
function setFilledSlots(currentNode, filledSlots, {fill}) {
15+
match.call(currentNode, {tag: fill}, fillNode => {
1616
if (!fillNode.attrs) {
1717
fillNode.attrs = {};
1818
}
1919

2020
const name = fillNode.tag.split(':')[1];
2121

22-
/** @var {Object} locals */
22+
/** @var {Object} locals - NOT YET TESTED */
2323
const locals = Object.fromEntries(Object.entries(fillNode.attrs).filter(([attributeName]) => ![name, 'type'].includes(attributeName)));
2424

2525
if (locals) {
@@ -30,7 +30,7 @@ function setFilledSlots(currentNode, slots, {slot}) {
3030
});
3131
}
3232

33-
slots[name] = {
33+
filledSlots[name] = {
3434
filled: true,
3535
rendered: false,
3636
tag: fillNode.tag,
@@ -45,68 +45,68 @@ function setFilledSlots(currentNode, slots, {slot}) {
4545
}
4646

4747
/**
48-
* Process <slot> tag
48+
* Process <fill> tag
4949
*
5050
* @param {Object} tree PostHTML tree
51-
* @param {Object} content Content pushed by stack name
51+
* @param {Object} filledSlots Filled slots content
5252
* @param {Object} options Plugin options
5353
* @return {void}
5454
*/
55-
function processSlotContent(tree, content, {slot}) {
56-
match.call(tree, {tag: slot}, slotNode => {
57-
const name = slotNode.tag.split(':')[1];
55+
function processFillContent(tree, filledSlots, {fill}) {
56+
match.call(tree, {tag: fill}, fillNode => {
57+
const name = fillNode.tag.split(':')[1];
5858

59-
if (!content[name]) {
60-
content[name] = {};
59+
if (!filledSlots[name]) {
60+
filledSlots[name] = {};
6161
}
6262

63-
content[name].tag = slotNode.tag;
64-
content[name].attrs = slotNode.attrs;
65-
content[name].content = slotNode.content;
66-
content[name].source = render(slotNode.content);
67-
content[name].rendered = false;
63+
filledSlots[name].tag = fillNode.tag;
64+
filledSlots[name].attrs = fillNode.attrs;
65+
filledSlots[name].content = fillNode.content;
66+
filledSlots[name].source = render(fillNode.content);
67+
filledSlots[name].rendered = false;
6868

69-
slotNode.tag = false;
70-
slotNode.content = null;
69+
fillNode.tag = false;
70+
fillNode.content = null;
7171

72-
return slotNode;
72+
return fillNode;
7373
});
7474
}
7575

7676
/**
77-
* Process <fill> tag
77+
* Process <slot> tag
7878
*
7979
* @param {Object} tree PostHTML tree
80-
* @param {Object} content Content pushed by stack name
80+
* @param {Object} filledSlots Filled slots content
8181
* @param {Object} options Plugin options
8282
* @return {void}
8383
*/
84-
function processFillContent(tree, content, {fill}) {
85-
match.call(tree, {tag: fill}, fillNode => {
86-
const name = fillNode.tag.split(':')[1];
84+
function processSlotContent(tree, filledSlots, {slot}) {
85+
match.call(tree, {tag: slot}, slotNode => {
86+
const name = slotNode.tag.split(':')[1];
8787

88-
fillNode.tag = false;
88+
slotNode.tag = false;
8989

90-
if (content[name]?.rendered) {
91-
fillNode.content = null;
92-
} else if (fillNode.content && content[name]?.attrs && (typeof content[name]?.attrs.append !== 'undefined' || typeof content[name]?.attrs.prepend !== 'undefined')) {
93-
fillNode.content = typeof content[name]?.attrs.append === 'undefined' ? content[name]?.content.concat(fillNode.content) : fillNode.content.concat(content[name]?.content);
90+
if (filledSlots[name]?.rendered) {
91+
slotNode.content = null;
92+
} else if (slotNode.content && filledSlots[name]?.attrs && (typeof filledSlots[name]?.attrs.append !== 'undefined' || typeof filledSlots[name]?.attrs.prepend !== 'undefined')) {
93+
slotNode.content = typeof filledSlots[name]?.attrs.append === 'undefined' ? filledSlots[name]?.content.concat(slotNode.content) : slotNode.content.concat(filledSlots[name]?.content);
9494
} else {
95-
fillNode.content = content[name]?.content;
95+
slotNode.content = filledSlots[name]?.content;
9696
}
9797

9898
// Set rendered to true so a slot can be output only once,
9999
// when not present "aware" attribute
100-
if (content[name] && (!content[name]?.attrs || typeof content[name].attrs.aware === 'undefined')) {
101-
content[name].rendered = true;
100+
if (filledSlots[name] && (!filledSlots[name]?.attrs || typeof filledSlots[name].attrs.aware === 'undefined')) {
101+
filledSlots[name].rendered = true;
102102
}
103103

104-
return fillNode;
104+
return slotNode;
105105
});
106106
}
107107

108108
module.exports = {
109109
setFilledSlots,
110-
processSlotContent,
111-
processFillContent
110+
processFillContent,
111+
processSlotContent
112112
};
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<div><fill:title>Title</fill:title></div><div><fill:body>Body</fill:body></div>
1+
<div><slot:title>Title</slot:title></div><div><slot:body>Body</slot:body></div>

test/templates/components/component-locals.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
body: 'Default body'
55
}
66
</script>
7-
<div><h1>{{title}}</h1></div><div><fill:body>{{body}}</fill:body></div>
7+
<div><h1>{{title}}</h1></div><div><slot:body>{{body}}</slot:body></div>
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<div><fill:title></fill:title></div><div><fill:body></fill:body></div><div><fill:title></fill:title></div>
1+
<div><slot:title></slot:title></div><div><slot:body></slot:body></div><div><slot:title></slot:title></div>
+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<div><fill:title></fill:title></div><div><fill:body></fill:body></div>
1+
<div><slot:title></slot:title></div><div><slot:body></slot:body></div>
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div class="nested-one">
2-
<div class="nested-one-before"><fill:before></fill:before></div>
2+
<div class="nested-one-before"><slot:before></slot:before></div>
33
<div class="nested-one-yield"><yield></yield></div>
4-
<div class="nested-one-after"><fill:after></fill:after></div>
4+
<div class="nested-one-after"><slot:after></slot:after></div>
55
</div>
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div class="nested-two">
2-
<div class="nested-two-before"><fill:before2></fill:before2></div>
2+
<div class="nested-two-before"><slot:before2></slot:before2></div>
33
<div class="nested-two-yield"><yield></yield></div>
4-
<div class="nested-two-after"><fill:after2></fill:after2></div>
4+
<div class="nested-two-after"><slot:after2></slot:after2></div>
55
</div>

test/templates/components/script-locals.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
</script>
77
{{ slotsAccessibleViaScript }}
88
<div>{{ $slots }}</div>
9-
<div><h1>{{title}}</h1></div><div><fill:filled></fill:filled><fill:notfilled></fill:notfilled></div>
9+
<div><h1>{{title}}</h1></div><div><slot:filled></slot:filled><slot:notfilled></slot:notfilled></div>

test/templates/layouts/base-locals.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
title: 'Default title'
44
}
55
</script>
6-
<html><head><title>{{ title }}</title></head><body><main><yield></yield></main><footer><fill:footer></fill:footer></footer></body></html>
6+
<html><head><title>{{ title }}</title></head><body><main><yield></yield></main><footer><slot:footer></slot:footer></footer></body></html>

test/templates/layouts/base.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<html>
22
<head><title>Base Layout</title></head>
33
<body>
4-
<header><fill:header></fill:header></header>
4+
<header><slot:header></slot:header></header>
55
<main><yield></yield></main>
6-
<footer><fill:footer>footer content</fill:footer></footer>
6+
<footer><slot:footer>footer content</slot:footer></footer>
77
</body>
88
</html>

test/templates/layouts/slot-condition.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<head><title>Slot Condition Layout</title></head>
33
<body>
44
<main><yield></yield></main>
5-
<if condition="$slots.footer?.filled"><footer><fill:footer></fill:footer></footer></if>
5+
<if condition="$slots.footer?.filled"><footer><slot:footer></slot:footer></footer></if>
66
<else><p>There is not footer defined.</p></else>
77
</body>
88
</html>

test/test-locals.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const posthtml = require('posthtml');
66
const clean = html => html.replace(/(\n|\t)/g, '').trim();
77

88
test('Must process layout with locals', async t => {
9-
const actual = `<component src="layouts/base-locals.html" locals='{ "title": "My Page" }'><div>Content</div><slot:footer>Footer</slot:footer></component>`;
9+
const actual = `<component src="layouts/base-locals.html" locals='{ "title": "My Page" }'><div>Content</div><fill:footer>Footer</fill:footer></component>`;
1010
const expected = `<html><head><title>My Page</title></head><body><main><div>Content</div></main><footer>Footer</footer></body></html>`;
1111

1212
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
@@ -15,7 +15,7 @@ test('Must process layout with locals', async t => {
1515
});
1616

1717
test('Must process attributes as locals', async t => {
18-
const actual = `<component src="components/component-locals.html" title="My Component Title" body="Content"><slot:body prepend><span>Body</span></slot:body></component>`;
18+
const actual = `<component src="components/component-locals.html" title="My Component Title" body="Content"><fill:body prepend><span>Body</span></fill:body></component>`;
1919
const expected = `<div><h1>My Component Title</h1></div><div><span>Body</span>Content</div>`;
2020

2121
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
@@ -56,8 +56,8 @@ test('Must process parent and child locals via component', async t => {
5656
});
5757

5858
test('Must has access to $slots in script locals', async t => {
59-
const actual = `<x-script-locals><slot:filled>filled slot content...</slot:filled></x-script-locals>`;
60-
const expected = `{"filled":{"filled":true,"rendered":false,"tag":"slot:filled","attrs":{},"content":["filled slot content..."],"source":"filled slot content...","locals":{}}}<div>{"filled":{"filled":true,"rendered":false,"tag":"slot:filled","attrs":{},"content":["filled slot content..."],"source":"filled slot content...","locals":{}}}</div><div><h1>Default title</h1></div><div>filled slot content...</div>`;
59+
const actual = `<x-script-locals><fill:filled>filled slot content...</fill:filled></x-script-locals>`;
60+
const expected = `{"filled":{"filled":true,"rendered":false,"tag":"fill:filled","attrs":{},"content":["filled slot content..."],"source":"filled slot content...","locals":{}}}<div>{"filled":{"filled":true,"rendered":false,"tag":"fill:filled","attrs":{},"content":["filled slot content..."],"source":"filled slot content...","locals":{}}}</div><div><h1>Default title</h1></div><div>filled slot content...</div>`;
6161

6262
const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
6363

test/test-nested.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ test('Must process all nested component to html', async t => {
1515
});
1616

1717
test('Must process all nested component with slots to html', async t => {
18-
const actual = `<x-nested-one-slot><x-nested-two-slot>yield content<slot:before2>nested-two before</slot:before2><slot:after2>nested-two after</slot:after2></x-nested-two-slot><slot:before>nested-one before</slot:before><slot:after>nested-one after</slot:after></x-nested-one-slot>`;
18+
const actual = `<x-nested-one-slot><x-nested-two-slot>yield content<fill:before2>nested-two before</fill:before2><fill:after2>nested-two after</fill:after2></x-nested-two-slot><fill:before>nested-one before</fill:before><fill:after>nested-one after</fill:after></x-nested-one-slot>`;
1919
const expected = `<div class="nested-one"><div class="nested-one-before">nested-one before</div><div class="nested-one-yield"><div class="nested-two"><div class="nested-two-before">nested-two before</div><div class="nested-two-yield">yield content</div><div class="nested-two-after">nested-two after</div></div></div><div class="nested-one-after">nested-one after</div></div>`;
2020

2121
const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));

test/test-slots.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const posthtml = require('posthtml');
66
const clean = html => html.replace(/(\n|\t)/g, '').trim();
77

88
test('Must process with slots', async t => {
9-
const actual = `<component src="layouts/base.html"><div>Main content</div><slot:header><h1>My header</h1></slot:header><slot:footer>My footer</slot:footer></component>`;
9+
const actual = `<component src="layouts/base.html"><div>Main content</div><fill:header><h1>My header</h1></fill:header><fill:footer>My footer</fill:footer></component>`;
1010
const expected = `<html><head><title>Base Layout</title></head><body><header><h1>My header</h1></header><main><div>Main content</div></main><footer>My footer</footer></body></html>`;
1111

1212
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
@@ -15,7 +15,7 @@ test('Must process with slots', async t => {
1515
});
1616

1717
test('Must process the same component multiple times', async t => {
18-
const actual = `<component src="components/component.html"><slot:title>Title</slot:title><slot:body>Body</slot:body></component><component src="components/component.html"><slot:title>Title 2</slot:title><slot:body>Body 2</slot:body></component>`;
18+
const actual = `<component src="components/component.html"><fill:title>Title</fill:title><fill:body>Body</fill:body></component><component src="components/component.html"><fill:title>Title 2</fill:title><fill:body>Body 2</fill:body></component>`;
1919
const expected = `<div>Title</div><div>Body</div><div>Title 2</div><div>Body 2</div>`;
2020

2121
const html = await posthtml([plugin({root: './test/templates/', tag: 'component'})]).process(actual).then(result => clean(result.html));
@@ -25,15 +25,15 @@ test('Must process the same component multiple times', async t => {
2525

2626
test('Must process multiple time a slot with aware attribute', async t => {
2727
// With aware
28-
let actual = `<component src="components/component-multiple-slot.html"><slot:title aware>Title</slot:title><slot:body>Body</slot:body></component>`;
28+
let actual = `<component src="components/component-multiple-slot.html"><fill:title aware>Title</fill:title><fill:body>Body</fill:body></component>`;
2929
let expected = `<div>Title</div><div>Body</div><div>Title</div>`;
3030

3131
let html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
3232

3333
t.is(html, expected);
3434

3535
// Without aware
36-
actual = `<component src="components/component-multiple-slot.html"><slot:title>Title</slot:title><slot:body>Body</slot:body></component>`;
36+
actual = `<component src="components/component-multiple-slot.html"><fill:title>Title</fill:title><fill:body>Body</fill:body></component>`;
3737
expected = `<div>Title</div><div>Body</div><div></div>`;
3838

3939
html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
@@ -42,7 +42,7 @@ test('Must process multiple time a slot with aware attribute', async t => {
4242
});
4343

4444
test('Must process append and prepend content to slot', async t => {
45-
const actual = `<component src="components/component-append-prepend.html"><slot:title append><span>Append</span></slot:title><slot:body prepend><span>Prepend</span></slot:body></component>`;
45+
const actual = `<component src="components/component-append-prepend.html"><fill:title append><span>Append</span></fill:title><fill:body prepend><span>Prepend</span></fill:body></component>`;
4646
const expected = `<div>Title<span>Append</span></div><div><span>Prepend</span>Body</div>`;
4747

4848
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
@@ -58,7 +58,7 @@ test('Must process slots conditional rendering by using slot name', async t => {
5858

5959
t.is(html, expected);
6060

61-
actual = `<component src="layouts/slot-condition.html"><h1>Content</h1><slot:footer>There is now footer defined</slot:footer></component>`;
61+
actual = `<component src="layouts/slot-condition.html"><h1>Content</h1><fill:footer>There is now footer defined</fill:footer></component>`;
6262
expected = `<html><head><title>Slot Condition Layout</title></head><body><main><h1>Content</h1></main><footer>There is now footer defined</footer></body></html>`;
6363

6464
html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
@@ -67,7 +67,7 @@ test('Must process slots conditional rendering by using slot name', async t => {
6767
});
6868

6969
test('Must render slots using $slots locals', async t => {
70-
const actual = `<component src="layouts/base-render-slots-locals.html"><div>Main content</div><slot:header><h1>My header</h1></slot:header><slot:footer>My footer</slot:footer></component>`;
70+
const actual = `<component src="layouts/base-render-slots-locals.html"><div>Main content</div><fill:header><h1>My header</h1></fill:header><fill:footer>My footer</fill:footer></component>`;
7171
const expected = `<html><head><title>Base Render Slots Locals Layout</title></head><body><header><h1>My header</h1></header><main><div>Main content</div></main><footer>My footer</footer></body></html>`;
7272

7373
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));

0 commit comments

Comments
 (0)