Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion resources/boost/guidelines/core.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -197,6 +197,7 @@
<native:button icon="trash" a11y-label="Delete draft" a11y-hint="Deletes the draft permanently" @tap="deleteDraft" />
<native:icon name="checkmark.seal" a11y-label="Verified" />
<native:list-item headline="Team meeting" trailingIconButton="ellipsis" trailing-a11y-label="More options" />
<native:list-item headline="Buy milk" trailingIconButton="trash" trailing-a11y-label="Delete" on-trailing-press="deleteTodo({{ $todo->id }})" />
</code-snippet>
@endverbatim

Expand Down
6 changes: 6 additions & 0 deletions src/Elements/ListItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
75 changes: 75 additions & 0 deletions tests/ListItemTrailingPressTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

use Native\Mobile\Edge\CallbackRegistry;
use Native\Mobile\Edge\ElementRegistry;
use Native\Mobile\Edge\NativeElementCollector;
use Native\Mobile\Edge\NativeTagPrecompiler;
use Native\Mobile\UI\Elements\ListItem;

/**
* A trailing icon button's press handler set from Blade has to reach the
* wire as `on_trailing_press`, which both renderers already fire.
*/
beforeEach(function () {
NativeElementCollector::reset();
ElementRegistry::reset();
ElementRegistry::register('list_item', ListItem::class);
});

afterEach(function () {
NativeElementCollector::reset();
ElementRegistry::reset();
});

function trailingPressTree(array $attrs, CallbackRegistry $registry): array
{
NativeElementCollector::leaf('list_item', ['headline' => '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)(
'<native:list-item headline="Buy milk" trailingIconButton="trash" on-trailing-press="deleteTodo({{ $id }})" />'
);
} 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' => []]);
});
Loading