diff --git a/resources/boost/guidelines/core.blade.php b/resources/boost/guidelines/core.blade.php index 35207f5..299e903 100644 --- a/resources/boost/guidelines/core.blade.php +++ b/resources/boost/guidelines/core.blade.php @@ -188,7 +188,7 @@ - Use `a11y-hint` sparingly, for supplementary guidance the label doesn't cover ("Double-tap to reorder"). Never repeat the label in the hint. - List items with a trailing icon button take `trailing-a11y-label` to label - that button separately from the row. + that button separately from the row, and `on-trailing-press` for its handler. - Text scales with the user's system font size on both platforms automatically — don't hardcode layouts that break at larger type sizes. @@ -197,6 +197,7 @@ + @endverbatim diff --git a/src/Elements/ListItem.php b/src/Elements/ListItem.php index e4bb74d..d5b2ace 100644 --- a/src/Elements/ListItem.php +++ b/src/Elements/ListItem.php @@ -200,6 +200,12 @@ public function applyAttributes(array $attrs): void $this->onTrailingChange($attrs['on-trailing-change'] ?? $attrs['onTrailingChange']); } + // Trailing icon button press, same spellings as the change + // callbacks above. + if (isset($attrs['on-trailing-press']) || isset($attrs['onTrailingPress'])) { + $this->onTrailingPress($attrs['on-trailing-press'] ?? $attrs['onTrailingPress']); + } + // Swipe actions — new structured multi-action API. Each entry // is `['method' => …, 'label' => …, 'icon' => …, 'tint' => …, // 'role' => …]`. Both arrays support 1+ actions. diff --git a/tests/ListItemTrailingPressTest.php b/tests/ListItemTrailingPressTest.php new file mode 100644 index 0000000..8330f52 --- /dev/null +++ b/tests/ListItemTrailingPressTest.php @@ -0,0 +1,75 @@ + 'Buy milk', 'trailingIconButton' => 'trash'] + $attrs); + + return NativeElementCollector::collect()->toArray($registry); +} + +it('registers the trailing press handler from each Blade spelling', function (string $attr) { + $registry = new CallbackRegistry; + $tree = trailingPressTree([$attr => 'deleteTodo(7)'], $registry); + + expect($tree['props']['trailing_type'])->toBe('icon_button') + ->and($tree['props']['on_trailing_press'])->toBeInt() + ->and($registry->resolve($tree['props']['on_trailing_press'])) + ->toBe(['method' => 'deleteTodo', 'args' => [7]]); +})->with(['on-trailing-press', 'onTrailingPress']); + +it('compiles on-trailing-press with a bound argument from a Blade tag', function () { + $wasActive = NativeTagPrecompiler::setActive(true); + + try { + $php = (new NativeTagPrecompiler)( + '' + ); + } finally { + NativeTagPrecompiler::setActive($wasActive); + } + + (function (int $id) use ($php) { + eval('?>'.$php); + })(7); + + $registry = new CallbackRegistry; + $tree = NativeElementCollector::collect()->toArray($registry); + + expect($registry->resolve($tree['props']['on_trailing_press'])) + ->toBe(['method' => 'deleteTodo', 'args' => [7]]); +}); + +it('sends no trailing press callback when none is set', function () { + $tree = trailingPressTree([], new CallbackRegistry); + + expect($tree['props'])->not->toHaveKey('on_trailing_press'); +}); + +it('keeps the fluent onTrailingPress builder working', function () { + $registry = new CallbackRegistry; + $props = ListItem::make('Buy milk')->trailingIconButton('trash')->onTrailingPress('deleteTodo') + ->toArray($registry)['props']; + + expect($registry->resolve($props['on_trailing_press']))->toBe(['method' => 'deleteTodo', 'args' => []]); +});