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
147 changes: 147 additions & 0 deletions resources/views/docs/mobile/4/edge-components/accordion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
---
title: Accordion
order: 90
---

## Overview

An expandable disclosure section — a tappable header row that opens and closes a collapsible content area.
Renders as a SwiftUI `DisclosureGroup` on iOS and a Compose column with an `AnimatedVisibility` content area
on Android.

An accordion wraps two child tags: a [`<native:accordion-header>`](#props) holding the always-visible row, and a
[`<native:accordion-content>`](#props) holding the collapsible body. Both accept any child elements.

@verbatim
```blade
@php $showSpecs = false; @endphp

<native:accordion :expanded="$showSpecs" @change="toggleSpecs">
<native:accordion-header>
<native:text class="text-base font-semibold">Specifications</native:text>
</native:accordion-header>
<native:accordion-content>
<native:text class="text-sm text-theme-on-surface-variant">Weight — 1.24 kg</native:text>
<native:text class="text-sm text-theme-on-surface-variant">Battery — up to 18 hours</native:text>
</native:accordion-content>
</native:accordion>
```
@endverbatim

`showSpecs` is a public bool property on your component — the `@php` line stands in for
`public bool $showSpecs = false;` — and `toggleSpecs()` is called with the new state whenever the user
taps the header.

Both platforms draw their own trailing chevron — the `DisclosureGroup` indicator on iOS, a rotating Material
arrow on Android — so don't add one to your header content. Tapping anywhere on the header row toggles the
section on both platforms.

## Props

- `expanded` - Whether the content area is open (optional, boolean, default: `false`). This is a live binding,
not just a mount-time hint — assigning the bound property from PHP animates the group open or closed at any
point, so patterns like "expand all" work
- `a11y-label` - Accessibility label (optional)
- `a11y-hint` - Accessibility hint (optional)

`<native:accordion-header>` and `<native:accordion-content>` take no props of their own beyond the same
`a11y-label` / `a11y-hint` pair — they exist to mark which children belong to which slot.

## Events

- `@change` - Component method called when the user expands or collapses the section. Receives the new
expanded state as a boolean parameter

<aside>

The direct children of `<native:accordion>` must be one `<native:accordion-header>` and one
`<native:accordion-content>`. The renderers pick each slot by child type — any other direct child is
silently ignored.

</aside>

## Two-way Binding

The accordion's state prop is `expanded`, not `value` — and the `native:model` directive expands to a
`:value` binding, which the accordion doesn't read. So unlike [`<native:toggle>`](toggle), `native:model`
alone won't drive an accordion. Write the pair explicitly: bind `:expanded` and point `@change` at
`__syncProperty`, the same sync handler `native:model` generates.

@verbatim
```blade
@php $showDetails = false; @endphp

<native:accordion :expanded="$showDetails" @change="__syncProperty('showDetails')">
<native:accordion-header>
<native:text class="text-base font-semibold">Order details</native:text>
</native:accordion-header>
<native:accordion-content>
<native:text class="text-sm text-theme-on-surface-variant">3 items · Arrives Thursday</native:text>
</native:accordion-content>
</native:accordion>

<native:text class="text-sm text-theme-on-surface-variant">{{ $showDetails ? 'Expanded' : 'Collapsed' }}</native:text>
```
@endverbatim

Tapping the header syncs `showDetails` back automatically — the echo below updates on every toggle. The sync
runs both ways: set `$showDetails` from any component method and the group animates to match. Both renderers
echo-prevent, so adopting a programmatic value never fires `@change` back at your component.

`sync-mode` and `debounce-ms` are not accepted — a header tap is a single discrete event, so there is nothing
to defer or debounce.

## Examples

### FAQ list

@verbatim
```blade
@php $faqs = [
['q' => 'How do I reset my password?', 'a' => 'Use the link on the sign-in screen.'],
['q' => 'Can I change my plan later?', 'a' => 'Yes — upgrades apply immediately, downgrades at renewal.'],
]; @endphp

<native:column class="w-full gap-0 px-4">
@foreach ($faqs as $faq)
<native:accordion>
<native:accordion-header>
<native:text class="text-base font-medium">{{ $faq['q'] }}</native:text>
</native:accordion-header>
<native:accordion-content>
<native:text class="text-sm text-theme-on-surface-variant pb-3">{{ $faq['a'] }}</native:text>
</native:accordion-content>
</native:accordion>
<native:divider />
@endforeach
</native:column>
```
@endverbatim

Accordions without `:expanded` start collapsed, and without `@change` they still toggle natively — wire the
event only when your component needs to know.

## Element

```php
use Native\Mobile\UI\Elements\Accordion;
use Native\Mobile\UI\Elements\AccordionContent;
use Native\Mobile\UI\Elements\AccordionHeader;
use Native\Mobile\UI\Elements\Text;

Accordion::make(
AccordionHeader::make(Text::make('Specifications')),
AccordionContent::make(Text::make('Weight — 1.24 kg')),
)
->expanded(true)
->onChange('toggleSpecs');
```

- `make(Element ...$children)` - Create an accordion from its header and content children
- `expanded(bool $expanded)` - Open or close the content area
- `onChange(string $method)` - Component method invoked when the user toggles the section
- `a11yLabel(string $value)` - Accessibility label
- `a11yHint(string $value)` - Accessibility hint

`AccordionHeader::make(...)` and `AccordionContent::make(...)` take their child elements the same way and
expose only the two a11y setters.
30 changes: 30 additions & 0 deletions resources/views/docs/mobile/4/edge-components/button.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ Slot content is treated as plain text — nested tags are stripped and whitespac
in `config/native-ui.php`) — see [Theming](../digging-deeper/theming)
- `size` - `sm`, `md` (default), `lg`
- `icon` - A leading [icon](icon#icon-name-reference) name (optional)
- `ios-icon` / `android-icon` - Per-platform overrides for the leading icon: an [SF Symbol](icon#ios-sf-symbols)
name on iOS, a [Material Icon](icon#android-material-icons) name on Android. `icon` is the fallback on whichever
platform has no override — or skip it and declare only per-platform icons. `iosIcon` / `androidIcon` and the
`<native:icon>`-style `ios` / `android` are accepted as aliases
- `icon-trailing` - A trailing [icon](icon#icon-name-reference) name (optional)
- `ios-icon-trailing` / `android-icon-trailing` - Per-platform overrides for the trailing icon, mirroring
`ios-icon` / `android-icon` (camelCase aliases accepted; no `ios` / `android` shorthand for this slot)
- `font` - Custom font for the label: a `resources/fonts/` file token or a config alias like `accent` (optional, string) — see [Text › Custom fonts](text#custom-fonts)
- `line-height` - Label line height as a multiplier of the font size (optional, float)
- `line-height-px` - Label line height as an absolute value in pixels (optional, float)
Expand Down Expand Up @@ -96,6 +102,30 @@ attributes are intentionally dropped before reaching the renderer.
```
@endverbatim

### Platform icons

When one shared name doesn't map well on both platforms, give each platform its own symbol — an
[SF Symbol](icon#ios-sf-symbols) name on iOS, a [Material Icon](icon#android-material-icons) name on Android:

@verbatim
```blade
<native:button
label="Tap to Pay"
ios-icon="wave.3.right"
android-icon="nfc"
@press="startPayment"
/>
```
@endverbatim

Resolution happens per platform: each side uses its override, falling back to `icon` where none is given. Bound
`:ios-icon` / `:android-icon` also accept `App\Icons` enum cases, exactly like
[`<native:icon>`'s `:ios` / `:android`](icon#typed-icon-enums). The trailing slot works the same way via
`ios-icon-trailing` / `android-icon-trailing`.

On iOS the icon's layout height is pinned to the size-driven icon size, so button height depends only on `size` —
not on which SF Symbol the button carries. Tall glyphs like `wave.3.right` no longer stretch the button.

### Loading state

@verbatim
Expand Down
14 changes: 14 additions & 0 deletions resources/views/docs/mobile/4/edge-components/chip.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ fully rounded and can be adjusted with `rounded-*` classes.
- `label` - Chip text (optional, string). Can also be passed as the first argument to `make()`
- `selected` / `value` - Whether the chip is active (optional, boolean, default: `false`)
- `icon` - Leading [icon](icon#icon-name-reference) name (optional, string)
- `ios-icon` / `android-icon` - Per-platform overrides for the leading icon: an [SF Symbol](icon#ios-sf-symbols)
name on iOS, a [Material Icon](icon#android-material-icons) name on Android. `icon` is the fallback on whichever
platform has no override. Bound `:ios-icon` / `:android-icon` also accept
[enum cases](icon#typed-icon-enums); `iosIcon` / `androidIcon` and `ios` / `android` are accepted as aliases
- `disabled` - Disable the chip (optional, boolean, default: `false`)
- `a11y-label` - Accessibility label (optional)
- `a11y-hint` - Accessibility hint (optional)
Expand Down Expand Up @@ -83,6 +87,16 @@ driving `selected` from one property keeps the row single-select.
```
@endverbatim

When the platforms need different symbols, override per platform — an SF Symbol on iOS, a Material name on Android:

@verbatim
```blade
@php $tapToPay = false; @endphp

<native:chip label="Tap to Pay" ios-icon="wave.3.right" android-icon="nfc" native:model="tapToPay" />
```
@endverbatim

## Element

```php
Expand Down
13 changes: 13 additions & 0 deletions resources/views/docs/mobile/4/edge-components/tab-row.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ Here `currentTab` stands in for `public int $currentTab = 0;` on your component.

- `label` - Tab label (required, string). Can also be passed as the first argument to `make()`
- `icon` - Optional [icon](icon#icon-name-reference) name rendered above the label
- `ios-icon` / `android-icon` - Per-platform overrides for the tab icon: an [SF Symbol](icon#ios-sf-symbols) name
on iOS, a [Material Icon](icon#android-material-icons) name on Android. `icon` is the fallback on whichever
platform has no override. Bound `:ios-icon` / `:android-icon` also accept
[enum cases](icon#typed-icon-enums); `iosIcon` / `androidIcon` and `ios` / `android` are accepted as aliases
- `a11y-label` - Accessibility label override (optional)

## Examples
Expand Down Expand Up @@ -119,6 +123,15 @@ typically add `fill` to the outer column and the content panes so they occupy th
```
@endverbatim

When a shared name doesn't map well on both platforms, give a tab per-platform icons — an SF Symbol on iOS, a
Material name on Android:

@verbatim
```blade
<native:tab label="Tap to Pay" ios-icon="wave.3.right" android-icon="nfc" />
```
@endverbatim

## Element

```php
Expand Down
Loading
Loading