From 80e0198478f39351f8641a258407ca3efeb89694 Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Sun, 27 Sep 2026 18:38:19 +0100 Subject: [PATCH] Wire up on-trailing-press on list items from Blade ListItem::applyAttributes never read a trailing press attribute, so the handler could only be set with the fluent onTrailingPress() builder. Both renderers already fire on_trailing_press from the trailing icon button, so accepting on-trailing-press / onTrailingPress (the same spellings as on-trailing-change) is the whole fix. Co-Authored-By: Claude Opus 5.5 (1M context) --- resources/boost/guidelines/core.blade.php | 3 +- src/Elements/ListItem.php | 6 ++ tests/ListItemTrailingPressTest.php | 75 +++++++++++++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 tests/ListItemTrailingPressTest.php 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' => []]); +});