Skip to content
21 changes: 17 additions & 4 deletions app/Http/Controllers/ShowDocumentationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
use Illuminate\View\View;
Expand Down Expand Up @@ -116,9 +117,18 @@ protected function getPageProperties($platform, $version, $page = null): array
$pageProperties['tableOfContents'] = $this->extractTableOfContents($pageProperties['content']);

$navigation = $this->getNavigation($platform, $version);
$pageProperties['navigation'] = Menu::build($navigation, function (Menu $menu, $nav): void {

$superNativeBadge = Blade::render(
'<x-icons.super-native class="ml-1 inline-block size-3.5 shrink-0 align-[-0.2em] text-yellow-500" aria-label="Super Native (beta)" />'
);

$label = fn (array $node): string => ($node['super_native'] ?? false)
? $node['title'].$superNativeBadge
: $node['title'];

$pageProperties['navigation'] = Menu::build($navigation, function (Menu $menu, $nav) use ($label): void {
if (array_key_exists('path', $nav)) {
$menu->link($nav['path'], $nav['title']);
$menu->link($nav['path'], $label($nav));
} elseif (array_key_exists('children', $nav)) {
$menu->setItemParentAttribute('x-data', '{ open: $el.classList.contains(\'active\') }');

Expand Down Expand Up @@ -168,14 +178,14 @@ protected function getPageProperties($platform, $version, $page = null): array
]);

foreach ($child['children'] as $subChild) {
$subSubmenu->link($subChild['path'], $subChild['title']);
$subSubmenu->link($subChild['path'], $label($subChild));
}

$subSubmenu->append('</div>');

$submenu->submenu($subHeader, $subSubmenu);
} else {
$submenu->link($child['path'], $child['title']);
$submenu->link($child['path'], $label($child));
}
}

Expand Down Expand Up @@ -249,6 +259,7 @@ protected function getNavigation(string $platform, string $version): array
'path' => $path,
'title' => $parsedSection->matter('title', ''),
'order' => $parsedSection->matter('order', 0),
'super_native' => (bool) $parsedSection->matter('super_native', false),
]);
}

Expand Down Expand Up @@ -288,6 +299,7 @@ protected function getNavigation(string $platform, string $version): array
'path' => $path,
'title' => $title,
'order' => $parsedSection->matter('order', 0),
'super_native' => (bool) $parsedSection->matter('super_native', false),
]);
}

Expand Down Expand Up @@ -335,6 +347,7 @@ protected function getNavigation(string $platform, string $version): array
'path' => $path,
'title' => $title,
'order' => $parsedPage->matter('order', 0),
'super_native' => (bool) $parsedPage->matter('super_native', false),
]);
}

Expand Down
7 changes: 7 additions & 0 deletions resources/views/components/docs/super-native-beta.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div class="not-prose my-6 flex items-start gap-3 rounded-2xl bg-yellow-50 px-5 py-4 text-yellow-900 ring-1 ring-yellow-200 dark:bg-yellow-950/40 dark:text-yellow-100 dark:ring-yellow-800/40" role="note">
<x-icons.super-native class="mt-0.5 size-5 shrink-0 text-yellow-600 dark:text-yellow-400" />
<div class="text-sm leading-relaxed">
<p class="font-semibold">This is a Super Native feature &mdash; currently in beta</p>
<p class="mt-1 text-yellow-900/80 dark:text-yellow-100/80">{{ $slot->isEmpty() ? 'Super Native is still in beta, so its APIs and behaviour may change before a stable release.' : $slot }}</p>
</div>
</div>
14 changes: 14 additions & 0 deletions resources/views/components/icons/super-native.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<svg
{{ $attributes->merge(['class' => 'lucide lucide-super-native']) }}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/>
</svg>
2 changes: 1 addition & 1 deletion resources/views/docs/mobile/3/edge-components/_index.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
title: EDGE Components
order: 30
order: 50
---
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
title: Activity Indicator
order: 350
super_native: true
---

<x-docs.super-native-beta />

## Overview

A circular spinner indicating background activity. Always indeterminate — for determinate progress use
[`<native:progress-bar>`](progress-bar). Renders as a SwiftUI `ProgressView` on iOS and Material3
`CircularProgressIndicator` on Android.

@verbatim
```blade
<native:activity-indicator />
```
@endverbatim

## Props

All [shared layout and style attributes](layout) are supported, plus:

- `size` - `"sm"`, `"md"` (default), or `"lg"` (optional, string). Legacy ints `1`=large, `2`=small are also accepted
- `color` - Spinner color as hex string (optional). Leave unset to use `theme.primary`
- `a11y-label` - Accessibility label (optional)

<aside>

`<native:activity-indicator />` is a self-closing element. It does not accept children.

The default tint comes from `theme.primary`. The `color` prop is an escape hatch — useful when the spinner sits on
a non-theme-styled container (e.g. a light spinner over a dark image overlay).

</aside>

## Examples

### Centered loading screen

@verbatim
```blade
<native:column fill center>
<native:activity-indicator size="lg" />
<native:text class="text-base text-slate-400 mt-4">Loading...</native:text>
</native:column>
```
@endverbatim

### Inline loading

@verbatim
```blade
<native:row :gap="8" :align-items="1">
<native:activity-indicator size="sm" />
<native:text class="text-sm text-slate-500">Refreshing</native:text>
</native:row>
```
@endverbatim

### Override the tint

@verbatim
```blade
<native:activity-indicator color="#7C3AED" />
```
@endverbatim

## Element

```php
use Nativephp\NativeUi\Elements\ActivityIndicator;

ActivityIndicator::make()
->size('lg')
->color('#7C3AED')
->a11yLabel('Loading messages');
```

- `make()` - Create a new indicator
- `size(string|int $size)` - `"sm" | "md" | "lg"`. Legacy: `1`=large, `2`=small
- `color(string $hex)` - Override the theme tint
- `a11yLabel(string $value)` - Accessibility label
93 changes: 93 additions & 0 deletions resources/views/docs/mobile/3/edge-components/badge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
title: Badge
order: 360
super_native: true
---

<x-docs.super-native-beta />

## Overview

A small count or text marker, typically used as an overlay on nav items, list rows, or buttons. Renders as a capsule
pill.

Per Model 3, colors come from the theme via the semantic `variant` prop — there are no per-instance overrides.

@verbatim
```blade
<native:badge :count="3" />
```
@endverbatim

## Props

- `count` - Numeric count. Renders as `"99+"` for values above 99 (optional, int)
- `label` - Arbitrary short text. Wins over `count` when both are set (optional, string)
- `variant` - Color variant (optional, string, default: `destructive`):
- `destructive` — `theme.destructive` / `theme.onDestructive`
- `primary` — `theme.primary` / `theme.onPrimary`
- `accent` — `theme.accent` / `theme.onAccent`
- `a11y-label` - Accessibility label (optional)

<aside>

`<native:badge />` is a self-closing element. It does not accept children. For a badge attached to a navigation
icon, see the `badge` and `news` props on [`<native:bottom-nav-item>`](bottom-nav).

</aside>

## Examples

### Count badge

@verbatim
```blade
<native:row :gap="8" :align-items="1">
<native:icon name="notifications" :size="24" />
<native:badge :count="$unreadCount" />
</native:row>
```
@endverbatim

### Label badge

@verbatim
```blade
<native:badge label="New" variant="primary" />
```
@endverbatim

### Anchored to an icon

Use a [`<native:stack>`](stack) to layer the badge over its target:

@verbatim
```blade
<native:stack :width="40" :height="40">
<native:icon name="cart" :size="32" />
<native:column class="absolute" :top="-2" :right="-2">
<native:badge :count="$cartItems" />
</native:column>
</native:stack>
```
@endverbatim

## Element

```php
use Nativephp\NativeUi\Elements\Badge;

Badge::make()
->count(3)
->variant('primary');

Badge::make()
->label('New')
->variant('accent');
```

- `make()` - Create a badge
- `count(int $count)` - Numeric count (capped display at `99+`)
- `label(string $text)` - Short text label (wins over `count`)
- `variant(string $variant)` - `destructive | primary | accent`
- `a11yLabel(string $value)` - Accessibility label
62 changes: 59 additions & 3 deletions resources/views/docs/mobile/3/edge-components/bottom-nav.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,28 +40,84 @@ A bottom navigation bar with up to 5 items. Used for your app's primary navigati

- `label-visibility` - `labeled`, `selected`, or `unlabeled` (optional, default: `labeled`)
- `dark` - Force dark mode styling (optional)
- `active-color` - Color of the active tab's icon and label. Hex string (optional)
- `background-color` - Bar background color. Hex string. Wins over `dark`'s default (optional)
- `text-color` - Color of inactive tab icons and labels. Hex string. Active tabs use `active-color` (optional)

<aside>

The bar handles its own bottom safe-area inset internally — the home-indicator zone on iOS, the gesture-bar zone on
Android. Don't add your own padding for it. The bar's background extends to the screen edge while its content stays
above the indicator, mirroring iOS `UITabBar`.

</aside>

## Children

A `<native:bottom-nav>` can contain up to 5 `<native:bottom-nav-item>` elements.

### Props

- `id` - Unique identifier (required)
- `icon` - A named [icon](icons) (required)
- `label` - Accessibility label (required)
- `url` - A URL to navigate to in the web view (required)
- `active` - Highlight this item as active (optional, default: `false`)
- `badge` - Badge text/number (optional)
- `news` - Show "new" indicator dot (optional, default: `false`)
- `badge` - Badge text/number, e.g. `"2"` — small red pill anchored top-right of the icon (optional)
- `news` - Show a small red dot anchored top-right of the icon. Mutually exclusive with `badge` (optional, default: `false`)

<aside>

Any `url` that doesn't match the web view's domain will open in the user's default browser.
Tab taps use `replace` semantics — tapping a tab swaps the current screen rather than pushing onto the stack. The
back chevron pops the entire tabs section in one step instead of stepping through tab history.

Any `url` that doesn't match a registered native route will exit to the web view and load that URL there.

</aside>

### `badge` example

<div class="sm:w-1/2">

![](/img/docs/edge-bottom-nav-item-badge.png)

</div>

## Builder API

When a `<native:bottom-nav>` is supplied by a [layout](../the-basics/layouts), you build it fluently with the `TabBar`
and `Tab` builders rather than writing it in Blade.

```php
use Native\Mobile\Edge\Layouts\Builders\Tab;
use Native\Mobile\Edge\Layouts\Builders\TabBar;

TabBar::make()
->dark()
->activeColor('#0891b2')
->labelVisibility('labeled')
->backgroundColor('#0F172A')
->textColor('#94A3B8')
->add(Tab::link('Chats', '/syncup', icon: 'chat_bubble')->badge('2'))
->add(Tab::link('Friends', '/syncup/friends', icon: 'person.3.fill')->news())
->add(Tab::link('Profile', '/syncup/profile', icon: 'person')->active());
```

### `TabBar` methods

- `make()` - Create a new builder
- `dark(bool $dark = true)` - Force dark mode styling
- `activeColor(string $color)` - Color of the active tab's icon and label
- `backgroundColor(string $color)` - Bar background color (overrides `dark()`'s default)
- `textColor(string $color)` - Color of inactive tab icons and labels
- `labelVisibility(string $mode)` - `"labeled"`, `"selected"`, or `"unlabeled"`
- `add(Tab $tab)` - Append a tab item

### `Tab` methods

- `link(string $label, string $url, ?string $icon = null)` - Build a tab. The id defaults to the label slugified
- `id(string $id)` - Override the auto-generated id
- `icon(string $icon)` - A named [icon](icons)
- `badge(string $badge, ?string $color = null)` - Show a numeric/text badge
- `news(bool $news = true)` - Show a red dot indicator
- `active(bool $active = true)` - Mark this tab as active
Loading
Loading