Skip to content

Commit 910a5e4

Browse files
authored
Merge pull request #26 from dingo-d/feature/mj-group
Implement mj-group element
2 parents c0d7943 + f1bf3de commit 910a5e4

File tree

2 files changed

+286
-0
lines changed

2 files changed

+286
-0
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
3+
/**
4+
* PHP MJML Renderer library
5+
*
6+
* @package MadeByDenis\PhpMjmlRenderer
7+
* @link https://github.com/dingo-d/php-mjml-renderer
8+
* @license https://opensource.org/licenses/MIT MIT
9+
*/
10+
11+
declare(strict_types=1);
12+
13+
namespace MadeByDenis\PhpMjmlRenderer\Elements\BodyComponents;
14+
15+
use MadeByDenis\PhpMjmlRenderer\Elements\AbstractElement;
16+
17+
/**
18+
* Mjml Group Element
19+
*
20+
* Group allows you to prevent columns from stacking on mobile.
21+
* To do so, wrap the columns inside a group component.
22+
*
23+
* @link https://documentation.mjml.io/#mj-group
24+
*
25+
* @since 1.0.0
26+
*/
27+
class MjGroup extends AbstractElement
28+
{
29+
public const string TAG_NAME = 'mj-group';
30+
31+
public const bool ENDING_TAG = false;
32+
33+
/**
34+
* List of allowed attributes on the element
35+
*
36+
* @var array<string, array<string, string>>
37+
*/
38+
protected array $allowedAttributes = [
39+
'width' => [
40+
'unit' => 'px,%',
41+
'type' => 'string',
42+
'description' => 'group width',
43+
'default_value' => '100%',
44+
],
45+
'vertical-align' => [
46+
'unit' => 'string',
47+
'type' => 'string',
48+
'description' => 'vertical alignment (top/middle/bottom)',
49+
'default_value' => 'top',
50+
],
51+
'background-color' => [
52+
'unit' => 'color',
53+
'type' => 'color',
54+
'description' => 'background color for the group',
55+
'default_value' => '',
56+
],
57+
'direction' => [
58+
'unit' => 'string',
59+
'type' => 'string',
60+
'description' => 'set the display order of direct children (ltr/rtl)',
61+
'default_value' => 'ltr',
62+
],
63+
'css-class' => [
64+
'unit' => 'string',
65+
'type' => 'string',
66+
'description' => 'class name added to root HTML element',
67+
'default_value' => '',
68+
],
69+
];
70+
71+
protected array $defaultAttributes = [
72+
'width' => '100%',
73+
'vertical-align' => 'top',
74+
'direction' => 'ltr',
75+
];
76+
77+
public function render(): string
78+
{
79+
$children = $this->getChildren() ?? [];
80+
$content = $this->renderChildren($children, []);
81+
82+
return $content;
83+
}
84+
85+
/**
86+
* Gets the context for child elements.
87+
*
88+
* @return array<string, mixed>
89+
*/
90+
public function getChildContext(): array
91+
{
92+
return [
93+
...$this->context,
94+
'containerWidth' => $this->getAttribute('width'),
95+
];
96+
}
97+
98+
/**
99+
* @return array<string, array<string, string>>
100+
*/
101+
public function getStyles(): array
102+
{
103+
return [
104+
'td' => [
105+
'background-color' => $this->getAttribute('background-color'),
106+
'direction' => $this->getAttribute('direction'),
107+
'font-size' => '0px',
108+
'text-align' => 'center',
109+
'vertical-align' => $this->getAttribute('vertical-align'),
110+
],
111+
];
112+
}
113+
}
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
<?php
2+
3+
namespace MadeByDenis\PhpMjmlRenderer\Tests\Unit\Elements\BodyComponents;
4+
5+
use MadeByDenis\PhpMjmlRenderer\Elements\BodyComponents\MjGroup;
6+
use MadeByDenis\PhpMjmlRenderer\Elements\ElementFactory;
7+
use MadeByDenis\PhpMjmlRenderer\Parser\MjmlNode;
8+
use OutOfBoundsException;
9+
10+
beforeEach(function () {
11+
$this->element = new MjGroup();
12+
});
13+
14+
it('is not ending tag', function () {
15+
expect($this->element->isEndingTag())->toBe(false);
16+
});
17+
18+
it('returns the correct component name', function () {
19+
expect($this->element->getTagName())->toBe('mj-group');
20+
});
21+
22+
it('returns the correct default attributes', function () {
23+
$attributes = [
24+
'width' => '100%',
25+
'vertical-align' => 'top',
26+
'direction' => 'ltr',
27+
];
28+
29+
foreach ($attributes as $key => $value) {
30+
expect($this->element->getAttribute($key))->toBe($value);
31+
}
32+
});
33+
34+
it('will throw out of bounds exception if the allowed attribute is not existing', function () {
35+
$this->element->getAllowedAttributeData('invalid-attribute');
36+
})->throws(OutOfBoundsException::class);
37+
38+
it('will return allowed attribute data', function () {
39+
$data = $this->element->getAllowedAttributeData('width');
40+
expect($data)->toBeArray();
41+
expect($data)->toHaveKey('type');
42+
expect($data)->toHaveKey('unit');
43+
});
44+
45+
it('will correctly render a simple group', function () {
46+
$groupNode = new MjmlNode(
47+
'mj-group',
48+
null,
49+
null,
50+
false,
51+
null
52+
);
53+
54+
$factory = new ElementFactory();
55+
$mjGroupElement = $factory->create($groupNode);
56+
57+
expect($mjGroupElement)->toBeInstanceOf(MjGroup::class);
58+
});
59+
60+
it('will correctly set background color attribute', function () {
61+
$groupNode = new MjmlNode(
62+
'mj-group',
63+
['background-color' => '#f5f5f5'],
64+
null,
65+
false,
66+
null
67+
);
68+
69+
$factory = new ElementFactory();
70+
$mjGroupElement = $factory->create($groupNode);
71+
72+
expect($mjGroupElement->getAttribute('background-color'))->toBe('#f5f5f5');
73+
74+
$styles = $mjGroupElement->getStyles();
75+
expect($styles['td']['background-color'])->toBe('#f5f5f5');
76+
});
77+
78+
it('will correctly render a group with custom width', function () {
79+
$groupNode = new MjmlNode(
80+
'mj-group',
81+
['width' => '600px'],
82+
null,
83+
false,
84+
null
85+
);
86+
87+
$factory = new ElementFactory();
88+
$mjGroupElement = $factory->create($groupNode);
89+
90+
expect($mjGroupElement)->toBeInstanceOf(MjGroup::class);
91+
expect($mjGroupElement->getAttribute('width'))->toBe('600px');
92+
});
93+
94+
it('will correctly set vertical alignment attribute', function () {
95+
$groupNode = new MjmlNode(
96+
'mj-group',
97+
['vertical-align' => 'middle'],
98+
null,
99+
false,
100+
null
101+
);
102+
103+
$factory = new ElementFactory();
104+
$mjGroupElement = $factory->create($groupNode);
105+
106+
expect($mjGroupElement->getAttribute('vertical-align'))->toBe('middle');
107+
108+
$styles = $mjGroupElement->getStyles();
109+
expect($styles['td']['vertical-align'])->toBe('middle');
110+
});
111+
112+
it('will correctly set rtl direction attribute', function () {
113+
$groupNode = new MjmlNode(
114+
'mj-group',
115+
['direction' => 'rtl'],
116+
null,
117+
false,
118+
null
119+
);
120+
121+
$factory = new ElementFactory();
122+
$mjGroupElement = $factory->create($groupNode);
123+
124+
expect($mjGroupElement->getAttribute('direction'))->toBe('rtl');
125+
126+
$styles = $mjGroupElement->getStyles();
127+
expect($styles['td']['direction'])->toBe('rtl');
128+
});
129+
130+
it('will correctly set css class attribute', function () {
131+
$groupNode = new MjmlNode(
132+
'mj-group',
133+
['css-class' => 'custom-group'],
134+
null,
135+
false,
136+
null
137+
);
138+
139+
$factory = new ElementFactory();
140+
$mjGroupElement = $factory->create($groupNode);
141+
142+
expect($mjGroupElement->getAttribute('css-class'))->toBe('custom-group');
143+
});
144+
145+
it('will correctly set all custom properties', function () {
146+
$groupNode = new MjmlNode(
147+
'mj-group',
148+
[
149+
'width' => '500px',
150+
'vertical-align' => 'bottom',
151+
'background-color' => '#eeeeee',
152+
'direction' => 'rtl',
153+
'css-class' => 'my-group',
154+
],
155+
null,
156+
false,
157+
null
158+
);
159+
160+
$factory = new ElementFactory();
161+
$mjGroupElement = $factory->create($groupNode);
162+
163+
expect($mjGroupElement->getAttribute('width'))->toBe('500px');
164+
expect($mjGroupElement->getAttribute('vertical-align'))->toBe('bottom');
165+
expect($mjGroupElement->getAttribute('background-color'))->toBe('#eeeeee');
166+
expect($mjGroupElement->getAttribute('direction'))->toBe('rtl');
167+
expect($mjGroupElement->getAttribute('css-class'))->toBe('my-group');
168+
169+
$styles = $mjGroupElement->getStyles();
170+
expect($styles['td']['vertical-align'])->toBe('bottom');
171+
expect($styles['td']['background-color'])->toBe('#eeeeee');
172+
expect($styles['td']['direction'])->toBe('rtl');
173+
});

0 commit comments

Comments
 (0)