mjml-rb 0.2.13 → 0.2.14

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c54cb0ddf9071b81422853dfcca7e3748ed404b7ea1afba2a99ce9a42229d01
4
- data.tar.gz: 7d2469230fa62b2dd52df43e3e8858f1a38aeb5964469af5ec8669182664e9f8
3
+ metadata.gz: 2d1dc49d39635e3f4530f642a8699646f3bff8e545213387f91d95bb461ea67d
4
+ data.tar.gz: 15139737ec96a78601bd7d0e0a992b8743060d4923664eea05462a76e70dc7d3
5
5
  SHA512:
6
- metadata.gz: 8e349fdbec211923111e8ce2f7a593f46f18308aef3461c531dc3fa6ccfdf97d024c8b181e0289c0b8819db272d49fd3c45c2130298373a8867f6f8f19f14916
7
- data.tar.gz: 9603224d7e49fc263441767a0d3a289bd5bbba4cdf93afebc07b1dd7dd0416f8cd5e0161843d50d31e2f21b6390be8a946569027c52f19ab4d6605442544507b
6
+ metadata.gz: 486e95fb106f03ebb1ae929ec548996f9d53868b360fcff23cfd0aa28d9e4240e3a3181f611b3270837c9012e523c32f3089c0ebe3a82e9bd6e067735a955bec
7
+ data.tar.gz: 5bf0eb72f669aed9eb59dc1b8fbe16563082392bbc8d05e2f8d4ce4098a492606303cea65692757fdf5b8eed2c0fc2be7080daeac73f6f242b0a1dfc1c0d5551
data/README.md CHANGED
@@ -44,7 +44,7 @@ The table below tracks current JS-to-Ruby migration status for MJML components i
44
44
  | `mj-section` | migrated | Implemented in `section.rb`. |
45
45
  | `mj-wrapper` | migrated | Implemented via `section.rb`. |
46
46
  | `mj-column` | migrated | Implemented in `column.rb`. |
47
- | `mj-group` | migrated | Rendered directly by the renderer. |
47
+ | `mj-group` | migrated | Implemented in `group.rb`, including width-aware child rendering and Outlook table wrappers. |
48
48
  | `mj-text` | migrated | Implemented in `text.rb`. |
49
49
  | `mj-image` | migrated | Implemented in `image.rb`. |
50
50
  | `mj-button` | migrated | Implemented in `button.rb`. |
@@ -0,0 +1,134 @@
1
+ require_relative "base"
2
+
3
+ module MjmlRb
4
+ module Components
5
+ class Group < Base
6
+ TAGS = ["mj-group"].freeze
7
+
8
+ ALLOWED_ATTRIBUTES = {
9
+ "background-color" => "color",
10
+ "direction" => "enum(ltr,rtl)",
11
+ "vertical-align" => "enum(top,bottom,middle)",
12
+ "width" => "unit(px,%)"
13
+ }.freeze
14
+
15
+ DEFAULT_ATTRIBUTES = {
16
+ "direction" => "ltr"
17
+ }.freeze
18
+
19
+ def tags
20
+ TAGS
21
+ end
22
+
23
+ def render(tag_name:, node:, context:, attrs:, parent:)
24
+ width_pct = context.delete(:_column_width_pct) || 100.0
25
+ a = DEFAULT_ATTRIBUTES.merge(attrs)
26
+ css_class = a["css-class"]
27
+
28
+ pct_str = width_pct.to_f.to_s.sub(/\.?0+$/, "")
29
+ class_suffix = pct_str.gsub(".", "-")
30
+ context[:column_widths][class_suffix] = pct_str if context[:column_widths]
31
+
32
+ group_class = "mj-column-per-#{class_suffix} mj-outlook-group-fix"
33
+ group_class = "#{group_class} #{css_class}" if css_class && !css_class.empty?
34
+
35
+ group_width = group_container_width(context, a, width_pct)
36
+ div_style = style_join(
37
+ "font-size" => "0",
38
+ "line-height" => "0",
39
+ "text-align" => "left",
40
+ "display" => "inline-block",
41
+ "width" => "100%",
42
+ "direction" => a["direction"],
43
+ "vertical-align" => a["vertical-align"],
44
+ "background-color" => a["background-color"]
45
+ )
46
+
47
+ inner = with_group_container_width(context, group_width) do
48
+ render_group_children(node, context, a, group_width)
49
+ end
50
+
51
+ %(<div class="#{escape_attr(group_class)}" style="#{div_style}">#{inner}</div>)
52
+ end
53
+
54
+ private
55
+
56
+ def render_group_children(node, context, attrs, group_width)
57
+ columns = node.element_children.select { |child| child.tag_name == "mj-column" }
58
+ widths = renderer.send(:compute_column_widths, columns, context)
59
+ group_width_px = parse_pixel_value(group_width)
60
+ group_bg = attrs["background-color"]
61
+ table_attrs = {
62
+ "bgcolor" => (group_bg == "none" ? nil : group_bg),
63
+ "border" => "0",
64
+ "cellpadding" => "0",
65
+ "cellspacing" => "0",
66
+ "role" => "presentation"
67
+ }
68
+
69
+ open_table = %(<!--[if mso | IE]><table#{html_attrs(table_attrs)}><tr><![endif]-->)
70
+ close_table = %(<!--[if mso | IE]></tr></table><![endif]-->)
71
+ column_index = 0
72
+
73
+ body = with_inherited_mj_class(context, node) do
74
+ node.children.map do |child|
75
+ case child.tag_name
76
+ when "mj-column"
77
+ width_pct = widths[column_index] || 100.0
78
+ column_index += 1
79
+ context[:_column_width_pct] = width_pct
80
+ td_style = style_join(
81
+ "vertical-align" => resolved_attributes(child, context)["vertical-align"] || "top",
82
+ "width" => "#{(group_width_px * width_pct / 100.0).round}px"
83
+ )
84
+ td_open = %(<!--[if mso | IE]><td#{html_attrs("style" => td_style)}><![endif]-->)
85
+ td_close = %(<!--[if mso | IE]></td><![endif]-->)
86
+ "#{td_open}#{render_node(child, context, parent: "mj-group")}#{td_close}"
87
+ when "mj-raw"
88
+ render_node(child, context, parent: "mj-group")
89
+ else
90
+ render_node(child, context, parent: "mj-group")
91
+ end
92
+ end.join("\n")
93
+ end
94
+
95
+ "#{open_table}#{body}#{close_table}"
96
+ end
97
+
98
+ def with_group_container_width(context, width)
99
+ previous = context[:container_width]
100
+ context[:container_width] = width
101
+ yield
102
+ ensure
103
+ context[:container_width] = previous
104
+ end
105
+
106
+ def group_container_width(context, attrs, width_pct)
107
+ parent_width = parse_pixel_value(context[:container_width] || "600px")
108
+ width = attrs["width"]
109
+
110
+ raw_width =
111
+ if present_attr?(width) && width.end_with?("%")
112
+ parent_width * parse_pixel_value(width) / 100.0
113
+ elsif present_attr?(width) && width.end_with?("px")
114
+ parse_pixel_value(width)
115
+ else
116
+ parent_width * width_pct / 100.0
117
+ end
118
+
119
+ "#{[raw_width, 0].max}px"
120
+ end
121
+
122
+ def present_attr?(value)
123
+ value && !value.empty?
124
+ end
125
+
126
+ def parse_pixel_value(value)
127
+ return 0.0 unless present_attr?(value)
128
+
129
+ matched = value.to_s.match(/(-?\d+(?:\.\d+)?)/)
130
+ matched ? matched[1].to_f : 0.0
131
+ end
132
+ end
133
+ end
134
+ end
@@ -233,12 +233,8 @@ module MjmlRb
233
233
  td_open = %(<!--[if mso | IE]><td class="" style="vertical-align:#{v_align};width:#{col_px}px;" ><![endif]-->)
234
234
  td_close = %(<!--[if mso | IE]></td><![endif]-->)
235
235
 
236
- col_html = if col.tag_name == "mj-group"
237
- renderer.send(:render_group, col, context, widths[i])
238
- else
239
- context[:_column_width_pct] = widths[i]
240
- render_node(col, context, parent: "mj-section")
241
- end
236
+ context[:_column_width_pct] = widths[i]
237
+ col_html = render_node(col, context, parent: "mj-section")
242
238
 
243
239
  "#{td_open}\n#{col_html}\n#{td_close}"
244
240
  end
@@ -7,6 +7,7 @@ require_relative "components/breakpoint"
7
7
  require_relative "components/button"
8
8
  require_relative "components/carousel"
9
9
  require_relative "components/carousel_image"
10
+ require_relative "components/group"
10
11
  require_relative "components/head"
11
12
  require_relative "components/hero"
12
13
  require_relative "components/image"
@@ -163,24 +164,7 @@ module MjmlRb
163
164
  if (component = component_for(node.tag_name))
164
165
  return component.render(tag_name: node.tag_name, node: node, context: context, attrs: attrs, parent: parent)
165
166
  end
166
-
167
- case node.tag_name
168
- when "mj-group"
169
- render_group(node, context)
170
- else
171
- render_children(node, context, parent: node.tag_name)
172
- end
173
- end
174
-
175
- def render_group(node, context, width_pct = 100)
176
- items = node.element_children.select { |e| e.tag_name == "mj-column" }
177
- widths = compute_column_widths(items, context)
178
- with_inherited_mj_class(context, node) do
179
- items.each_with_index.map do |item, i|
180
- context[:_column_width_pct] = widths[i]
181
- render_node(item, context, parent: "mj-group")
182
- end.join("\n")
183
- end
167
+ render_children(node, context, parent: node.tag_name)
184
168
  end
185
169
 
186
170
  def compute_column_widths(columns, context)
@@ -444,6 +428,7 @@ module MjmlRb
444
428
  register_component(registry, Components::Button.new(self))
445
429
  register_component(registry, Components::Carousel.new(self))
446
430
  register_component(registry, Components::CarouselImage.new(self))
431
+ register_component(registry, Components::Group.new(self))
447
432
  register_component(registry, Components::Hero.new(self))
448
433
  register_component(registry, Components::Image.new(self))
449
434
  register_component(registry, Components::Navbar.new(self))
@@ -1,3 +1,3 @@
1
1
  module MjmlRb
2
- VERSION = "0.2.13".freeze
2
+ VERSION = "0.2.14".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mjml-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.13
4
+ version: 0.2.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrei Andriichuk
@@ -63,6 +63,7 @@ files:
63
63
  - lib/mjml-rb/components/carousel_image.rb
64
64
  - lib/mjml-rb/components/column.rb
65
65
  - lib/mjml-rb/components/divider.rb
66
+ - lib/mjml-rb/components/group.rb
66
67
  - lib/mjml-rb/components/head.rb
67
68
  - lib/mjml-rb/components/hero.rb
68
69
  - lib/mjml-rb/components/html_attributes.rb