From 1a74123c7c7f3f045e6f2435eec26437edc4f3c4 Mon Sep 17 00:00:00 2001 From: Dan Matthews Date: Fri, 13 Sep 2024 14:14:28 +0100 Subject: [PATCH 1/7] New @attributes directive/helper. --- .../View/Compilers/BladeCompiler.php | 1 + .../Compilers/Concerns/CompilesAttributes.php | 18 ++++++++++++++++++ tests/View/Blade/BladeAttributesTest.php | 14 ++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 src/Illuminate/View/Compilers/Concerns/CompilesAttributes.php create mode 100644 tests/View/Blade/BladeAttributesTest.php diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 7911462ebf32..a26431a2cfb8 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -15,6 +15,7 @@ class BladeCompiler extends Compiler implements CompilerInterface { use Concerns\CompilesAuthorizations, + Concerns\CompilesAttributes, Concerns\CompilesClasses, Concerns\CompilesComments, Concerns\CompilesComponents, diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesAttributes.php b/src/Illuminate/View/Compilers/Concerns/CompilesAttributes.php new file mode 100644 index 000000000000..694190881896 --- /dev/null +++ b/src/Illuminate/View/Compilers/Concerns/CompilesAttributes.php @@ -0,0 +1,18 @@ +map(function (\$val, \$key) => { if (\$key && \$value) { return \$value ? \$key : null } else { return \$value; } })->filter()->implode(' '); ?>"; + } +} diff --git a/tests/View/Blade/BladeAttributesTest.php b/tests/View/Blade/BladeAttributesTest.php new file mode 100644 index 000000000000..281c3dbd91a9 --- /dev/null +++ b/tests/View/Blade/BladeAttributesTest.php @@ -0,0 +1,14 @@ + true, 'disabled=\"disabled\"' => false, 'role=\"button\"' ])>"; + $expected = " true, 'mr-2' => false]); ?>\">"; + + $this->assertEquals($expected, $this->compiler->compileString($string)); + } +} From 5ab08ed88312b90dd23c62622b3872a82af9020a Mon Sep 17 00:00:00 2001 From: Dan Matthews Date: Fri, 13 Sep 2024 16:53:08 +0100 Subject: [PATCH 2/7] Syntax fix. --- src/Illuminate/View/Compilers/Concerns/CompilesAttributes.php | 2 +- tests/View/Blade/BladeAttributesTest.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesAttributes.php b/src/Illuminate/View/Compilers/Concerns/CompilesAttributes.php index 694190881896..cb24867883e0 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesAttributes.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesAttributes.php @@ -13,6 +13,6 @@ trait CompilesAttributes protected function compileAttributes($expression) { $expression = is_null($expression) ? '([])' : $expression; - return "map(function (\$val, \$key) => { if (\$key && \$value) { return \$value ? \$key : null } else { return \$value; } })->filter()->implode(' '); ?>"; + return "map(function (\$value, \$key) { if (\$key && \$value) { return \$value ? \$key : null; } else { return \$value; } })->filter()->implode(' '); ?>"; } } diff --git a/tests/View/Blade/BladeAttributesTest.php b/tests/View/Blade/BladeAttributesTest.php index 281c3dbd91a9..34204ace0d43 100644 --- a/tests/View/Blade/BladeAttributesTest.php +++ b/tests/View/Blade/BladeAttributesTest.php @@ -8,7 +8,6 @@ public function testClassesAreConditionallyCompiledFromArray() { $string = " true, 'disabled=\"disabled\"' => false, 'role=\"button\"' ])>"; $expected = " true, 'mr-2' => false]); ?>\">"; - $this->assertEquals($expected, $this->compiler->compileString($string)); } } From c795114a4a2051c233db60ae2d4bf5e61e1f5b7e Mon Sep 17 00:00:00 2001 From: Dan Matthews Date: Fri, 13 Sep 2024 18:00:30 +0100 Subject: [PATCH 3/7] Enables @attributes on custom components. --- src/Illuminate/View/Compilers/ComponentTagCompiler.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Illuminate/View/Compilers/ComponentTagCompiler.php b/src/Illuminate/View/Compilers/ComponentTagCompiler.php index 9c3d6adbec99..7154cc2d050b 100644 --- a/src/Illuminate/View/Compilers/ComponentTagCompiler.php +++ b/src/Illuminate/View/Compilers/ComponentTagCompiler.php @@ -111,6 +111,9 @@ protected function compileOpeningTags(string $value) (?: \s+ (?: + (?: + @(?:attributes)(\( (?: (?>[^()]+) | (?-1) )* \)) + ) (?: @(?:class)(\( (?: (?>[^()]+) | (?-1) )* \)) ) From 22aa33d435dfbb618d465063127e32db47b32736 Mon Sep 17 00:00:00 2001 From: Dan Matthews Date: Fri, 13 Sep 2024 18:41:44 +0100 Subject: [PATCH 4/7] New array toHtmlAttributes helper on the Arr class. --- src/Illuminate/Collections/Arr.php | 22 +++++++++++ .../View/Compilers/ComponentTagCompiler.php | 38 +++++++++++++++++-- .../Compilers/Concerns/CompilesAttributes.php | 2 +- tests/View/Blade/BladeAttributesTest.php | 7 ++-- 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index cddcde2ecc9f..c86ebba07848 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -4,7 +4,9 @@ use ArgumentCountError; use ArrayAccess; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Support\Traits\Macroable; +use Illuminate\View\ComponentAttributeBag; use InvalidArgumentException; use Random\Randomizer; @@ -891,6 +893,26 @@ public static function toCssClasses($array) return implode(' ', $classes); } + /** + * Conditionally compile attributes from an array into an HTML attribute string. + * + * @param array $array + * @return string + */ + public static function toHtmlAttributes($array) + { + return Collection::make($array)->map(function ($value, $key) { + if ($key) { + return $value ? sprintf('%s', $key) : null; + } elseif ($value instanceof ComponentAttributeBag) { + return collect($value->getAttributes())->map(fn ($value, $key) => sprintf('%s="%s"', $key, $value)); + } else { + return sprintf("%s", $value); + } + }) + ->implode(" "); + } + /** * Conditionally compile styles from an array into a style list. * diff --git a/src/Illuminate/View/Compilers/ComponentTagCompiler.php b/src/Illuminate/View/Compilers/ComponentTagCompiler.php index 7154cc2d050b..ff8f17508101 100644 --- a/src/Illuminate/View/Compilers/ComponentTagCompiler.php +++ b/src/Illuminate/View/Compilers/ComponentTagCompiler.php @@ -112,8 +112,9 @@ protected function compileOpeningTags(string $value) \s+ (?: (?: - @(?:attributes)(\( (?: (?>[^()]+) | (?-1) )* \)) + @(?:withAttributes)(\( (?: (?>[^()]+) | (?-1) )* \)) ) + | (?: @(?:class)(\( (?: (?>[^()]+) | (?-1) )* \)) ) @@ -155,7 +156,6 @@ protected function compileOpeningTags(string $value) $this->boundAttributes = []; $attributes = $this->getAttributesFromAttributeString($matches['attributes']); - return $this->componentString($matches[1], $attributes); }, $value); } @@ -179,6 +179,10 @@ protected function compileSelfClosingTags(string $value) (?: \s+ (?: + (?: + @(?:attributes)(\( (?: (?>[^()]+) | (?-1) )* \)) + ) + | (?: @(?:class)(\( (?: (?>[^()]+) | (?-1) )* \)) ) @@ -514,6 +518,10 @@ public function compileSlots(string $value) (?: \s+ (?: + (?: + @(?:attributes)(\( (?: (?>[^()]+) | (?-1) )* \)) + ) + | (?: @(?:class)(\( (?: (?>[^()]+) | (?-1) )* \)) ) @@ -584,8 +592,9 @@ public function compileSlots(string $value) */ protected function getAttributesFromAttributeString(string $attributeString) { - $attributeString = $this->parseShortAttributeSyntax($attributeString); $attributeString = $this->parseAttributeBag($attributeString); + $attributeString = $this->parseShortAttributeSyntax($attributeString); + $attributeString = $this->parseComponentTagAttributesStatements($attributeString); $attributeString = $this->parseComponentTagClassStatements($attributeString); $attributeString = $this->parseComponentTagStyleStatements($attributeString); $attributeString = $this->parseBindAttributes($attributeString); @@ -635,7 +644,8 @@ protected function getAttributesFromAttributeString(string $attributeString) } return [$attribute => $value]; - })->toArray(); + }) + ->toArray(); } /** @@ -690,6 +700,26 @@ protected function parseComponentTagClassStatements(string $attributeString) ); } + /** + * Parse @attributes statements in a given attribute string into their fully-qualified syntax. + * + * @param string $attributeString + * @return string + */ + protected function parseComponentTagAttributesStatements(string $attributeString) + { + return preg_replace_callback( + '/@(attributes)(\( ( (?>[^()]+) | (?2) )* \))/x', function ($match) { + if ($match[1] === 'attributes') { + $match[2] = str_replace('"', "'", $match[2]); + return \Illuminate\Support\Arr::toHtmlAttributes($match[2]); + } + + return $match[0]; + }, $attributeString + ); + } + /** * Parse @style statements in a given attribute string into their fully-qualified syntax. * diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesAttributes.php b/src/Illuminate/View/Compilers/Concerns/CompilesAttributes.php index cb24867883e0..513fc8b0abf1 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesAttributes.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesAttributes.php @@ -13,6 +13,6 @@ trait CompilesAttributes protected function compileAttributes($expression) { $expression = is_null($expression) ? '([])' : $expression; - return "map(function (\$value, \$key) { if (\$key && \$value) { return \$value ? \$key : null; } else { return \$value; } })->filter()->implode(' '); ?>"; + return ""; } } diff --git a/tests/View/Blade/BladeAttributesTest.php b/tests/View/Blade/BladeAttributesTest.php index 34204ace0d43..23e4e5d3abe9 100644 --- a/tests/View/Blade/BladeAttributesTest.php +++ b/tests/View/Blade/BladeAttributesTest.php @@ -4,10 +4,11 @@ class BladeAttributesTest extends AbstractBladeTestCase { - public function testClassesAreConditionallyCompiledFromArray() + public function testAttributesAreConditionallyCompiledFromArray() { - $string = " true, 'disabled=\"disabled\"' => false, 'role=\"button\"' ])>"; - $expected = " true, 'mr-2' => false]); ?>\">"; + $string = " true, 'disabled=\"disabled\"' => false, 'role=\"button\"'])>"; + $expected = " true, 'disabled=\"disabled\"' => false, 'role=\"button\"']); ?>>"; + $this->assertEquals($expected, $this->compiler->compileString($string)); } } From a4411eca56f4a7b1b17f12dd70b7089d5574b0db Mon Sep 17 00:00:00 2001 From: Dan Matthews Date: Fri, 13 Sep 2024 23:13:16 +0100 Subject: [PATCH 5/7] WIP - compiles @attributes for components. --- src/Illuminate/Collections/Arr.php | 2 +- .../View/Compilers/ComponentTagCompiler.php | 42 +++++++++++++++---- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index c86ebba07848..a9e88b33e2f8 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -905,7 +905,7 @@ public static function toHtmlAttributes($array) if ($key) { return $value ? sprintf('%s', $key) : null; } elseif ($value instanceof ComponentAttributeBag) { - return collect($value->getAttributes())->map(fn ($value, $key) => sprintf('%s="%s"', $key, $value)); + return collect($value->getAttributes())->map(fn ($value, $key) => sprintf('%s="%s"', $key, $value))->join(' '); } else { return sprintf("%s", $value); } diff --git a/src/Illuminate/View/Compilers/ComponentTagCompiler.php b/src/Illuminate/View/Compilers/ComponentTagCompiler.php index ff8f17508101..14d43d514176 100644 --- a/src/Illuminate/View/Compilers/ComponentTagCompiler.php +++ b/src/Illuminate/View/Compilers/ComponentTagCompiler.php @@ -19,6 +19,9 @@ */ class ComponentTagCompiler { + + use Concerns\CompilesAttributes; + /** * The Blade compiler instance. * @@ -112,7 +115,7 @@ protected function compileOpeningTags(string $value) \s+ (?: (?: - @(?:withAttributes)(\( (?: (?>[^()]+) | (?-1) )* \)) + @(?:attributes)(\( (?: (?>[^()]+) | (?-1) )* \)) ) | (?: @@ -154,7 +157,6 @@ protected function compileOpeningTags(string $value) return preg_replace_callback($pattern, function (array $matches) { $this->boundAttributes = []; - $attributes = $this->getAttributesFromAttributeString($matches['attributes']); return $this->componentString($matches[1], $attributes); }, $value); @@ -592,9 +594,9 @@ public function compileSlots(string $value) */ protected function getAttributesFromAttributeString(string $attributeString) { + $attributeString = $this->parseComponentTagAttributesStatements($attributeString); $attributeString = $this->parseAttributeBag($attributeString); $attributeString = $this->parseShortAttributeSyntax($attributeString); - $attributeString = $this->parseComponentTagAttributesStatements($attributeString); $attributeString = $this->parseComponentTagClassStatements($attributeString); $attributeString = $this->parseComponentTagStyleStatements($attributeString); $attributeString = $this->parseBindAttributes($attributeString); @@ -619,7 +621,8 @@ protected function getAttributesFromAttributeString(string $attributeString) return []; } - return collect($matches)->mapWithKeys(function ($match) { + return collect($matches) + ->mapWithKeys(function ($match) { $attribute = $match['attribute']; $value = $match['value'] ?? null; @@ -691,7 +694,6 @@ protected function parseComponentTagClassStatements(string $attributeString) '/@(class)(\( ( (?>[^()]+) | (?2) )* \))/x', function ($match) { if ($match[1] === 'class') { $match[2] = str_replace('"', "'", $match[2]); - return ":class=\"\Illuminate\Support\Arr::toCssClasses{$match[2]}\""; } @@ -711,8 +713,34 @@ protected function parseComponentTagAttributesStatements(string $attributeString return preg_replace_callback( '/@(attributes)(\( ( (?>[^()]+) | (?2) )* \))/x', function ($match) { if ($match[1] === 'attributes') { - $match[2] = str_replace('"', "'", $match[2]); - return \Illuminate\Support\Arr::toHtmlAttributes($match[2]); +// $match[2] = str_replace('"', "'", $match[2]); + + // Using regex to extract keys and values + $matches = []; + preg_match_all( + "/'([^']+)' =>\s*(true|false|'.*?')/", + $match[2], + $matches); + + $parsedArray = []; + // Iterate through the matches to handle boolean and string values correctly + foreach ($matches[1] as $index => $key) { + $value = $matches[2][$index]; + + // Check if the value is actual boolean true or false + if ($value === 'true') { + $parsedArray[$key] = true; + } elseif ($value === 'false') { + $parsedArray[$key] = false; + } else { + // If it's a string (e.g., 'value'), remove the surrounding quotes + $parsedArray[$key] = trim($value, "'"); + } + } + + // Combine keys and values into an associative array + $parsedArray = array_combine($matches[1], $matches[2]); + return \Illuminate\Support\Arr::toHtmlAttributes($parsedArray); } return $match[0]; From 216fcd115e2aed86299dcd6b3b05a0b6b275572e Mon Sep 17 00:00:00 2001 From: Dan Matthews Date: Sat, 14 Sep 2024 21:31:59 +0100 Subject: [PATCH 6/7] Tests for Arr:: helper and refactor to use key => val structure. --- src/Illuminate/Collections/Arr.php | 7 ++++-- tests/Support/SupportArrTest.php | 30 ++++++++++++++++++++++++ tests/View/Blade/BladeAttributesTest.php | 4 ++-- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Collections/Arr.php b/src/Illuminate/Collections/Arr.php index a9e88b33e2f8..43e36422fcc0 100644 --- a/src/Illuminate/Collections/Arr.php +++ b/src/Illuminate/Collections/Arr.php @@ -903,13 +903,16 @@ public static function toHtmlAttributes($array) { return Collection::make($array)->map(function ($value, $key) { if ($key) { - return $value ? sprintf('%s', $key) : null; + $value = value($value); + return is_null($value) || $value === false ? null : sprintf('%s="%s"', $key, $value); } elseif ($value instanceof ComponentAttributeBag) { - return collect($value->getAttributes())->map(fn ($value, $key) => sprintf('%s="%s"', $key, $value))->join(' '); + return self::toHtmlAttributes($value->getAttributes()); } else { return sprintf("%s", $value); } }) + ->filter() + ->values() ->implode(" "); } diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 82044805b7cb..0f05757f47a5 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -6,6 +6,7 @@ use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; +use Illuminate\View\ComponentAttributeBag; use InvalidArgumentException; use PHPUnit\Framework\TestCase; use stdClass; @@ -1235,6 +1236,35 @@ public function testToCssClasses() $this->assertSame('font-bold mt-4 ml-2', $classes); } + public function testToHtmlAttributes() + { + $resultString = Arr::toHtmlAttributes([ + new ComponentAttributeBag([ + 'taylor' => false, + 'joe' => '', + 'james' => null, + 'tim' => 'macdonald', + 'christoph' => fn () => "rumpel", + ]), + 'audrey' => '', + 'leyton' => false, + 'till' => null, + 'josie' => 'cold', + 'hedwood' => fn () => 'melanie' + ]); + + $this->assertStringContainsString( 'audrey=""', $resultString); + $this->assertStringContainsString( 'hedwood="melanie"', $resultString); + $this->assertStringNotContainsString( 'leyton', $resultString); + $this->assertStringNotContainsString( 'till', $resultString); + + $this->assertStringContainsString( 'joe=""', $resultString); + $this->assertStringContainsString( 'christoph="rumpel"', $resultString); + $this->assertStringContainsString( 'tim="macdonald"', $resultString); + $this->assertStringNotContainsString( 'taylor', $resultString); + $this->assertStringNotContainsString( 'james', $resultString); + } + public function testToCssStyles() { $styles = Arr::toCssStyles([ diff --git a/tests/View/Blade/BladeAttributesTest.php b/tests/View/Blade/BladeAttributesTest.php index 23e4e5d3abe9..d2c2895c0cf9 100644 --- a/tests/View/Blade/BladeAttributesTest.php +++ b/tests/View/Blade/BladeAttributesTest.php @@ -6,8 +6,8 @@ class BladeAttributesTest extends AbstractBladeTestCase { public function testAttributesAreConditionallyCompiledFromArray() { - $string = " true, 'disabled=\"disabled\"' => false, 'role=\"button\"'])>"; - $expected = " true, 'disabled=\"disabled\"' => false, 'role=\"button\"']); ?>>"; + $string = " \"mt-1\", 'disabled' => false, 'role' => null, 'wire:poll' => fn () => true])>"; + $expected = " \"mt-1\", 'disabled' => false, 'role' => null, 'wire:poll' => fn () => true]); ?>>"; $this->assertEquals($expected, $this->compiler->compileString($string)); } From 2e1c3a5bb1d9a2414f884a718fd9fdd5fc01e2f1 Mon Sep 17 00:00:00 2001 From: Dan Matthews Date: Tue, 17 Sep 2024 09:41:56 +0100 Subject: [PATCH 7/7] Parsing and tests for processing string based arrays back into php based ones. --- .../View/Compilers/ComponentTagCompiler.php | 67 +++++++++++-------- tests/Support/SupportArrTest.php | 4 ++ .../Blade/BladeComponentTagCompilerTest.php | 20 ++++++ 3 files changed, 63 insertions(+), 28 deletions(-) diff --git a/src/Illuminate/View/Compilers/ComponentTagCompiler.php b/src/Illuminate/View/Compilers/ComponentTagCompiler.php index 14d43d514176..fa0c85ec917a 100644 --- a/src/Illuminate/View/Compilers/ComponentTagCompiler.php +++ b/src/Illuminate/View/Compilers/ComponentTagCompiler.php @@ -558,6 +558,8 @@ public function compileSlots(string $value) /x"; $value = preg_replace_callback($pattern, function ($matches) { + + $name = $this->stripQuotes($matches['inlineName'] ?: $matches['name'] ?: $matches['boundName']); if (Str::contains($name, '-') && ! empty($matches['inlineName'])) { @@ -571,6 +573,7 @@ public function compileSlots(string $value) $this->boundAttributes = []; + $attributes = $this->getAttributesFromAttributeString($matches['attributes']); // If an inline name was provided and a name or bound name was *also* provided, we will assume the name should be an attribute... @@ -712,35 +715,12 @@ protected function parseComponentTagAttributesStatements(string $attributeString { return preg_replace_callback( '/@(attributes)(\( ( (?>[^()]+) | (?2) )* \))/x', function ($match) { + + if ($match[1] === 'attributes') { -// $match[2] = str_replace('"', "'", $match[2]); - - // Using regex to extract keys and values - $matches = []; - preg_match_all( - "/'([^']+)' =>\s*(true|false|'.*?')/", - $match[2], - $matches); - - $parsedArray = []; - // Iterate through the matches to handle boolean and string values correctly - foreach ($matches[1] as $index => $key) { - $value = $matches[2][$index]; - - // Check if the value is actual boolean true or false - if ($value === 'true') { - $parsedArray[$key] = true; - } elseif ($value === 'false') { - $parsedArray[$key] = false; - } else { - // If it's a string (e.g., 'value'), remove the surrounding quotes - $parsedArray[$key] = trim($value, "'"); - } - } - - // Combine keys and values into an associative array - $parsedArray = array_combine($matches[1], $matches[2]); - return \Illuminate\Support\Arr::toHtmlAttributes($parsedArray); + return \Illuminate\Support\Arr::toHtmlAttributes( + $this->reformatAttributeExpressionStringToArray($match[2]) + ); } return $match[0]; @@ -748,6 +728,37 @@ protected function parseComponentTagAttributesStatements(string $attributeString ); } + /** + * Take an attribute string in expression format (surrounded by ([])) + * and reformat it into a compiled HTML attribute string. + * + * @param string $expression + * @return array + */ + public function reformatAttributeExpressionStringToArray(string $expression) + { + preg_match_all( + '/[\'"](?[^\'"]+)[\'"]\s*=>\s*(?:(?true|false)|(?\d+)|[\'"](?[^\'"]*)[\'"])/x', + trim($expression, '()[]'), + $matches, + PREG_SET_ORDER + ); + return \Illuminate\Support\Collection::make($matches) + ->mapWithKeys(function ($match) { + $key = $match['key']; + if (isset($match['bool']) && $match['bool'] !== '') { + $value = $match['bool'] === 'true'; + } elseif (isset($match['int']) && $match['int'] !== '') { + $value = intval($match['int']); + } elseif (isset($match['string'])) { + $value = $match['string']; + } else { + $value = null; + } + return [$key => $value]; + })->toArray(); + } + /** * Parse @style statements in a given attribute string into their fully-qualified syntax. * diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 0f05757f47a5..379b7a1cd5a9 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -1242,11 +1242,13 @@ public function testToHtmlAttributes() new ComponentAttributeBag([ 'taylor' => false, 'joe' => '', + 'aaron' => 0, 'james' => null, 'tim' => 'macdonald', 'christoph' => fn () => "rumpel", ]), 'audrey' => '', + 'alex' => 0, 'leyton' => false, 'till' => null, 'josie' => 'cold', @@ -1255,11 +1257,13 @@ public function testToHtmlAttributes() $this->assertStringContainsString( 'audrey=""', $resultString); $this->assertStringContainsString( 'hedwood="melanie"', $resultString); + $this->assertStringContainsString( 'alex="0"', $resultString); $this->assertStringNotContainsString( 'leyton', $resultString); $this->assertStringNotContainsString( 'till', $resultString); $this->assertStringContainsString( 'joe=""', $resultString); $this->assertStringContainsString( 'christoph="rumpel"', $resultString); + $this->assertStringContainsString( 'aaron="0"', $resultString); $this->assertStringContainsString( 'tim="macdonald"', $resultString); $this->assertStringNotContainsString( 'taylor', $resultString); $this->assertStringNotContainsString( 'james', $resultString); diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php index 38a4a037b21a..4244d918fb63 100644 --- a/tests/View/Blade/BladeComponentTagCompilerTest.php +++ b/tests/View/Blade/BladeComponentTagCompilerTest.php @@ -87,6 +87,26 @@ public function testSlotsWithClassDirectiveCanBeCompiled() $this->assertSame("@slot('foo', null, ['class' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(\Illuminate\Support\Arr::toCssClasses(\$classes))]) \n".' @endslot', trim($result)); } + public function testSlotsWithAttributesDirectiveCanBeCompiled() + { + $this->mockViewFactory(); + $result = $this->compiler()->compileSlots(' "ml-4", "disabled" => false, "readonly" => 0])>"])> +'); +dd(trim($result)); + $this->assertSame("@slot('foo', null, ['class' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute(\Illuminate\Support\Arr::toCssClasses(\$classes))]) \n".' @endslot', trim($result)); + } + + public function testReformatAttributeExpressionStringToArrayMethod() + { + $compiler = app(ComponentTagCompiler::class); + $result = $compiler->reformatAttributeExpressionStringToArray('(["contains(" => ")bracket", "[other" => "]bracket,", "string" => "string", "bool" => true, "falseBool" => false, "int" => 32, \'singlestring\' => \'single\'])'); + $this->assertEquals('string', $result['string']); + $this->assertEquals('single', $result['singlestring']); + $this->assertTrue($result['bool']); + $this->assertFalse($result['falseBool']); + $this->assertEquals(32, $result['int']); + } + public function testSlotsWithStyleDirectiveCanBeCompiled() { $this->mockViewFactory();