emjay 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +158 -0
  4. data/lib/emjay/body_component.rb +142 -0
  5. data/lib/emjay/component.rb +61 -0
  6. data/lib/emjay/components/body/mj_accordion.rb +99 -0
  7. data/lib/emjay/components/body/mj_accordion_element.rb +127 -0
  8. data/lib/emjay/components/body/mj_accordion_text.rb +123 -0
  9. data/lib/emjay/components/body/mj_accordion_title.rb +171 -0
  10. data/lib/emjay/components/body/mj_body.rb +70 -0
  11. data/lib/emjay/components/body/mj_button.rb +198 -0
  12. data/lib/emjay/components/body/mj_carousel.rb +410 -0
  13. data/lib/emjay/components/body/mj_carousel_image.rb +188 -0
  14. data/lib/emjay/components/body/mj_column.rb +287 -0
  15. data/lib/emjay/components/body/mj_divider.rb +120 -0
  16. data/lib/emjay/components/body/mj_group.rb +196 -0
  17. data/lib/emjay/components/body/mj_hero.rb +382 -0
  18. data/lib/emjay/components/body/mj_image.rb +188 -0
  19. data/lib/emjay/components/body/mj_navbar.rb +187 -0
  20. data/lib/emjay/components/body/mj_navbar_link.rb +129 -0
  21. data/lib/emjay/components/body/mj_raw.rb +34 -0
  22. data/lib/emjay/components/body/mj_section.rb +442 -0
  23. data/lib/emjay/components/body/mj_social.rb +174 -0
  24. data/lib/emjay/components/body/mj_social_element.rb +272 -0
  25. data/lib/emjay/components/body/mj_spacer.rb +57 -0
  26. data/lib/emjay/components/body/mj_table.rb +113 -0
  27. data/lib/emjay/components/body/mj_text.rb +100 -0
  28. data/lib/emjay/components/body/mj_wrapper.rb +56 -0
  29. data/lib/emjay/components/head/mj_attributes.rb +38 -0
  30. data/lib/emjay/components/head/mj_breakpoint.rb +28 -0
  31. data/lib/emjay/components/head/mj_font.rb +24 -0
  32. data/lib/emjay/components/head/mj_head.rb +20 -0
  33. data/lib/emjay/components/head/mj_html_attributes.rb +33 -0
  34. data/lib/emjay/components/head/mj_preview.rb +24 -0
  35. data/lib/emjay/components/head/mj_style.rb +34 -0
  36. data/lib/emjay/components/head/mj_title.rb +24 -0
  37. data/lib/emjay/global_data.rb +64 -0
  38. data/lib/emjay/head_component.rb +37 -0
  39. data/lib/emjay/helpers/conditional_tag.rb +24 -0
  40. data/lib/emjay/helpers/fonts.rb +34 -0
  41. data/lib/emjay/helpers/gen_random_hex_string.rb +9 -0
  42. data/lib/emjay/helpers/make_lower_breakpoint.rb +17 -0
  43. data/lib/emjay/helpers/media_queries.rb +47 -0
  44. data/lib/emjay/helpers/merge_outlook_conditionals.rb +11 -0
  45. data/lib/emjay/helpers/minify_outlook_conditionals.rb +18 -0
  46. data/lib/emjay/helpers/shorthand_parser.rb +33 -0
  47. data/lib/emjay/helpers/styles.rb +34 -0
  48. data/lib/emjay/helpers/suffix_css_classes.rb +12 -0
  49. data/lib/emjay/helpers/width_parser.rb +26 -0
  50. data/lib/emjay/rails/mail_interceptor.rb +37 -0
  51. data/lib/emjay/rails/template_handler.rb +16 -0
  52. data/lib/emjay/railtie.rb +21 -0
  53. data/lib/emjay/registry.rb +19 -0
  54. data/lib/emjay/renderer.rb +302 -0
  55. data/lib/emjay/skeleton.rb +80 -0
  56. data/lib/emjay/version.rb +5 -0
  57. data/lib/emjay.rb +66 -0
  58. data/llms.txt +130 -0
  59. metadata +129 -0
@@ -0,0 +1,272 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../body_component"
4
+ require_relative "../../registry"
5
+
6
+ module Emjay
7
+ module Components
8
+ class MjSocialElement < BodyComponent
9
+ IMG_BASE_URL = "https://www.mailjet.com/images/theme/v1/icons/ico-social/"
10
+
11
+ DEFAULT_SOCIAL_NETWORKS = {
12
+ "facebook" => {"share-url" => "https://www.facebook.com/sharer/sharer.php?u=[[URL]]", "background-color" => "#3b5998", "src" => "#{IMG_BASE_URL}facebook.png"},
13
+ "twitter" => {"share-url" => "https://twitter.com/intent/tweet?url=[[URL]]", "background-color" => "#55acee", "src" => "#{IMG_BASE_URL}twitter.png"},
14
+ "x" => {"share-url" => "https://twitter.com/intent/tweet?url=[[URL]]", "background-color" => "#000000", "src" => "#{IMG_BASE_URL}twitter-x.png"},
15
+ "google" => {"share-url" => "https://plus.google.com/share?url=[[URL]]", "background-color" => "#dc4e41", "src" => "#{IMG_BASE_URL}google-plus.png"},
16
+ "pinterest" => {"share-url" => "https://pinterest.com/pin/create/button/?url=[[URL]]&media=&description=", "background-color" => "#bd081c", "src" => "#{IMG_BASE_URL}pinterest.png"},
17
+ "linkedin" => {"share-url" => "https://www.linkedin.com/shareArticle?mini=true&url=[[URL]]&title=&summary=&source=", "background-color" => "#0077b5", "src" => "#{IMG_BASE_URL}linkedin.png"},
18
+ "instagram" => {"background-color" => "#3f729b", "src" => "#{IMG_BASE_URL}instagram.png"},
19
+ "web" => {"src" => "#{IMG_BASE_URL}web.png", "background-color" => "#4BADE9"},
20
+ "snapchat" => {"src" => "#{IMG_BASE_URL}snapchat.png", "background-color" => "#FFFA54"},
21
+ "youtube" => {"src" => "#{IMG_BASE_URL}youtube.png", "background-color" => "#EB3323"},
22
+ "tumblr" => {"src" => "#{IMG_BASE_URL}tumblr.png", "share-url" => "https://www.tumblr.com/widgets/share/tool?canonicalUrl=[[URL]]", "background-color" => "#344356"},
23
+ "github" => {"src" => "#{IMG_BASE_URL}github.png", "background-color" => "#000000"},
24
+ "xing" => {"src" => "#{IMG_BASE_URL}xing.png", "share-url" => "https://www.xing.com/app/user?op=share&url=[[URL]]", "background-color" => "#296366"},
25
+ "vimeo" => {"src" => "#{IMG_BASE_URL}vimeo.png", "background-color" => "#53B4E7"},
26
+ "medium" => {"src" => "#{IMG_BASE_URL}medium.png", "background-color" => "#000000"},
27
+ "soundcloud" => {"src" => "#{IMG_BASE_URL}soundcloud.png", "background-color" => "#EF7F31"},
28
+ "dribbble" => {"src" => "#{IMG_BASE_URL}dribbble.png", "background-color" => "#D95988"}
29
+ }.freeze
30
+
31
+ # Build noshare variants
32
+ SOCIAL_NETWORKS = DEFAULT_SOCIAL_NETWORKS.each_with_object({}) { |(key, val), hash|
33
+ hash[key] = val
34
+ hash["#{key}-noshare"] = val.merge("share-url" => "[[URL]]")
35
+ }.freeze
36
+
37
+ def self.component_name
38
+ "mj-social-element"
39
+ end
40
+
41
+ def self.ending_tag?
42
+ true
43
+ end
44
+
45
+ def self.default_attributes
46
+ {
47
+ "alt" => "",
48
+ "align" => "left",
49
+ "icon-position" => "left",
50
+ "color" => "#000",
51
+ "border-radius" => "3px",
52
+ "font-family" => "Ubuntu, Helvetica, Arial, sans-serif",
53
+ "font-size" => "13px",
54
+ "line-height" => "1",
55
+ "padding" => "4px",
56
+ "text-padding" => "4px 4px 4px 0",
57
+ "target" => "_blank",
58
+ "text-decoration" => "none",
59
+ "vertical-align" => "middle"
60
+ }
61
+ end
62
+
63
+ def self.allowed_attributes
64
+ {
65
+ "align" => "enum(left,center,right)",
66
+ "icon-position" => "enum(left,right)",
67
+ "background-color" => "color",
68
+ "color" => "color",
69
+ "border-radius" => "string",
70
+ "font-family" => "string",
71
+ "font-size" => "unit(px)",
72
+ "font-style" => "string",
73
+ "font-weight" => "string",
74
+ "href" => "string",
75
+ "icon-size" => "unit(px,%)",
76
+ "icon-height" => "unit(px,%)",
77
+ "icon-padding" => "unit(px,%){1,4}",
78
+ "line-height" => "unit(px,%,)",
79
+ "name" => "string",
80
+ "padding-bottom" => "unit(px,%)",
81
+ "padding-left" => "unit(px,%)",
82
+ "padding-right" => "unit(px,%)",
83
+ "padding-top" => "unit(px,%)",
84
+ "padding" => "unit(px,%){1,4}",
85
+ "text-padding" => "unit(px,%){1,4}",
86
+ "rel" => "string",
87
+ "src" => "string",
88
+ "srcset" => "string",
89
+ "sizes" => "string",
90
+ "alt" => "string",
91
+ "title" => "string",
92
+ "target" => "string",
93
+ "text-decoration" => "string",
94
+ "vertical-align" => "enum(top,middle,bottom)"
95
+ }
96
+ end
97
+
98
+ def get_styles
99
+ social = get_social_attributes
100
+ icon_size = social["icon-size"]
101
+ icon_height = social["icon-height"]
102
+ bg_color = social["background-color"]
103
+
104
+ {
105
+ td: {
106
+ "padding" => get_attribute("padding"),
107
+ "padding-top" => get_attribute("padding-top"),
108
+ "padding-right" => get_attribute("padding-right"),
109
+ "padding-bottom" => get_attribute("padding-bottom"),
110
+ "padding-left" => get_attribute("padding-left"),
111
+ "vertical-align" => get_attribute("vertical-align")
112
+ },
113
+ table: {
114
+ "background" => bg_color,
115
+ "border-radius" => get_attribute("border-radius"),
116
+ "width" => icon_size
117
+ },
118
+ icon: {
119
+ "padding" => get_attribute("icon-padding"),
120
+ "font-size" => "0",
121
+ "height" => icon_height || icon_size,
122
+ "vertical-align" => "middle",
123
+ "width" => icon_size
124
+ },
125
+ img: {
126
+ "border-radius" => get_attribute("border-radius"),
127
+ "display" => "block"
128
+ },
129
+ tdText: {
130
+ "vertical-align" => "middle",
131
+ "padding" => get_attribute("text-padding"),
132
+ "text-align" => get_attribute("align")
133
+ },
134
+ text: {
135
+ "color" => get_attribute("color"),
136
+ "font-size" => get_attribute("font-size"),
137
+ "font-weight" => get_attribute("font-weight"),
138
+ "font-style" => get_attribute("font-style"),
139
+ "font-family" => get_attribute("font-family"),
140
+ "line-height" => get_attribute("line-height"),
141
+ "text-decoration" => get_attribute("text-decoration")
142
+ }
143
+ }
144
+ end
145
+
146
+ def render
147
+ social = get_social_attributes
148
+ src = social["src"]
149
+ srcset = social["srcset"]
150
+ sizes = social["sizes"]
151
+ href = social["href"]
152
+ icon_size = social["icon-size"]
153
+
154
+ has_link = !!get_attribute("href")
155
+ icon_position = get_attribute("icon-position")
156
+
157
+ icon_html = render_icon(src, srcset, sizes, href, icon_size, has_link)
158
+ content_html = render_text_content(href, has_link)
159
+
160
+ tr_attrs = html_attributes(class: get_attribute("css-class"))
161
+
162
+ parts = if icon_position == "left"
163
+ "#{icon_html} #{content_html}"
164
+ else
165
+ "#{content_html} #{icon_html}"
166
+ end
167
+
168
+ <<~HTML
169
+ <tr
170
+ #{tr_attrs}
171
+ >
172
+ #{parts}
173
+ </tr>
174
+ HTML
175
+ end
176
+
177
+ private
178
+
179
+ def get_social_attributes
180
+ network = SOCIAL_NETWORKS[get_attribute("name")] || {}
181
+ href = get_attribute("href")
182
+
183
+ if href && network["share-url"]
184
+ href = network["share-url"].gsub("[[URL]]", href)
185
+ end
186
+
187
+ attrs = %w[icon-size icon-height srcset sizes src background-color].each_with_object({}) do |attr, result|
188
+ result[attr] = get_attribute(attr) || network[attr]
189
+ end
190
+
191
+ attrs.merge("href" => href)
192
+ end
193
+
194
+ def render_icon(src, srcset, sizes, href, icon_size, has_link)
195
+ td_attrs = html_attributes(style: :td)
196
+ table_attrs = html_attributes(
197
+ border: "0",
198
+ cellpadding: "0",
199
+ cellspacing: "0",
200
+ role: "presentation",
201
+ style: :table
202
+ )
203
+ icon_td_attrs = html_attributes(style: :icon)
204
+
205
+ a_open = has_link ? "<a#{html_attributes(href: href, rel: get_attribute("rel"), target: get_attribute("target"))}>" : ""
206
+ a_close = has_link ? "</a>" : ""
207
+
208
+ img_attrs = html_attributes(
209
+ alt: get_attribute("alt"),
210
+ title: get_attribute("title"),
211
+ src: src,
212
+ style: :img,
213
+ width: icon_size.to_i,
214
+ sizes: sizes,
215
+ srcset: srcset
216
+ )
217
+
218
+ <<~HTML
219
+ <td#{td_attrs}>
220
+ <table
221
+ #{table_attrs}
222
+ >
223
+ <tbody>
224
+ <tr>
225
+ <td#{icon_td_attrs}>
226
+ #{a_open}
227
+ <img
228
+ #{img_attrs}
229
+ />
230
+ #{a_close}
231
+ </td>
232
+ </tr>
233
+ </tbody>
234
+ </table>
235
+ </td>
236
+ HTML
237
+ end
238
+
239
+ def render_text_content(href, has_link)
240
+ content = get_content
241
+ return "" if content.nil? || content.empty?
242
+
243
+ td_text_attrs = html_attributes(style: :tdText)
244
+
245
+ if has_link
246
+ a_attrs = html_attributes(
247
+ href: href,
248
+ style: :text,
249
+ rel: get_attribute("rel"),
250
+ target: get_attribute("target")
251
+ )
252
+ <<~HTML
253
+ <td#{td_text_attrs}>
254
+ <a#{a_attrs}>
255
+ #{content}
256
+ </a>
257
+ </td>
258
+ HTML
259
+ else
260
+ span_attrs = html_attributes(style: :text)
261
+ <<~HTML
262
+ <td#{td_text_attrs}>
263
+ <span#{span_attrs}>#{content}</span>
264
+ </td>
265
+ HTML
266
+ end
267
+ end
268
+ end
269
+ end
270
+
271
+ Registry.register(Components::MjSocialElement)
272
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../body_component"
4
+ require_relative "../../registry"
5
+
6
+ module Emjay
7
+ module Components
8
+ class MjSpacer < BodyComponent
9
+ def self.component_name
10
+ "mj-spacer"
11
+ end
12
+
13
+ def self.default_attributes
14
+ {
15
+ "height" => "20px"
16
+ }
17
+ end
18
+
19
+ def self.allowed_attributes
20
+ {
21
+ "border" => "string",
22
+ "border-bottom" => "string",
23
+ "border-left" => "string",
24
+ "border-right" => "string",
25
+ "border-top" => "string",
26
+ "container-background-color" => "color",
27
+ "padding-bottom" => "unit(px,%)",
28
+ "padding-left" => "unit(px,%)",
29
+ "padding-right" => "unit(px,%)",
30
+ "padding-top" => "unit(px,%)",
31
+ "padding" => "unit(px,%){1,4}",
32
+ "height" => "unit(px,%)"
33
+ }
34
+ end
35
+
36
+ def get_styles
37
+ {
38
+ div: {
39
+ "height" => get_attribute("height"),
40
+ "line-height" => get_attribute("height")
41
+ }
42
+ }
43
+ end
44
+
45
+ def render
46
+ div_attrs = html_attributes(style: :div)
47
+ <<~HTML
48
+ <div
49
+ #{div_attrs}
50
+ >&#8202;</div>
51
+ HTML
52
+ end
53
+ end
54
+ end
55
+
56
+ Registry.register(Components::MjSpacer)
57
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../body_component"
4
+ require_relative "../../registry"
5
+ require_relative "../../helpers/width_parser"
6
+
7
+ module Emjay
8
+ module Components
9
+ class MjTable < BodyComponent
10
+ def self.component_name
11
+ "mj-table"
12
+ end
13
+
14
+ def self.ending_tag?
15
+ true
16
+ end
17
+
18
+ def self.default_attributes
19
+ {
20
+ "align" => "left",
21
+ "border" => "none",
22
+ "cellpadding" => "0",
23
+ "cellspacing" => "0",
24
+ "color" => "#000000",
25
+ "font-family" => "Ubuntu, Helvetica, Arial, sans-serif",
26
+ "font-size" => "13px",
27
+ "line-height" => "22px",
28
+ "padding" => "10px 25px",
29
+ "table-layout" => "auto",
30
+ "width" => "100%"
31
+ }
32
+ end
33
+
34
+ def self.allowed_attributes
35
+ {
36
+ "align" => "enum(left,right,center)",
37
+ "border" => "string",
38
+ "cellpadding" => "integer",
39
+ "cellspacing" => "integer",
40
+ "container-background-color" => "color",
41
+ "color" => "color",
42
+ "font-family" => "string",
43
+ "font-size" => "unit(px)",
44
+ "font-weight" => "string",
45
+ "line-height" => "unit(px,%,)",
46
+ "padding-bottom" => "unit(px,%)",
47
+ "padding-left" => "unit(px,%)",
48
+ "padding-right" => "unit(px,%)",
49
+ "padding-top" => "unit(px,%)",
50
+ "padding" => "unit(px,%){1,4}",
51
+ "role" => "enum(none,presentation)",
52
+ "table-layout" => "enum(auto,fixed,initial,inherit)",
53
+ "vertical-align" => "enum(top,bottom,middle)",
54
+ "width" => "unit(px,%,auto)"
55
+ }
56
+ end
57
+
58
+ def get_styles
59
+ table_styles = {
60
+ "color" => get_attribute("color"),
61
+ "font-family" => get_attribute("font-family"),
62
+ "font-size" => get_attribute("font-size"),
63
+ "line-height" => get_attribute("line-height"),
64
+ "table-layout" => get_attribute("table-layout"),
65
+ "width" => get_attribute("width"),
66
+ "border" => get_attribute("border")
67
+ }
68
+
69
+ table_styles["border-collapse"] = "separate" if has_cellspacing?
70
+
71
+ {table: table_styles}
72
+ end
73
+
74
+ def render
75
+ table_attrs = html_attributes(
76
+ cellpadding: get_attribute("cellpadding"),
77
+ cellspacing: get_attribute("cellspacing"),
78
+ role: get_attribute("role"),
79
+ width: get_width,
80
+ border: "0",
81
+ style: :table
82
+ )
83
+ <<~HTML
84
+ <table
85
+ #{table_attrs}
86
+ >
87
+ #{get_content}
88
+ </table>
89
+ HTML
90
+ end
91
+
92
+ private
93
+
94
+ def get_width
95
+ width = get_attribute("width")
96
+ return width if width == "auto"
97
+
98
+ parsed = WidthParser.call(width)
99
+ (parsed[:unit] == "%") ? width : parsed[:parsed_width]
100
+ end
101
+
102
+ def has_cellspacing?
103
+ cellspacing = get_attribute("cellspacing")
104
+ numeric_value = cellspacing.to_s.gsub(/[^\d.]/, "").to_f
105
+ !numeric_value.nan? && numeric_value > 0
106
+ rescue
107
+ false
108
+ end
109
+ end
110
+ end
111
+
112
+ Registry.register(Components::MjTable)
113
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../body_component"
4
+ require_relative "../../registry"
5
+ require_relative "../../helpers/conditional_tag"
6
+
7
+ module Emjay
8
+ module Components
9
+ class MjText < BodyComponent
10
+ def self.component_name
11
+ "mj-text"
12
+ end
13
+
14
+ def self.ending_tag?
15
+ true
16
+ end
17
+
18
+ def self.default_attributes
19
+ {
20
+ "align" => "left",
21
+ "color" => "#000000",
22
+ "font-family" => "Ubuntu, Helvetica, Arial, sans-serif",
23
+ "font-size" => "13px",
24
+ "line-height" => "1",
25
+ "padding" => "10px 25px"
26
+ }
27
+ end
28
+
29
+ def self.allowed_attributes
30
+ {
31
+ "align" => "enum(left,right,center,justify)",
32
+ "background-color" => "color",
33
+ "color" => "color",
34
+ "container-background-color" => "color",
35
+ "font-family" => "string",
36
+ "font-size" => "unit(px)",
37
+ "font-style" => "string",
38
+ "font-weight" => "string",
39
+ "height" => "unit(px,%)",
40
+ "letter-spacing" => "unitWithNegative(px,em)",
41
+ "line-height" => "unit(px,%,)",
42
+ "padding-bottom" => "unit(px,%)",
43
+ "padding-left" => "unit(px,%)",
44
+ "padding-right" => "unit(px,%)",
45
+ "padding-top" => "unit(px,%)",
46
+ "padding" => "unit(px,%){1,4}",
47
+ "text-decoration" => "string",
48
+ "text-transform" => "string",
49
+ "vertical-align" => "enum(top,bottom,middle)"
50
+ }
51
+ end
52
+
53
+ def get_styles
54
+ {
55
+ text: {
56
+ "font-family" => get_attribute("font-family"),
57
+ "font-size" => get_attribute("font-size"),
58
+ "font-style" => get_attribute("font-style"),
59
+ "font-weight" => get_attribute("font-weight"),
60
+ "letter-spacing" => get_attribute("letter-spacing"),
61
+ "line-height" => get_attribute("line-height"),
62
+ "text-align" => get_attribute("align"),
63
+ "text-decoration" => get_attribute("text-decoration"),
64
+ "text-transform" => get_attribute("text-transform"),
65
+ "color" => get_attribute("color"),
66
+ "height" => get_attribute("height")
67
+ }
68
+ }
69
+ end
70
+
71
+ def render
72
+ height = get_attribute("height")
73
+
74
+ if height
75
+ <<~HTML
76
+ #{ConditionalTag.conditional_tag(
77
+ "<table role=\"presentation\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr><td height=\"#{height}\" style=\"vertical-align:top;height:#{height};\">"
78
+ )}
79
+ #{render_content}
80
+ #{ConditionalTag.conditional_tag(
81
+ "</td></tr></table>"
82
+ )}
83
+ HTML
84
+ else
85
+ render_content
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def render_content
92
+ <<~HTML
93
+ <div#{html_attributes(style: :text)}>#{get_content}</div>
94
+ HTML
95
+ end
96
+ end
97
+ end
98
+
99
+ Registry.register(Components::MjText)
100
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "mj_section"
4
+
5
+ module Emjay
6
+ module Components
7
+ class MjWrapper < MjSection
8
+ def self.component_name
9
+ "mj-wrapper"
10
+ end
11
+
12
+ def self.allowed_attributes
13
+ MjSection.allowed_attributes.merge("gap" => "unit(px)")
14
+ end
15
+
16
+ def get_child_context
17
+ widths = get_box_widths
18
+ @context.merge(
19
+ container_width: "#{widths[:box]}px",
20
+ gap: get_attribute("gap")
21
+ )
22
+ end
23
+
24
+ private
25
+
26
+ def render_wrapped_children
27
+ children = @props[:children] || []
28
+ container_width = @context[:container_width]
29
+
30
+ render_children(children, renderer: ->(component) {
31
+ if component.class.raw_element?
32
+ component.render
33
+ else
34
+ <<~HTML
35
+ <!--[if mso | IE]>
36
+ <tr>
37
+ <td#{component.html_attributes(
38
+ align: component.get_attribute("align"),
39
+ class: SuffixCssClasses.call(component.get_attribute("css-class"), "outlook"),
40
+ width: container_width
41
+ )}>
42
+ <![endif]-->
43
+ #{component.render}
44
+ <!--[if mso | IE]>
45
+ </td>
46
+ </tr>
47
+ <![endif]-->
48
+ HTML
49
+ end
50
+ })
51
+ end
52
+ end
53
+ end
54
+
55
+ Registry.register(Components::MjWrapper)
56
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../head_component"
4
+ require_relative "../../registry"
5
+
6
+ module Emjay
7
+ module Components
8
+ class MjAttributes < HeadComponent
9
+ def self.component_name
10
+ "mj-attributes"
11
+ end
12
+
13
+ def handler
14
+ add = @context[:add]
15
+ children = @props[:children] || []
16
+
17
+ children.each do |child|
18
+ tag_name = child[:tag_name]
19
+ attributes = child[:attributes] || {}
20
+ child_children = child[:children] || []
21
+
22
+ if tag_name == "mj-class"
23
+ name = attributes["name"]
24
+ add.call(:classes, name, attributes.except("name"))
25
+ add.call(:classes_default, name,
26
+ child_children.each_with_object({}) { |cc, acc|
27
+ acc[cc[:tag_name]] = cc[:attributes] || {}
28
+ })
29
+ else
30
+ add.call(:default_attributes, tag_name, attributes)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ Registry.register(Components::MjAttributes)
38
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../head_component"
4
+ require_relative "../../registry"
5
+
6
+ module Emjay
7
+ module Components
8
+ class MjBreakpoint < HeadComponent
9
+ def self.component_name
10
+ "mj-breakpoint"
11
+ end
12
+
13
+ def self.ending_tag?
14
+ true
15
+ end
16
+
17
+ def self.allowed_attributes
18
+ {"width" => "unit(px)"}
19
+ end
20
+
21
+ def handler
22
+ @context[:add].call(:breakpoint, get_attribute("width"))
23
+ end
24
+ end
25
+ end
26
+
27
+ Registry.register(Components::MjBreakpoint)
28
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../head_component"
4
+ require_relative "../../registry"
5
+
6
+ module Emjay
7
+ module Components
8
+ class MjFont < HeadComponent
9
+ def self.component_name
10
+ "mj-font"
11
+ end
12
+
13
+ def self.allowed_attributes
14
+ {"name" => "string", "href" => "string"}
15
+ end
16
+
17
+ def handler
18
+ @context[:add].call(:fonts, get_attribute("name"), get_attribute("href"))
19
+ end
20
+ end
21
+ end
22
+
23
+ Registry.register(Components::MjFont)
24
+ end