Skip to content
Snippets Groups Projects
Commit 2ac2823c authored by Mikael Meulle's avatar Mikael Meulle
Browse files

Issue #3510596 by just_like_good_vibes, goz: Improve prop value rendering for booleans

parent 4e187eda
No related branches found
No related tags found
1 merge request!358Issue #3510596 by goz, just_like_good_vibes: [2.0.4] Improve prop value rendering for booleans
Pipeline #457458 passed
......@@ -98,7 +98,24 @@ class ComponentElementBuilder implements TrustedCallbackInterface {
}
}
else {
if (!empty($data) || $prop_type->getPluginId() === 'attributes') {
if (!static::isPropValueEmpty($data, $prop_type)) {
$build['#props'][$prop_or_slot_id] = $data;
}
}
}
/**
* Determine if a prop value is empty.
*
* @param mixed $data
* The prop value.
* @param \Drupal\ui_patterns\PropTypeInterface $prop_type
* Target prop type.
*
* @return bool
* TRUE if the prop value is empty, FALSE otherwise.
*/
protected static function isPropValueEmpty(mixed $data, PropTypeInterface $prop_type): bool {
// For JSON Schema validator, empty value is not the same as missing
// value, and we want to prevent some of the prop types rules to be
// applied on empty values: string pattern, string format,
......@@ -106,9 +123,12 @@ class ComponentElementBuilder implements TrustedCallbackInterface {
// However, we don't remove empty attributes to avoid an error with
// Drupal\Core\Template\TwigExtension::createAttribute() when themers
// forget to use the default({}) filter.
$build['#props'][$prop_or_slot_id] = $data;
}
}
// For boolean values, we only remove NULL values.
return match ($prop_type->getPluginId()) {
'attributes' => FALSE,
'boolean' => ($data === NULL),
default => empty($data),
};
}
/**
......
......@@ -28,7 +28,7 @@ class BooleanPropType extends PropTypePluginBase {
/**
* {@inheritdoc}
*/
public static function normalize(mixed $value, ?array $definition = NULL): bool {
public static function normalize(mixed $value, ?array $definition = NULL): ?bool {
if (is_bool($value)) {
return $value;
}
......@@ -37,7 +37,7 @@ class BooleanPropType extends PropTypePluginBase {
$value = (int) $value;
return (bool) $value;
}
return (bool) $value;
return ($value !== NULL) ? (bool) $value : NULL;
}
}
......@@ -37,7 +37,7 @@ class StringPropType extends PropTypePluginBase {
'url' => $value,
'identifier' => $value,
'string' => $value,
'default' => (string) $value,
default => (string) $value,
};
}
......
......@@ -29,6 +29,12 @@ props:
boolean:
title: "Boolean"
$ref: "ui-patterns://boolean"
boolean_with_default_false:
title: "Boolean"
$ref: "ui-patterns://boolean"
boolean_with_default_true:
title: "Boolean"
$ref: "ui-patterns://boolean"
links:
title: "Links"
$ref: "ui-patterns://links"
......
......@@ -25,6 +25,18 @@
<div class="ui-patterns-props-boolean">
{{ boolean }}
</div>
<div class="ui-patterns-props-boolean_with_default_false">
{% if (boolean_with_default_false is not defined) or (boolean_with_default_false is null) %}
{% set boolean_with_default_false = false %}
{% endif %}
{{ boolean_with_default_false }}
</div>
<div class="ui-patterns-props-boolean_with_default_true">
{% if (boolean_with_default_true is not defined) or (boolean_with_default_true is null) %}
{% set boolean_with_default_true = true %}
{% endif %}
{{ boolean_with_default_true }}
</div>
<div class="ui-patterns-props-links">
{% for item in links %}
{% if item.url %}
......
......@@ -34,6 +34,24 @@ class BooleanPropTypeTest extends PropTypeNormalizationTestBase {
$this->runRenderPropTest('boolean', ["value" => $value, "rendered_value" => $rendered_value]);
}
/**
* Test rendered component with prop default false.
*
* @dataProvider renderingTestsDefaultFalse
*/
public function testRenderingDefaultFalse(mixed $value, mixed $rendered_value) : void {
$this->runRenderPropTest('boolean_with_default_false', ["value" => $value, "rendered_value" => $rendered_value]);
}
/**
* Test rendered component with prop default true.
*
* @dataProvider renderingTestsDefaultTrue
*/
public function testRenderingDefaultTrue(mixed $value, mixed $rendered_value) : void {
$this->runRenderPropTest('boolean_with_default_true', ["value" => $value, "rendered_value" => $rendered_value]);
}
/**
* Provides data for testNormalization.
*/
......@@ -81,4 +99,44 @@ class BooleanPropTypeTest extends PropTypeNormalizationTestBase {
];
}
/**
* Provides data for testNormalization.
*/
public static function renderingTestsDefaultFalse() : array {
return [
"null value" => [
NULL,
'<div class="ui-patterns-props-boolean_with_default_false"></div>',
],
"false value" => [
FALSE,
'<div class="ui-patterns-props-boolean_with_default_false"></div>',
],
"true value" => [
TRUE,
'<div class="ui-patterns-props-boolean_with_default_false">1</div>',
],
];
}
/**
* Provides data for testNormalization.
*/
public static function renderingTestsDefaultTrue() : array {
return [
"null value" => [
NULL,
'<div class="ui-patterns-props-boolean_with_default_true">1</div>',
],
"false value" => [
FALSE,
'<div class="ui-patterns-props-boolean_with_default_true"></div>',
],
"true value" => [
TRUE,
'<div class="ui-patterns-props-boolean_with_default_true">1</div>',
],
];
}
}
......@@ -54,12 +54,17 @@ abstract class PropTypeNormalizationTestBase extends KernelTestBase {
/**
* Run tests with a given prop.
*
* @param string $prop
* The prop to test.
* @param string|null $prop
* The prop to test or NULL for no prop.
* @param array $tested_value
* The tested value.
*/
protected function runRenderPropTest(string $prop, array $tested_value) : void {
protected function runRenderPropTest(?string $prop, array $tested_value) : void {
if ($tested_value["value"] === NULL && !empty($prop)) {
// If the value injected is NULL
// we will also try with removing the prop.
$this->runRenderPropTest(NULL, $tested_value);
}
$expectedOutput = [
"rendered_value" => $tested_value["rendered_value"],
"assert" => $tested_value["assert"] ?? "assertStringContainsString",
......@@ -68,19 +73,35 @@ abstract class PropTypeNormalizationTestBase extends KernelTestBase {
if (!empty($exception_class)) {
$this->expectException($exception_class);
}
if (!empty($prop)) {
$this->assertExpectedOutput($expectedOutput, [
"#type" => "inline_template",
"#template" => sprintf("{{ include('ui_patterns_test:test-component', {%s: injected}) }}", $prop),
"#context" => ["injected" => $tested_value["value"]],
]);
}
else {
$this->assertExpectedOutput($expectedOutput, [
"#type" => "inline_template",
"#template" => "{{ include('ui_patterns_test:test-component', {}) }}",
]);
}
if (!empty($exception_class)) {
$this->expectException($exception_class);
}
if (!empty($prop)) {
$this->assertExpectedOutput($expectedOutput, [
"#type" => "component",
'#component' => 'ui_patterns_test:test-component',
"#props" => [$prop => $tested_value["value"]],
]);
}
else {
$this->assertExpectedOutput($expectedOutput, [
"#type" => "component",
'#component' => 'ui_patterns_test:test-component',
]);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment