Skip to content

Commit 4a088b6

Browse files
authored
Merge pull request #3004 from mjmlio/feature/MJML-52-mj-wrapper_add_spacing_between_sections
feature(mjml-wrapper): add gap between sections #2977
2 parents e97390b + 3b60b46 commit 4a088b6

File tree

4 files changed

+85
-2
lines changed

4 files changed

+85
-2
lines changed

packages/mjml-section/src/index.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export default class MjSection extends BodyComponent {
4747
return {
4848
...this.context,
4949
containerWidth: `${box}px`,
50+
gap: this.getAttribute('gap'),
5051
}
5152
}
5253

@@ -57,6 +58,8 @@ export default class MjSection extends BodyComponent {
5758

5859
const hasBorderRadius = this.hasBorderRadius()
5960

61+
const isFirstSection = this.props.index === 0
62+
6063
const background = this.getAttribute('background-url')
6164
? {
6265
background: this.getBackground(),
@@ -102,6 +105,7 @@ export default class MjSection extends BodyComponent {
102105
'max-width': containerWidth,
103106
'border-radius': this.getAttribute('border-radius'),
104107
...(hasBorderRadius && { overflow: 'hidden' }),
108+
'margin-top': !isFirstSection ? this.context.gap : undefined,
105109
},
106110
innerDiv: {
107111
'line-height': '0',
@@ -195,12 +199,21 @@ export default class MjSection extends BodyComponent {
195199
return borderRadius !== '' && typeof borderRadius !== 'undefined'
196200
}
197201

202+
hasGap() {
203+
const { gap } = this.context
204+
return gap != null && gap !== ''
205+
}
206+
198207
renderBefore() {
199208
const { containerWidth } = this.context
200209
const bgcolorAttr = this.getAttribute('background-color')
201210
? { bgcolor: this.getAttribute('background-color') }
202211
: {}
203212

213+
const isFirstSection = this.props.index === 0
214+
215+
const hasGap = this.hasGap()
216+
204217
return `
205218
<!--[if mso | IE]>
206219
<table
@@ -211,9 +224,12 @@ export default class MjSection extends BodyComponent {
211224
cellspacing: '0',
212225
class: suffixCssClasses(this.getAttribute('css-class'), 'outlook'),
213226
role: 'presentation',
214-
style: { width: `${containerWidth}` },
227+
style: {
228+
width: `${containerWidth}`,
229+
'padding-top': !isFirstSection ? this.context.gap : undefined,
230+
},
215231
width: parseInt(containerWidth, 10),
216-
...bgcolorAttr,
232+
...(!hasGap && { ...bgcolorAttr }),
217233
})}
218234
>
219235
<tr>

packages/mjml-wrapper/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ border-right | string | css border format | n/a
6464
border-top | string | css border format | n/a
6565
css-class | string | class name, added to the root HTML element created | n/a
6666
full-width | string | make the wrapper full-width | n/a
67+
gap | px | applies a vertical gap between child mj-sections | n/a
6768
padding | px | supports up to 4 parameters | 20px 0
6869
padding-bottom | px | section bottom offset | n/a
6970
padding-left | px | section left offset | n/a

packages/mjml-wrapper/src/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ import { suffixCssClasses } from 'mjml-core'
44
export default class MjWrapper extends MjSection {
55
static componentName = 'mj-wrapper'
66

7+
static allowedAttributes = {
8+
gap: 'unit(px)',
9+
}
10+
11+
getChildContext() {
12+
return {
13+
...this.context,
14+
gap: this.getAttribute('gap'),
15+
}
16+
}
17+
718
renderWrappedChildren() {
819
const { children } = this.props
920
const { containerWidth } = this.context
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
const chai = require('chai')
2+
const { load } = require('cheerio')
3+
const mjml = require('../lib')
4+
5+
describe('mj-wrapper gap', function () {
6+
it('should render correct gap values in CSS style values on children mj-section', function () {
7+
const input = `
8+
<mjml>
9+
<mj-body>
10+
<mj-wrapper gap="20px" css-class="my-wrapper" background-color="#000">
11+
<mj-section css-class="my-section" background-color="#f45e43" padding="10px">
12+
<mj-column>
13+
<mj-text>Section 1</mj-text>
14+
</mj-column>
15+
</mj-section>
16+
<mj-section css-class="my-section" background-color="#ccc" padding="10px">
17+
<mj-column>
18+
<mj-text>Section 2</mj-text>
19+
</mj-column>
20+
</mj-section>
21+
<mj-section css-class="my-section" background-color="#333" padding="10px">
22+
<mj-column>
23+
<mj-text color="#fff">Section 3</mj-text>
24+
</mj-column>
25+
</mj-section>
26+
</mj-wrapper>
27+
</mj-body>
28+
</mjml>
29+
`
30+
31+
const { html } = mjml(input)
32+
33+
const $ = load(html)
34+
35+
// gap values should be correct
36+
chai
37+
.expect(
38+
$('.my-section')
39+
.map(function getAttr() {
40+
const str = $(this).attr('style')
41+
const substr = 'margin-top:'
42+
43+
if (str.includes(substr)) {
44+
const start = $(this).attr('style').indexOf(substr) + 11
45+
const end = $(this).attr('style').indexOf(';', start)
46+
return $(this).attr('style').substring(start, end)
47+
}
48+
return undefined
49+
})
50+
.get(),
51+
'Gap in CSS style values on mj-wrapper',
52+
)
53+
.to.eql(['20px', '20px'])
54+
})
55+
})

0 commit comments

Comments
 (0)