Created
April 12, 2018 14:21
-
-
Save homerjam/82f5f1d712b10ea1cf8b80f2cf088cdb to your computer and use it in GitHub Desktop.
mc-section: Mailchimp compatible MJML v4 component
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { BodyComponent } from 'mjml-core' | |
| import { flow, identity, join, filter } from 'lodash/fp' | |
| import widthParser from 'mjml-core/lib/helpers/widthParser' | |
| const makeBackgroundString = flow(filter(identity), join(' ')) | |
| export default class McSection extends BodyComponent { | |
| static allowedAttributes = { | |
| 'mc:hideable': 'boolean', | |
| 'mc:repeatable': 'string', | |
| 'mc:variant': 'string', | |
| 'background-color': 'color', | |
| 'background-url': 'string', | |
| 'background-repeat': 'enum(repeat/no-repeat)', | |
| 'background-size': 'string', | |
| border: 'string', | |
| 'border-bottom': 'string', | |
| 'border-left': 'string', | |
| 'border-radius': 'string', | |
| 'border-right': 'string', | |
| 'border-top': 'string', | |
| direction: 'enum(ltr,rtl)', | |
| 'full-width': 'enum(full-width)', | |
| padding: 'unit(px,%){1,4}', | |
| 'padding-top': 'unit(px,%)', | |
| 'padding-bottom': 'unit(px,%)', | |
| 'padding-left': 'unit(px,%)', | |
| 'padding-right': 'unit(px,%)', | |
| 'text-align': 'enum(left,center,right)', | |
| 'text-padding': 'unit(px,%){1,4}', | |
| 'vertical-align': 'enum(bottom,middle,top)', | |
| } | |
| static defaultAttributes = { | |
| 'background-repeat': 'repeat', | |
| 'background-size': 'auto', | |
| direction: 'ltr', | |
| padding: '20px 0', | |
| 'text-align': 'center', | |
| 'text-padding': '4px 4px 4px 0', | |
| 'vertical-align': 'top', | |
| } | |
| getChildContext() { | |
| const { containerWidth } = this.context | |
| const paddingSize = | |
| this.getShorthandAttrValue('padding', 'left') + | |
| this.getShorthandAttrValue('padding', 'right') | |
| const { parsedWidth } = widthParser(containerWidth, { | |
| parseFloatToInt: false, | |
| }) | |
| return { | |
| ...this.context, | |
| containerWidth: `${parsedWidth - paddingSize}px`, | |
| } | |
| } | |
| getStyles() { | |
| const { containerWidth } = this.context | |
| const fullWidth = this.isFullWidth() | |
| const background = this.getAttribute('background-url') | |
| ? { background: this.getBackground() } | |
| : { | |
| background: this.getAttribute('background-color'), | |
| 'background-color': this.getAttribute('background-color'), | |
| } | |
| return { | |
| tableFullwidth: { | |
| ...(fullWidth ? background : {}), | |
| width: '100%', | |
| 'border-radius': this.getAttribute('border-radius'), | |
| }, | |
| table: { | |
| ...(fullWidth ? {} : background), | |
| width: '100%', | |
| 'border-radius': this.getAttribute('border-radius'), | |
| }, | |
| td: { | |
| border: this.getAttribute('border'), | |
| 'border-bottom': this.getAttribute('border-bottom'), | |
| 'border-left': this.getAttribute('border-left'), | |
| 'border-right': this.getAttribute('border-right'), | |
| 'border-top': this.getAttribute('border-top'), | |
| direction: this.getAttribute('direction'), | |
| 'font-size': '0px', | |
| padding: this.getAttribute('padding'), | |
| 'padding-bottom': this.getAttribute('padding-bottom'), | |
| 'padding-left': this.getAttribute('padding-left'), | |
| 'padding-right': this.getAttribute('padding-right'), | |
| 'padding-top': this.getAttribute('padding-top'), | |
| 'text-align': this.getAttribute('text-align'), | |
| 'vertical-align': this.getAttribute('vertical-align'), | |
| }, | |
| div: { | |
| ...(fullWidth ? {} : background), | |
| Margin: '0px auto', | |
| 'border-radius': this.getAttribute('border-radius'), | |
| 'max-width': containerWidth, | |
| }, | |
| innerDiv: { | |
| 'line-height': '0', | |
| 'font-size': '0', | |
| }, | |
| } | |
| } | |
| getBackground = () => | |
| makeBackgroundString([ | |
| this.getAttribute('background-color'), | |
| ...(this.hasBackground() | |
| ? [ | |
| `url(${this.getAttribute('background-url')})`, | |
| `top center / ${this.getAttribute('background-size')}`, | |
| this.getAttribute('background-repeat'), | |
| ] | |
| : []), | |
| ]) | |
| hasBackground() { | |
| return this.getAttribute('background-url') != null | |
| } | |
| isFullWidth() { | |
| return this.getAttribute('full-width') === 'full-width' | |
| } | |
| renderBefore() { | |
| const { containerWidth } = this.context | |
| return ` | |
| <!--[if mso | IE]> | |
| <table | |
| ${this.htmlAttributes({ | |
| align: 'center', | |
| border: '0', | |
| cellpadding: '0', | |
| cellspacing: '0', | |
| class: this.getAttribute('css-class') | |
| ? this.getAttribute('css-class') | |
| .split(' ') | |
| .map(c => `${c}-outlook`) | |
| .join(' ') | |
| : null, | |
| style: { width: `${containerWidth}` }, | |
| width: parseInt(containerWidth, 10), | |
| })} | |
| > | |
| <tr> | |
| <td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"> | |
| <![endif]--> | |
| ` | |
| } | |
| renderAfter() { | |
| // eslint-disable-line class-methods-use-this | |
| return ` | |
| <!--[if mso | IE]> | |
| </td> | |
| </tr> | |
| </table> | |
| <![endif]--> | |
| ` | |
| } | |
| renderWrappedChildren() { | |
| const { children } = this.props | |
| return ` | |
| <!--[if mso | IE]> | |
| <tr> | |
| <![endif]--> | |
| ${this.renderChildren(children, { | |
| renderer: component => | |
| component.constructor.isRawElement() | |
| ? component.render() | |
| : ` | |
| <!--[if mso | IE]> | |
| <td | |
| ${component.htmlAttributes({ | |
| align: component.getAttribute('align'), | |
| class: component.getAttribute('css-class') | |
| ? component | |
| .getAttribute('css-class') | |
| .split(' ') | |
| .map(c => `${c}-outlook`) | |
| .join(' ') | |
| : null, | |
| style: 'tdOutlook', | |
| })} | |
| > | |
| <![endif]--> | |
| ${component.render()} | |
| <!--[if mso | IE]> | |
| </td> | |
| <![endif]--> | |
| `, | |
| })} | |
| <!--[if mso | IE]> | |
| </tr> | |
| <![endif]--> | |
| ` | |
| } | |
| renderWithBackground(content) { | |
| const fullWidth = this.isFullWidth() | |
| const { containerWidth } = this.context | |
| return ` | |
| <!--[if mso | IE]> | |
| <v:rect ${this.htmlAttributes({ | |
| style: fullWidth | |
| ? { 'mso-width-percent': '1000' } | |
| : { width: containerWidth }, | |
| 'xmlns:v': 'urn:schemas-microsoft-com:vml', | |
| fill: 'true', | |
| stroke: 'false', | |
| })}> | |
| <v:fill ${this.htmlAttributes({ | |
| origin: '0.5, 0', | |
| position: '0.5, 0', | |
| src: this.getAttribute('background-url'), | |
| color: this.getAttribute('background-color'), | |
| type: 'tile', | |
| })} /> | |
| <v:textbox style="mso-fit-shape-to-text:true" inset="0,0,0,0"> | |
| <![endif]--> | |
| ${content} | |
| <!--[if mso | IE]> | |
| </v:textbox> | |
| </v:rect> | |
| <![endif]--> | |
| ` | |
| } | |
| renderSection() { | |
| const hasBackground = this.hasBackground() | |
| return ` | |
| <div ${this.htmlAttributes({ | |
| class: this.isFullWidth() ? null : this.getAttribute('css-class'), | |
| style: 'div', | |
| 'mc:hideable': this.getAttribute('mc:hideable'), | |
| 'mc:repeatable': this.getAttribute('mc:repeatable'), | |
| 'mc:variant': this.getAttribute('mc:variant'), | |
| })}> | |
| ${hasBackground | |
| ? `<div ${this.htmlAttributes({ style: 'innerDiv' })}>` | |
| : ''} | |
| <table | |
| ${this.htmlAttributes({ | |
| align: 'center', | |
| background: this.isFullWidth() | |
| ? null | |
| : this.getAttribute('background-url'), | |
| border: '0', | |
| cellpadding: '0', | |
| cellspacing: '0', | |
| role: 'presentation', | |
| style: 'table', | |
| })} | |
| > | |
| <tbody> | |
| <tr> | |
| <td | |
| ${this.htmlAttributes({ | |
| style: 'td', | |
| })} | |
| > | |
| <!--[if mso | IE]> | |
| <table role="presentation" border="0" cellpadding="0" cellspacing="0"> | |
| <![endif]--> | |
| ${this.renderWrappedChildren()} | |
| <!--[if mso | IE]> | |
| </table> | |
| <![endif]--> | |
| </td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| ${hasBackground ? '</div>' : ''} | |
| </div> | |
| ` | |
| } | |
| renderFullWidth() { | |
| const content = this.hasBackground() | |
| ? this.renderWithBackground(` | |
| ${this.renderBefore()} | |
| ${this.renderSection()} | |
| ${this.renderAfter()} | |
| `) | |
| : ` | |
| ${this.renderBefore()} | |
| ${this.renderSection()} | |
| ${this.renderAfter()} | |
| ` | |
| return ` | |
| <table | |
| ${this.htmlAttributes({ | |
| align: 'center', | |
| class: this.getAttribute('css-class'), | |
| background: this.getAttribute('background-url'), | |
| border: '0', | |
| cellpadding: '0', | |
| cellspacing: '0', | |
| role: 'presentation', | |
| style: 'tableFullwidth', | |
| })} | |
| > | |
| <tbody> | |
| <tr> | |
| <td> | |
| ${content} | |
| </td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| ` | |
| } | |
| renderSimple() { | |
| const section = this.renderSection() | |
| return ` | |
| ${this.renderBefore()} | |
| ${this.hasBackground() ? this.renderWithBackground(section) : section} | |
| ${this.renderAfter()} | |
| ` | |
| } | |
| render() { | |
| return this.isFullWidth() ? this.renderFullWidth() : this.renderSimple() | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment