From 76acb295fc0fb64b61eecc7f452845fdec7ab4ee Mon Sep 17 00:00:00 2001 From: Shane Rosenthal Date: Wed, 8 Jul 2026 21:53:01 -0400 Subject: [PATCH 1/9] docs(mobile/v4): Device/Dialog/File/System are now core built-ins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These four APIs moved from standalone plugins into nativephp/mobile core. Add SuperNative reference pages for each — documented from the actual core source (the old plugin READMEs were stale) — remove the empty plugins/core stubs from the sidebar, and 301-redirect their old URLs to the new pages. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../docs/mobile/4/plugins/core/device.md | 4 - .../docs/mobile/4/plugins/core/dialog.md | 4 - .../views/docs/mobile/4/plugins/core/file.md | 4 - .../docs/mobile/4/plugins/core/system.md | 4 - .../docs/mobile/4/super-native/device.md | 112 ++++++++++++++++++ .../docs/mobile/4/super-native/dialog.md | 111 +++++++++++++++++ .../views/docs/mobile/4/super-native/file.md | 63 ++++++++++ .../docs/mobile/4/super-native/system.md | 78 ++++++++++++ routes/web.php | 6 + 9 files changed, 370 insertions(+), 16 deletions(-) delete mode 100644 resources/views/docs/mobile/4/plugins/core/device.md delete mode 100644 resources/views/docs/mobile/4/plugins/core/dialog.md delete mode 100644 resources/views/docs/mobile/4/plugins/core/file.md delete mode 100644 resources/views/docs/mobile/4/plugins/core/system.md create mode 100644 resources/views/docs/mobile/4/super-native/device.md create mode 100644 resources/views/docs/mobile/4/super-native/dialog.md create mode 100644 resources/views/docs/mobile/4/super-native/file.md create mode 100644 resources/views/docs/mobile/4/super-native/system.md diff --git a/resources/views/docs/mobile/4/plugins/core/device.md b/resources/views/docs/mobile/4/plugins/core/device.md deleted file mode 100644 index 8ed74240..00000000 --- a/resources/views/docs/mobile/4/plugins/core/device.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Device -order: 400 ---- diff --git a/resources/views/docs/mobile/4/plugins/core/dialog.md b/resources/views/docs/mobile/4/plugins/core/dialog.md deleted file mode 100644 index 788aec6e..00000000 --- a/resources/views/docs/mobile/4/plugins/core/dialog.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Dialog -order: 500 ---- diff --git a/resources/views/docs/mobile/4/plugins/core/file.md b/resources/views/docs/mobile/4/plugins/core/file.md deleted file mode 100644 index 9136481d..00000000 --- a/resources/views/docs/mobile/4/plugins/core/file.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: File -order: 600 ---- diff --git a/resources/views/docs/mobile/4/plugins/core/system.md b/resources/views/docs/mobile/4/plugins/core/system.md deleted file mode 100644 index 44f7e38d..00000000 --- a/resources/views/docs/mobile/4/plugins/core/system.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: System -order: 1500 ---- diff --git a/resources/views/docs/mobile/4/super-native/device.md b/resources/views/docs/mobile/4/super-native/device.md new file mode 100644 index 00000000..b196bad9 --- /dev/null +++ b/resources/views/docs/mobile/4/super-native/device.md @@ -0,0 +1,112 @@ +--- +title: Device +order: 100 +--- + +## Overview + +The `Device` API exposes device hardware and information — vibration, the flashlight, a stable device +identifier, and device + battery details. + +It's a **core built-in** in v4: the facade resolves with nothing to install or register. + +```php +use Native\Mobile\Facades\Device; +``` + +## Vibrate + +Trigger a short haptic tap: + +```php +$fired = Device::vibrate(); // bool — true if the haptic actually fired +``` + +On Android this uses the `VIBRATE` permission, which ships in the app manifest automatically. iOS needs no +permission. + +## Flashlight + +Toggle the rear flashlight on or off and read back the new state: + +```php +$result = Device::flashlight(); +// ['success' => true, 'state' => true] state: true = on, false = off +``` + +| Key | Type | Description | +| --- | --- | --- | +| `success` | bool | Whether the toggle succeeded | +| `state` | bool | The flashlight state after toggling (`true` = on) | + +On Android this uses the `FLASHLIGHT` permission, included in the manifest automatically. + +## Device identifier + +```php +$id = Device::getId(); // ?string +``` + +A stable per-install identifier — `identifierForVendor` on iOS, `ANDROID_ID` on Android. Returns `null` when +called off-device (e.g. in tests or the web preview). + +## Device info + +`getInfo()` returns a JSON **string**, so decode it before use: + +```php +$info = json_decode(Device::getInfo(), true); + +$info['platform']; // 'ios' | 'android' +$info['model']; // e.g. 'iPhone15,3' +``` + +| Field | Description | +| --- | --- | +| `name` | Device name | +| `model` | Device model identifier | +| `platform` | `'ios'` or `'android'` | +| `operatingSystem` | OS name | +| `osVersion` | OS version string | +| `manufacturer` | Device manufacturer | +| `language` | Device language as a BCP 47 tag (e.g. `en-US`) | +| `isVirtual` | Whether running in a simulator/emulator | +| `memUsed` | Memory usage in bytes | +| `webViewVersion` | WebView version | + + + +## Battery + +`getBatteryInfo()` also returns a JSON string: + +```php +$battery = json_decode(Device::getBatteryInfo(), true); + +$battery['batteryLevel']; // 0.0 – 1.0 +$battery['isCharging']; // bool +``` + +| Field | Description | +| --- | --- | +| `batteryLevel` | Battery level from `0.0` to `1.0` | +| `isCharging` | Whether the device is charging | + +## Permissions + +| Platform | Permissions | +| --- | --- | +| Android | `VIBRATE`, `FLASHLIGHT` — merged into your manifest automatically | +| iOS | None | + + diff --git a/resources/views/docs/mobile/4/super-native/dialog.md b/resources/views/docs/mobile/4/super-native/dialog.md new file mode 100644 index 00000000..64680c31 --- /dev/null +++ b/resources/views/docs/mobile/4/super-native/dialog.md @@ -0,0 +1,111 @@ +--- +title: Dialog +order: 110 +--- + +## Overview + +The `Dialog` API shows native alert dialogs and toast/snackbar notifications — a real `UIAlertController` on +iOS and `AlertDialog` on Android, so they look and feel exactly like the platform. + +It's a **core built-in** in v4: the facade resolves with nothing to install or register. + +```php +use Native\Mobile\Facades\Dialog; +``` + +## Alerts + +Show an alert with a title, message, and optional buttons: + +```php +// Simple alert with a default OK button +Dialog::alert('Hello', 'Welcome to the app!'); + +// Custom buttons +Dialog::alert('Confirm', 'Are you sure?', ['Cancel', 'Delete']); +``` + +`alert()` returns a `PendingAlert` you can configure fluently. If you don't call `->show()`, the alert displays +automatically when the object goes out of scope. + +| Method | Description | +| --- | --- | +| `->id(string $id)` | Tag the alert so you can tell which one a button press came from | +| `->event(string $class)` | Dispatch a custom event class instead of the default `ButtonPressed` | +| `->remember()` | Flash the alert's `id` to the session so you can read it back later with `PendingAlert::lastId()` | +| `->show()` | Display the alert explicitly (otherwise it shows on destruct) | +| `->buttonPressed(Closure $cb)` | Run a callback when a button is tapped (see below) | +| `->on(string $class, Closure $cb)` | Callback for a custom event set via `->event()` | + +### Handling button presses + +Chain a callback directly onto the alert. It runs on your live component, so `$this` works just like a method: + +```php +Dialog::alert('Confirm', 'Are you sure?', ['Cancel', 'Delete']) + ->buttonPressed(function ($event) { + if ($event->label === 'Delete') { + $this->deleteItem(); + } + }); +``` + +Or listen from the component with `#[On]`. The event's public properties bind to your method parameters by name: + +```php +use Native\Mobile\Attributes\On; +use Native\Mobile\Events\Alert\ButtonPressed; + +#[On(ButtonPressed::class)] +public function onButton(int $index, string $label, ?string $id = null): void +{ + if ($id === 'delete-confirm' && $label === 'Delete') { + $this->deleteItem(); + } +} +``` + +The `ButtonPressed` event carries: + +| Property | Type | Description | +| --- | --- | --- | +| `index` | int | The tapped button's index (0-based) | +| `label` | string | The button's label text | +| `id` | ?string | The alert's `id`, if one was set | + +If you didn't set an explicit `id`, call `->remember()` to flash the auto-generated one to the session, then +read it back in your listener with `PendingAlert::lastId()`: + +```php +Dialog::alert('Confirm', 'Delete this item?', ['Cancel', 'Delete'])->remember(); + +#[On(ButtonPressed::class)] +public function onButton(string $label, ?string $id = null): void +{ + if ($id === \Native\Mobile\PendingAlert::lastId() && $label === 'Delete') { + $this->deleteItem(); + } +} +``` + +## Toasts + +A brief, non-blocking message — a `Snackbar` on Android, an overlay on iOS: + +```php +Dialog::toast('Item saved!'); // 'long' (~4s) by default +Dialog::toast('Copied', 'short'); // 'short' (~2s) +``` + +| Parameter | Type | Default | Description | +| --- | --- | --- | --- | +| `message` | string | required | The text to display | +| `duration` | string | `'long'` | `'short'` (~2s) or `'long'` (~4s) | + + diff --git a/resources/views/docs/mobile/4/super-native/file.md b/resources/views/docs/mobile/4/super-native/file.md new file mode 100644 index 00000000..0820be46 --- /dev/null +++ b/resources/views/docs/mobile/4/super-native/file.md @@ -0,0 +1,63 @@ +--- +title: File +order: 120 +--- + +## Overview + +The `File` API performs native file operations — moving and copying files — using each platform's file system +directly. + +It's a **core built-in** in v4: the facade resolves with nothing to install or register. + +```php +use Native\Mobile\Facades\File; +``` + +## Move + +```php +$ok = File::move('/path/to/source.txt', '/path/to/destination.txt'); // bool +``` + +## Copy + +```php +$ok = File::copy('/path/to/source.txt', '/path/to/copy.txt'); // bool +``` + +Both methods return a `bool` — `true` on success, `false` if the operation failed. + +| Parameter | Type | Description | +| --- | --- | --- | +| `from` | string | Source file path | +| `to` | string | Destination file path | + +## Behavior + +- Parent directories are created automatically if they don't exist. +- An existing destination file is overwritten. +- File integrity is verified after a copy. +- On Android, if a rename fails across file systems, it falls back to copy + delete. + +## Example + +Move a recording out of temporary storage into a permanent location: + +```php +use Native\Mobile\Facades\File; + +$temp = sys_get_temp_dir().'/recording.m4a'; +$permanent = storage_path('recordings/recording.m4a'); + +if (File::move($temp, $permanent)) { + // saved +} +``` + + diff --git a/resources/views/docs/mobile/4/super-native/system.md b/resources/views/docs/mobile/4/super-native/system.md new file mode 100644 index 00000000..a3a12c29 --- /dev/null +++ b/resources/views/docs/mobile/4/super-native/system.md @@ -0,0 +1,78 @@ +--- +title: System +order: 130 +--- + +## Overview + +The `System` API covers system-level concerns — platform detection and opening the app's settings screen. + +It's a **core built-in** in v4: the facade resolves with nothing to install or register. + +```php +use Native\Mobile\Facades\System; +``` + +## Platform detection + +```php +System::isIos(); // true on iOS +System::isAndroid(); // true on Android +System::isMobile(); // true on either platform +``` + +Use these to branch behavior or conditionally render UI for a specific platform. + +Each is also available as a global helper function — `isIos()`, `isAndroid()`, `isMobile()` — for terse use in +Blade and components: + +```php +if (isAndroid()) { + // ... +} +``` + +In Blade, the same checks are available as conditional directives: + +@verbatim +```blade +@ios + {{-- iOS-only markup --}} +@endios + +@android + {{-- Android-only markup --}} +@endandroid + +@mobile + {{-- running inside the native app (iOS or Android) --}} +@endmobile + +@web + {{-- running in a browser / outside the native app --}} +@endweb +``` +@endverbatim + +Each also supports the usual `@@else…` and `@@unless…` forms — `@@elseios`, `@@unlessandroid`, and so on. + +## App settings + +Open the app's page in the device Settings app — useful for sending a user to re-grant a permission they +previously denied: + +```php +System::appSettings(); +``` + +## Appearance (light / dark) + +Reading the current appearance and reacting to theme changes lives with the rest of theming — see +[Theming → Appearance in PHP](theming#appearance-in-php) for `System::appearance()`, `isDarkMode()`, +`isLightMode()`, the `isDark()` / `theme()` helpers, and the `AppearanceChanged` event. + + diff --git a/routes/web.php b/routes/web.php index 1396ef7e..c825879b 100644 --- a/routes/web.php +++ b/routes/web.php @@ -72,6 +72,12 @@ Route::redirect('t-shirt', 'blog/nativephp-for-mobile-is-now-free'); Route::redirect('tshirt', 'blog/nativephp-for-mobile-is-now-free'); +// v4: Device/Dialog/File/System moved from plugins into core built-ins; their docs +// now live in the SuperNative section (must precede the generic core-plugin redirect below). +foreach (['device', 'dialog', 'file', 'system'] as $corePage) { + Route::redirect("docs/mobile/4/plugins/core/{$corePage}", "/docs/mobile/4/super-native/{$corePage}", 301); +} + // Redirect mobile core plugin docs to plugin directory pages Route::get('docs/mobile/{version}/plugins/core/{page}', function (string $version, string $page) { return redirect("/plugins/nativephp/mobile-{$page}", 301); From c776a887d498fff54b21c5f2d3b3178391510fd9 Mon Sep 17 00:00:00 2001 From: Shane Rosenthal Date: Wed, 8 Jul 2026 21:53:17 -0400 Subject: [PATCH 2/9] =?UTF-8?q?docs(mobile/v4):=20SuperNative=20feature=20?= =?UTF-8?q?docs=20=E2=80=94=20appearance,=20text,=20navbar,=20bottom-bar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Theming: "Appearance in PHP" — System::appearance()/isDarkMode(), the isDark()/isLight()/theme() helpers, and the AppearanceChanged event. - Text: inline runs and select-text/select-none selection. - Layouts: NavBar::titleView()/logo() and keyboard-aware . - Text Input: cross-link to the keyboard-aware bottom bar. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../mobile/4/edge-components/text-input.md | 8 ++ .../docs/mobile/4/edge-components/text.md | 47 ++++++++++- .../docs/mobile/4/super-native/layouts.md | 77 +++++++++++++++++++ .../docs/mobile/4/super-native/theming.md | 65 ++++++++++++++++ 4 files changed, 195 insertions(+), 2 deletions(-) diff --git a/resources/views/docs/mobile/4/edge-components/text-input.md b/resources/views/docs/mobile/4/edge-components/text-input.md index 5c3634cf..2d36dd10 100644 --- a/resources/views/docs/mobile/4/edge-components/text-input.md +++ b/resources/views/docs/mobile/4/edge-components/text-input.md @@ -80,6 +80,14 @@ Both variants are self-closing. They do not accept children. + + ## Two-way Binding Use the `native:model` directive for automatic two-way binding with a component property. The directive expands to diff --git a/resources/views/docs/mobile/4/edge-components/text.md b/resources/views/docs/mobile/4/edge-components/text.md index eec6ba8f..bd7f6015 100644 --- a/resources/views/docs/mobile/4/edge-components/text.md +++ b/resources/views/docs/mobile/4/edge-components/text.md @@ -34,8 +34,50 @@ All [shared layout and style attributes](layout) are supported, plus: + +## Inline runs + +Nest `` elements inside a `` to style spans within a single paragraph. The nested runs +and the surrounding text compose into **one** attributed string that wraps together as a unit — each run carries +its own classes (weight, color, size): + +@verbatim +```blade + + Use bold and + color inline. + +``` +@endverbatim + +Runs render in document order, so interleaved text and nested `` stay in sequence. A `` +with no nested runs behaves exactly like a plain string. + +## Text selection + +Text isn't selectable by default. Add `select-text` to make a subtree long-press-selectable (the native Copy +menu). It's container-scoped and inherited, so it covers every descendant — put it on a wrapping element to make a +whole region selectable. Use `select-none` to opt a nested subtree back out: + +@verbatim +```blade + + Selectable heading + This body copy can be selected and copied. + + Not selectable + +``` +@endverbatim + + @@ -135,3 +177,4 @@ Text::make('Hello') - `color(string $hex)` - Text color - `textAlign(int $align)` - `0`=start, `1`=center, `2`=end - `maxLines(int $lines)` - Truncate after N lines +- `selectable(bool $on = true)` - Make the subtree selectable (mirrors `select-text` / `select-none`) diff --git a/resources/views/docs/mobile/4/super-native/layouts.md b/resources/views/docs/mobile/4/super-native/layouts.md index f8f68b9d..9724f93b 100644 --- a/resources/views/docs/mobile/4/super-native/layouts.md +++ b/resources/views/docs/mobile/4/super-native/layouts.md @@ -101,6 +101,8 @@ in a screen's Blade. - `make()` — create a builder - `title(?string)` / `subtitle(?string)` — title and the small line under it +- `titleView(Element|View)` — render a custom element or Blade view in the bar's centered slot instead of the string title (a logo lockup, wordmark, …) +- `logo(string $src, float $height = 28)` — convenience over `titleView()` for a bundled logo image - `back(bool $show = true)` — show the back chevron - `backgroundColor(string)` / `textColor(string)` — bar background and title/icon tint - `elevation(int $px)` — hairline thickness at the bottom of the bar @@ -119,6 +121,29 @@ in a screen's Blade. - `destructive(bool = true)` — render in the destructive tint - `items(array $actions)` — nest `NavAction`s to render a pull-down menu; `NavAction::divider()` adds a separator +#### Custom title view / logo + +Use `logo()` for the common case — a bundled brand image in place of the string title — or `titleView()` for any +element tree or Blade view: + +```php +public function navBar(NativeComponent $screen): ?NavBar +{ + return NavBar::make() + ->logo('images/logo.png'); // bundled asset, ~28pt tall + // ->titleView(Image::make('images/logo.png')->height(24)) + // ->titleView(view('native.brand-lockup')) +} +``` + + + ### `TabBar` — the bottom tabs - `make()` — create a builder; `add(Tab $tab)` — append a tab (up to 5) @@ -157,6 +182,58 @@ class AppLayout extends NativeLayout } ``` +## Keyboard-aware bottom content + +Beyond the tab bar, a layout or an individual screen can pin its own content to the bottom of the screen — a chat +input, a search field, a contextual action bar. This content **stays above the software keyboard automatically**: +on iOS via `.safeAreaInset(.bottom)`, on Android via the `Scaffold` bottom bar plus `imePadding()`. The main +content region sits above it and keeps its own scroll. + +The most ergonomic way is an inline `` at the root of a screen's Blade. It's lifted out of the +content flow and pinned, and it overrides the layout's `bottomBar()` for that screen: + +@verbatim +```blade + + + @foreach($messages as $message) + {{ $message->body }} + @endforeach + + + {{-- Pinned to the bottom, riding above the keyboard while typing --}} + + + + + + + +``` +@endverbatim + +To pin the same content across every screen under a layout, override `bottomBar()` instead — it returns any +element tree: + +```php +public function bottomBar(NativeComponent $screen): ?Element +{ + // Return an element tree, or null for no bottom bar. + // An inline on a screen overrides this for that screen. +} +``` + +Style the bar with the `glass` / `glass-thick` classes for a Liquid Glass capsule. Bottom-pinned content is only +rendered by layouts using native chrome (`usesNativeChrome()` is `true`). + + + ## How chrome wraps the screen When a screen renders, the framework's `wrapWithChrome` flow: diff --git a/resources/views/docs/mobile/4/super-native/theming.md b/resources/views/docs/mobile/4/super-native/theming.md index 8d57317b..50da3b63 100644 --- a/resources/views/docs/mobile/4/super-native/theming.md +++ b/resources/views/docs/mobile/4/super-native/theming.md @@ -76,6 +76,71 @@ Specify any token under `dark` to override just that value: ], ``` +## Appearance in PHP + +The renderers switch between the `light` and `dark` token blocks automatically as the system appearance changes. +When you need the current appearance in PHP — to pick an asset, resolve a token, or branch logic — read it from +the `System` facade: + +```php +use Native\Mobile\Facades\System; + +System::appearance(); // 'light' | 'dark' +System::isDarkMode(); // bool +System::isLightMode(); // bool +``` + +Global helper functions wrap the same calls for terse use in Blade and components: + +```php +isDark(); // bool +isLight(); // bool +``` + +### Resolving a token in PHP + +The `theme()` helper returns a token's value **for the current appearance** — the PHP-side counterpart to the +`bg-theme-*` / `text-theme-*` classes, reading from the same `config/native-ui.php` theme config: + +```php +theme('primary'); // config('native-ui.theme.dark.primary') in dark mode, light otherwise +theme('primary', '#0F766E'); // fall back to a value when the token is unset +``` + +Pass a fallback when a setter needs a non-null string — `theme()` returns your default when the key is missing +(or `native-ui` isn't installed). + +### Reacting to changes + +When the OS flips the theme — a Control Center toggle, or the sunset auto-switch — the `AppearanceChanged` event +fires. React in a component with `#[On]`; `$mode` is `'light'` or `'dark'`: + +```php +use Native\Mobile\Attributes\On; +use Native\Mobile\Events\System\AppearanceChanged; + +#[On(AppearanceChanged::class)] +public function appearanceChanged(string $mode): void +{ + // re-resolve anything appearance-dependent +} +``` + +`AppearanceChanged` also dispatches globally, so code anywhere in the app can listen — not just the active +screen: + +```php +use Illuminate\Support\Facades\Event; +use Native\Mobile\Events\System\AppearanceChanged; + +Event::listen(AppearanceChanged::class, function (AppearanceChanged $e) { + // $e->mode +}); +``` + +The query side (`System::appearance()` / `isDark()`) is kept in sync off this event, so reads stay fresh without +a bridge round-trip. + ## Runtime theming For per-tenant or user-selectable themes, merge tokens at runtime from a service provider with `Theme::merge()`. From 0b62dac942b32e558497035e609eafd08b61213b Mon Sep 17 00:00:00 2001 From: Shane Rosenthal Date: Wed, 8 Jul 2026 21:53:30 -0400 Subject: [PATCH 3/9] =?UTF-8?q?docs(mobile/v4):=20release=20notes=20?= =?UTF-8?q?=E2=80=94=20core-plugin=20migration=20+=20Vite=20opt-in?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Upgrade Guide: new "Upgrading To 4.0 From 3.x" — remove the mobile-device/ dialog/file/system plugins before upgrading; Vite dev server is now opt-in. - Changelog: Breaking Changes for both. - Commands/Development: document the --vite flag (Vite no longer auto-starts; pass --vite for JS/CSS HMR). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../mobile/4/getting-started/changelog.md | 5 ++ .../docs/mobile/4/getting-started/commands.md | 10 +++ .../mobile/4/getting-started/development.md | 21 +++++- .../mobile/4/getting-started/upgrade-guide.md | 66 +++++++++++++++++++ 4 files changed, 99 insertions(+), 3 deletions(-) diff --git a/resources/views/docs/mobile/4/getting-started/changelog.md b/resources/views/docs/mobile/4/getting-started/changelog.md index 81384a58..2ce7b918 100644 --- a/resources/views/docs/mobile/4/getting-started/changelog.md +++ b/resources/views/docs/mobile/4/getting-started/changelog.md @@ -26,6 +26,11 @@ For changes prior to v4, see the [v3 documentation](/docs/mobile/3/getting-start - **[Native navigation stack](../super-native/navigation)** — register screens with `Route::native()`, then push, pop, and replace them with native transitions - **[Component testing suite](../testing/introduction)** — mount a `NativeComponent`, drive interactions, and assert on state and output entirely in-process, with no device or simulator +### Breaking Changes + +- **Device, Dialog, File and System are now core built-ins** — the `nativephp/mobile-device`, `nativephp/mobile-dialog`, `nativephp/mobile-file`, and `nativephp/mobile-system` plugins have moved into `nativephp/mobile`. **Remove the standalone plugins before upgrading** (see the [Upgrade Guide](upgrade-guide)). The facades and events are unchanged, so no application code changes are needed. +- **The Vite dev server is now opt-in** — `native:run` / `native:watch` no longer start Vite automatically. Pass `--vite` to enable JS/CSS HMR. The `--no-vite` flag still works but is now redundant. See [Hot Reloading](development#hot-reloading). + ### For Plugin Developers - **No breaking changes** to the plugin architecture — add the `^4.0` constraint to your plugin's `nativephp/mobile` dependency and you're done diff --git a/resources/views/docs/mobile/4/getting-started/commands.md b/resources/views/docs/mobile/4/getting-started/commands.md index ae22359e..8b8f0e0e 100644 --- a/resources/views/docs/mobile/4/getting-started/commands.md +++ b/resources/views/docs/mobile/4/getting-started/commands.md @@ -38,6 +38,7 @@ php artisan native:run {os?} {udid?} | `udid` | Specific device/simulator UDID | | `--build=debug` | Build type: `debug`, `release`, or `bundle` | | `--watch` | Enable hot reloading during development | +| `--vite` | Start the Vite dev server for JS/CSS HMR (opt-in; off by default) | | `--start-url=` | Initial URL/path to load (e.g., `/dashboard`) | | `--no-tty` | Disable TTY mode for non-interactive environments | @@ -60,6 +61,15 @@ php artisan native:watch {platform?} {target?} |--------|-----------------------------------------| | `platform` | Target platform: `ios/i` or `android/a` | | `target` | The device/simulator UDID to watch | +| `--vite` | Start the Vite dev server for JS/CSS HMR (opt-in; off by default) | + + ### native:jump diff --git a/resources/views/docs/mobile/4/getting-started/development.md b/resources/views/docs/mobile/4/getting-started/development.md index cbd99fae..bfd44ee3 100644 --- a/resources/views/docs/mobile/4/getting-started/development.md +++ b/resources/views/docs/mobile/4/getting-started/development.md @@ -177,12 +177,27 @@ application to the target device and _then_ start the watcher, all in one go. This will start a long-lived process that watches your application's source files for changes, pushing them into the emulator after any updates and reloading the current screen. -If you're using Vite, we'll also use your Node CLI tool of choice (`npm`, `bun`, `pnpm`, or `yarn`) to run Vite's HMR -server. +If you're using Vite for your UI (React/Vue/Tailwind, etc.), pass the `--vite` flag and we'll also start Vite's HMR +server using your Node CLI tool of choice (`npm`, `bun`, `pnpm`, or `yarn`): + +```shell +php artisan native:watch --vite + +# or build, deploy, and start watching in one go: +php artisan native:run --watch --vite +``` + + ### Enabling HMR -To make HMR work, you'll need to add the `hot` file helper to your `laravel` plugin's config in your `vite.config.js`: +To make HMR work, add the `hot` file helper to your `laravel` plugin's config in your `vite.config.js`, then run +the watcher with `--vite` (above): ```js import { nativephpMobile, nativephpHotFile } from './vendor/nativephp/mobile/resources/js/vite-plugin.js'; // [tl! focus] diff --git a/resources/views/docs/mobile/4/getting-started/upgrade-guide.md b/resources/views/docs/mobile/4/getting-started/upgrade-guide.md index ea5cca07..3f49bba7 100644 --- a/resources/views/docs/mobile/4/getting-started/upgrade-guide.md +++ b/resources/views/docs/mobile/4/getting-started/upgrade-guide.md @@ -3,6 +3,72 @@ title: Upgrade Guide order: 3 --- +## Upgrading To 4.0 From 3.x + +v4's headline is [SuperNative](../super-native/introduction) — fully native UI. Most of the release is additive, +but there is **one breaking change to your dependencies**: a handful of APIs that used to be separate plugins are +now core built-ins. + +### Device, Dialog, File and System are now built in + +`Device`, `Dialog`, `File`, and `System` now ship inside `nativephp/mobile` — their native bridge functions are +registered by core. If you have the standalone plugins installed, **remove them before upgrading**, otherwise +their bridge functions register twice. + +Uninstall each one you have (this also unregisters it from your `NativeServiceProvider`): + +```shell +php artisan native:plugin:uninstall nativephp/mobile-device +php artisan native:plugin:uninstall nativephp/mobile-dialog +php artisan native:plugin:uninstall nativephp/mobile-file +php artisan native:plugin:uninstall nativephp/mobile-system +``` + +Or remove them directly with Composer if they were never registered in your `NativeServiceProvider`: + +```shell +composer remove nativephp/mobile-device nativephp/mobile-dialog nativephp/mobile-file nativephp/mobile-system +``` + +**No application code changes are required.** The `Native\Mobile\Facades\{Device, Dialog, File, System}` facades +and their events (`ButtonPressed`, etc.) are unchanged. Their docs now live in the SuperNative section: +[Device](../super-native/device), [Dialog](../super-native/dialog), [File](../super-native/file), and +[System](../super-native/system). + +### The Vite dev server is now opt-in + +`native:run` and `native:watch` no longer start the Vite dev server automatically. If you rely on Vite HMR during +development (React/Vue/Tailwind, etc.), add the `--vite` flag: + +```shell +php artisan native:watch --vite +php artisan native:run --watch --vite +``` + +The old `--no-vite` flag still exists but is now redundant — Vite is off unless you ask for it. If you have +`--no-vite` in your scripts, you can drop it. + +### Update your dependency + +```json +"require": { + "nativephp/mobile": "~3.1.0" // [tl! remove] + "nativephp/mobile": "~4.0.0" // [tl! add] +} +``` + +```sh +composer update +php artisan native:install --force +``` + + + + ## Upgrading To 3.1 From 3.0 v3.1 is a drop-in upgrade with no breaking changes. The headline feature is a **persistent PHP runtime** that From 3c1bae8f7759fa1f2cdf3a35f8176f42409b91c3 Mon Sep 17 00:00:00 2001 From: Shane Rosenthal Date: Wed, 8 Jul 2026 21:57:42 -0400 Subject: [PATCH 4/9] docs(mobile/v4): list select-text/select-none in class reference; note Composer conflict guard - Add the text-selection classes to the "Supported Tailwind classes" table. - Upgrade Guide: v4 declares a Composer conflict with the four ex-plugins, so the update hard-blocks until they're removed (clearer than "registers twice"). Co-Authored-By: Claude Opus 4.8 (1M context) --- resources/views/docs/mobile/4/edge-components/layout.md | 1 + .../views/docs/mobile/4/getting-started/upgrade-guide.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/views/docs/mobile/4/edge-components/layout.md b/resources/views/docs/mobile/4/edge-components/layout.md index b0957bf4..04b716a8 100644 --- a/resources/views/docs/mobile/4/edge-components/layout.md +++ b/resources/views/docs/mobile/4/edge-components/layout.md @@ -295,6 +295,7 @@ The parser recognizes the classes listed below. | Text size | `text-xs`, `text-sm`, `text-base`, `text-lg`, `text-xl`, `text-2xl`, `text-3xl`, `text-4xl`, `text-5xl`, `text-6xl`, arbitrary `text-[N]` | | Font weight | `font-thin`, `font-extralight`, `font-light`, `font-normal`, `font-medium`, `font-semibold`, `font-bold`, `font-extrabold`, `font-black` | | Text align | `text-left`, `text-center`, `text-right` | +| Text selection | `select-text`, `select-none` (container-scoped; descendants inherit) | | Safe area | `safe-area` (top + bottom), `safe-area-top`, `safe-area-bottom` | | Liquid Glass | `glass`, `glass:prominent`, `glass:interactive`, `glass:clear` (compose: `glass:clear:interactive`) | diff --git a/resources/views/docs/mobile/4/getting-started/upgrade-guide.md b/resources/views/docs/mobile/4/getting-started/upgrade-guide.md index 3f49bba7..efe95bbf 100644 --- a/resources/views/docs/mobile/4/getting-started/upgrade-guide.md +++ b/resources/views/docs/mobile/4/getting-started/upgrade-guide.md @@ -12,8 +12,8 @@ now core built-ins. ### Device, Dialog, File and System are now built in `Device`, `Dialog`, `File`, and `System` now ship inside `nativephp/mobile` — their native bridge functions are -registered by core. If you have the standalone plugins installed, **remove them before upgrading**, otherwise -their bridge functions register twice. +registered by core. `nativephp/mobile` v4 declares a Composer **conflict** with the four standalone plugins, so +`composer update` will refuse to resolve until you **remove them**. Uninstall each one you have (this also unregisters it from your `NativeServiceProvider`): From 6cdc6d1ff74e7b780c019572a8bfe6c17ecbe250 Mon Sep 17 00:00:00 2001 From: Shane Rosenthal Date: Wed, 8 Jul 2026 22:03:52 -0400 Subject: [PATCH 5/9] docs(mobile/v4): add "Why SuperNative" rationale to the upgrade guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frame the strategic shift: the web view tied the UI to upstream stacks we didn't own (Inertia 3 dropping axios, Livewire 4 emoji filenames breaking iOS builds). SuperNative is a stack we own end to end — PHP to SwiftUI/Compose. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../mobile/4/getting-started/upgrade-guide.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/resources/views/docs/mobile/4/getting-started/upgrade-guide.md b/resources/views/docs/mobile/4/getting-started/upgrade-guide.md index efe95bbf..37c532a8 100644 --- a/resources/views/docs/mobile/4/getting-started/upgrade-guide.md +++ b/resources/views/docs/mobile/4/getting-started/upgrade-guide.md @@ -9,6 +9,24 @@ v4's headline is [SuperNative](../super-native/introduction) — fully native UI but there is **one breaking change to your dependencies**: a handful of APIs that used to be separate plugins are now core built-ins. +### Why SuperNative + +For its first three major versions, NativePHP for Mobile was built around a fast, opinionated web view. It worked +well — but it tied your app's UI to a stack of moving parts we didn't own, and every upstream release was a chance +for something to break. Inertia 3 dropped its axios dependency and broke Inertia apps. Livewire 4 began emitting +compiled filenames containing an emoji (🔥) that iOS builds refused to package. We spent real energy chasing a +target that kept moving, on layers we couldn't control. + +SuperNative changes that equation. Instead of rendering your UI in a browser and hoping the layers above stay +compatible, it renders real SwiftUI and Jetpack Compose views driven directly by your PHP — a stack we own end to +end, from your Laravel app all the way down to the native view tree. That means our effort goes into making *that* +fast, stable, and capable, rather than reacting to churn elsewhere. The web view's advantages have narrowed as +SuperNative's rendering has matured, and for new work SuperNative is where the platform — and our focus — is +headed. + +The web view isn't going away: [it's still available as a component](../edge-components/web-view) for the cases +that genuinely need HTML. But it's now opt-in, not the foundation. + ### Device, Dialog, File and System are now built in `Device`, `Dialog`, `File`, and `System` now ship inside `nativephp/mobile` — their native bridge functions are From 09a5b22b3e3547f761b6111240ef128fecd5d5c2 Mon Sep 17 00:00:00 2001 From: Shane Rosenthal Date: Wed, 8 Jul 2026 22:11:37 -0400 Subject: [PATCH 6/9] docs(mobile/v4): correct Livewire 4 emoji-filename detail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The breakage was our bundled PHP binaries initially failing to read the emoji (🔥) filenames, not the iOS packager rejecting them. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../views/docs/mobile/4/getting-started/upgrade-guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/docs/mobile/4/getting-started/upgrade-guide.md b/resources/views/docs/mobile/4/getting-started/upgrade-guide.md index 37c532a8..9fd2cbe2 100644 --- a/resources/views/docs/mobile/4/getting-started/upgrade-guide.md +++ b/resources/views/docs/mobile/4/getting-started/upgrade-guide.md @@ -14,8 +14,8 @@ now core built-ins. For its first three major versions, NativePHP for Mobile was built around a fast, opinionated web view. It worked well — but it tied your app's UI to a stack of moving parts we didn't own, and every upstream release was a chance for something to break. Inertia 3 dropped its axios dependency and broke Inertia apps. Livewire 4 began emitting -compiled filenames containing an emoji (🔥) that iOS builds refused to package. We spent real energy chasing a -target that kept moving, on layers we couldn't control. +filenames containing an emoji (🔥) that our bundled PHP binaries initially couldn't read. We spent real energy +chasing a target that kept moving, on layers we couldn't control. SuperNative changes that equation. Instead of rendering your UI in a browser and hoping the layers above stay compatible, it renders real SwiftUI and Jetpack Compose views driven directly by your PHP — a stack we own end to From c3989b5b1433845b77072c08affc8ca7ea3f1dac Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Thu, 9 Jul 2026 13:59:29 +0100 Subject: [PATCH 7/9] docs(mobile/v4): reorganize sections and make docs version-neutral - Move Architecture to just below Getting Started (before The Basics) - Move Device, Dialog, File and System from SuperNative into The Basics; place Dialog below Native UI - Remove version-specific phrasing ("in v4", "as of v4", "v3.1 introduces") so the docs port cleanly to future versions - Convert hard-coded /docs/mobile/3 and /docs/mobile/1 links to relative, version-portable paths Co-Authored-By: Claude Opus 4.8 (1M context) --- package-lock.json | 2 +- resources/views/docs/mobile/4/architecture/_index.md | 2 +- .../4/architecture/about-the-new-architecture.md | 6 +++--- .../views/docs/mobile/4/architecture/glossary.md | 2 +- .../views/docs/mobile/4/architecture/overview.md | 2 +- resources/views/docs/mobile/4/concepts/databases.md | 4 ++-- resources/views/docs/mobile/4/concepts/queues.md | 2 +- .../views/docs/mobile/4/edge-components/web-view.md | 2 +- .../views/docs/mobile/4/getting-started/commands.md | 2 +- .../docs/mobile/4/getting-started/configuration.md | 6 +++--- .../docs/mobile/4/getting-started/deployment.md | 4 ++-- .../docs/mobile/4/getting-started/development.md | 2 +- .../docs/mobile/4/getting-started/introduction.md | 2 +- .../docs/mobile/4/getting-started/upgrade-guide.md | 6 +++--- .../views/docs/mobile/4/plugins/best-practices.md | 8 ++++---- .../views/docs/mobile/4/super-native/introduction.md | 12 ++++++------ .../mobile/4/{super-native => the-basics}/device.md | 4 ++-- .../mobile/4/{super-native => the-basics}/dialog.md | 4 ++-- .../mobile/4/{super-native => the-basics}/file.md | 4 ++-- resources/views/docs/mobile/4/the-basics/jump.md | 10 +++++----- .../mobile/4/{super-native => the-basics}/system.md | 4 ++-- 21 files changed, 45 insertions(+), 45 deletions(-) rename resources/views/docs/mobile/4/{super-native => the-basics}/device.md (96%) rename resources/views/docs/mobile/4/{super-native => the-basics}/dialog.md (97%) rename resources/views/docs/mobile/4/{super-native => the-basics}/file.md (92%) rename resources/views/docs/mobile/4/{super-native => the-basics}/system.md (94%) diff --git a/package-lock.json b/package-lock.json index 5c328eae..a6c6dd65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "bold-condor", + "name": "nativephp-com-pr-419-3993c2ad", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/resources/views/docs/mobile/4/architecture/_index.md b/resources/views/docs/mobile/4/architecture/_index.md index 23fd3cd6..5bccd3fb 100644 --- a/resources/views/docs/mobile/4/architecture/_index.md +++ b/resources/views/docs/mobile/4/architecture/_index.md @@ -1,4 +1,4 @@ --- title: Architecture -order: 80 +order: 10 --- diff --git a/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md b/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md index 57a13307..ffcefdbd 100644 --- a/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md +++ b/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md @@ -3,8 +3,8 @@ title: About the New Architecture order: 10 --- -Since v1, NativePHP for Mobile has run your Laravel app on the device itself — no server, no network round-trip. In -v3 and earlier, your app's UI rendered as HTML inside a web view. That model is productive and familiar, and it's +NativePHP for Mobile runs your Laravel app on the device itself — no server, no network round-trip. Traditionally, +your app's UI rendered as HTML inside a web view. That model is productive and familiar, and it's [still fully supported](../super-native/introduction#is-the-web-view-still-an-option). But it puts a browser between your app and the platform, and some things can only feel truly native when they *are* native. @@ -68,7 +68,7 @@ app faster. If your app is happy in the web view, it will keep working exactly a ## Should you use it today? -SuperNative is **the default** in v4: new apps render native screens from the very first route. It's in beta, so +SuperNative is **the default**: new apps render native screens from the very first route. It's in beta, so expect rapid iteration — and if you'd rather wait, [opting out](../super-native/introduction#is-the-web-view-still-an-option) is one route and one component. diff --git a/resources/views/docs/mobile/4/architecture/glossary.md b/resources/views/docs/mobile/4/architecture/glossary.md index 51ee86f6..5601ccdd 100644 --- a/resources/views/docs/mobile/4/architecture/glossary.md +++ b/resources/views/docs/mobile/4/architecture/glossary.md @@ -7,7 +7,7 @@ Definitions for the terms used throughout the Architecture section. ## SuperNative -The engine behind native rendering in NativePHP for Mobile v4. It spans everything described in this section: +The engine behind native rendering in NativePHP for Mobile. It spans everything described in this section: components, the render pipeline, the shared-memory boundary and the platform renderers. [About the New Architecture](about-the-new-architecture) is the best starting point. diff --git a/resources/views/docs/mobile/4/architecture/overview.md b/resources/views/docs/mobile/4/architecture/overview.md index a9d2fc8b..3ef7c0e6 100644 --- a/resources/views/docs/mobile/4/architecture/overview.md +++ b/resources/views/docs/mobile/4/architecture/overview.md @@ -4,7 +4,7 @@ order: 1 --- Welcome! This section is a look under the hood of [SuperNative](../super-native/introduction), the engine that powers -native rendering in NativePHP for Mobile v4. It explains how your Blade templates become real SwiftUI and Jetpack +native rendering in NativePHP for Mobile. It explains how your Blade templates become real SwiftUI and Jetpack Compose views, how state flows between PHP and the screen, and why the whole thing is fast. diff --git a/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md b/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md index ffcefdbd..79708bac 100644 --- a/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md +++ b/resources/views/docs/mobile/4/architecture/about-the-new-architecture.md @@ -5,10 +5,10 @@ order: 10 NativePHP for Mobile runs your Laravel app on the device itself — no server, no network round-trip. Traditionally, your app's UI rendered as HTML inside a web view. That model is productive and familiar, and it's -[still fully supported](../super-native/introduction#is-the-web-view-still-an-option). But it puts a browser between +[still fully supported](../architecture/super-native#is-the-web-view-still-an-option). But it puts a browser between your app and the platform, and some things can only feel truly native when they *are* native. -The new architecture — [SuperNative](../super-native/introduction) — removes that layer entirely. Your screens are +The new architecture — [SuperNative](../architecture/super-native) — removes that layer entirely. Your screens are real SwiftUI and Jetpack Compose views, created and updated directly by your PHP code. Here's why we built it, and what it changes. @@ -69,7 +69,7 @@ app faster. If your app is happy in the web view, it will keep working exactly a ## Should you use it today? SuperNative is **the default**: new apps render native screens from the very first route. It's in beta, so -expect rapid iteration — and if you'd rather wait, [opting out](../super-native/introduction#is-the-web-view-still-an-option) +expect rapid iteration — and if you'd rather wait, [opting out](../architecture/super-native#is-the-web-view-still-an-option) is one route and one component. Ready to go deeper? Start with [The Renderer](renderer). diff --git a/resources/views/docs/mobile/4/architecture/overview.md b/resources/views/docs/mobile/4/architecture/overview.md deleted file mode 100644 index 3ef7c0e6..00000000 --- a/resources/views/docs/mobile/4/architecture/overview.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Architecture Overview -order: 1 ---- - -Welcome! This section is a look under the hood of [SuperNative](../super-native/introduction), the engine that powers -native rendering in NativePHP for Mobile. It explains how your Blade templates become real SwiftUI and Jetpack -Compose views, how state flows between PHP and the screen, and why the whole thing is fast. - - - -These pages describe the internals as they exist today. SuperNative is in beta and moving quickly, so details may -evolve — the concepts, however, are stable. - -## Table of Contents - -- [About the New Architecture](about-the-new-architecture) — why we rebuilt rendering from the ground up, and what - it means for your apps. - -### Rendering - -- [The Renderer](renderer) — the rendering system at the heart of SuperNative, and the goals that shaped it. -- [Render, Publish, and Mount](render-publish-mount) — the three-phase pipeline that turns your PHP into pixels. -- [Cross-Platform Implementation](cross-platform-implementation) — how one shared core keeps iOS and Android in - perfect agreement. -- [Subtree Reuse](subtree-reuse) — the optimizations that make re-rendering cheap, automatically. -- [Threading Model](threading-model) — which threads do what, and how your UI stays responsive. - -### Build Tools - -- [Embedded PHP](embedded-php) — how a full PHP runtime ends up inside your app, built in lockstep with the - framework. - -### Reference - -- [Glossary](glossary) — every term used in these pages, defined in one place. - -If anything here is unclear or you'd like more depth on a particular topic, we'd love to hear from you. diff --git a/resources/views/docs/mobile/4/architecture/super-native.md b/resources/views/docs/mobile/4/architecture/super-native.md new file mode 100644 index 00000000..94b58f87 --- /dev/null +++ b/resources/views/docs/mobile/4/architecture/super-native.md @@ -0,0 +1,130 @@ +--- +title: SuperNative Introduction +order: 5 +--- + +## What is SuperNative? + +SuperNative is our name for a combination of technologies that enable PHP to produce platform-native UI at +blistering speeds. + +While SuperNative uses HTML-like syntax, **there is no need for a web view**. Your apps built with Blade +can fully leverage the native components and performance of each platform's UI tools, directly from PHP — SwiftUI +on iOS and Jetpack Compose on Android. + +Your app's screens are not web views rendering HTML. They are real, platform-native views, built and +updated by your PHP code. Same Laravel app, same Blade templates, two genuine native UIs. + +You don't need to think about the right syntax for Android vs iOS, just use EDGE. + +SuperNative is **the default**. New apps render native screens from the very first route — no configuration +required. + + + +## What SuperNative is not + +SuperNative is not a fully custom renderer, like Skia or Impeller. It does not attempt to create pixel-perfect +cross-platform user interfaces. Instead it *embraces* the differences and simply smooths over them with a single +consistent syntax. + +It's not another virtual machine on top of or adjacent to PHP trying to convert *all* instructions to/from native +equivalents. It's explicitly focused on turning PHP objects that conform to a known interface into a fixed-length +byte array that can be processed by an explicit native-side interpreter. + +It is also not a transpiler or HTML-to-native converter. We've built our own Blade engine that converts Blade components +into a simplified binary format instead of HTML ([The Renderer](renderer)) and passes the + +## Try it now + +The fastest way to see SuperNative is to run the demo app, +[`nativephp/super-native`](https://github.com/nativephp/super-native), on a simulator or device. + +You'll need a working NativePHP for Mobile [development environment](../getting-started/environment-setup) first +(Xcode for iOS, Android Studio for Android). Then clone the demo, install it, and run it: + +```shell +git clone https://github.com/nativephp/super-native +cd super-native +composer install +php artisan native:install +php artisan native:run +``` + +`native:run` builds the app and launches it on your connected device or simulator. Explore the source to see how +the screens are built, then start swapping in your own. + +## How it works + +SuperNative builds on three ideas working together: + +- **Shared memory with PHP** — the native layer and your PHP application share memory directly, so there's no + network round-trip, no serialization overhead, and no waiting on a web view bridge. State changes flow between + PHP and the native UI almost instantly. +- **Livewire-like components** — each screen is driven by a PHP component class that holds its state and behavior, + just like a Livewire component. User interactions call your methods, your properties update, and the UI + re-renders to match. +- **Blade components for DX** — you define your UI with the same [EDGE component](../edge-components/introduction) + syntax you already know. Familiar, expressive Blade templates compile down to native SwiftUI and Compose views. + +If you've built anything with Livewire, you already know how to build with SuperNative. + +For a look under the hood — how Blade becomes SwiftUI and Compose, how state flows across the shared-memory +boundary, and the threading model behind it — see the rest of the [Architecture](about-the-new-architecture) section. + + + +## Why SuperNative? + +Two reasons above all: + +- **Performance** — native views render and animate at full platform speed. No web view startup cost, no DOM, no + JavaScript bridge. Scrolling, transitions and gestures feel exactly the way users expect because they're powered + by the same UI frameworks every other native app uses. +- **Accessibility** — SwiftUI and Jetpack Compose come with the platform's accessibility support built in. + Screen readers, dynamic type, contrast settings and assistive controls work with your app out of the box, + rather than being approximated through a browser. + +There's more detail [in this blog article](/blog/supernative). + +## Is the web view still an option? + +Yes, but instead of being the default, it's now a component that you add to a native view. To make your app behave +the same way that NativePHP for Mobile versions before v4 did, you can do something like this: + +```php +// routes/mobile.php +Route::native('/home', WebViewScreen::class); + +// webviewscreen.blade.php + + +// routes/web.php +Route::view('/', 'welcome'); +``` + +Then just set `NATIVEPHP_START_URL=/home` in your `.env`. + +This way your existing web view-based app can keep on working and you can start adopt SuperNative one screen at a time +whenever you're ready — or not at all. + +## For Plugin Developers + +SuperNative contains **no breaking changes** to our plugin architecture. + +It actually expands what your plugins are capable of by giving you a standardized target for UI elements. That means your +plugins can ship fully native EDGE components that you know will work consistently for developers using your plugin. + +No need to make your plugins UI-less abstractions or support multiple flavors of front-end tooling; simply create and ship +EDGE components and every consumer of your plugin will see the UI you intended. diff --git a/resources/views/docs/mobile/4/concepts/_index.md b/resources/views/docs/mobile/4/concepts/_index.md deleted file mode 100644 index 6e3f1cfd..00000000 --- a/resources/views/docs/mobile/4/concepts/_index.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Concepts -order: 40 ---- diff --git a/resources/views/docs/mobile/4/digging-deeper/_index.md b/resources/views/docs/mobile/4/digging-deeper/_index.md new file mode 100644 index 00000000..a4ac31b2 --- /dev/null +++ b/resources/views/docs/mobile/4/digging-deeper/_index.md @@ -0,0 +1,4 @@ +--- +title: Digging Deeper +order: 40 +--- diff --git a/resources/views/docs/mobile/4/super-native/accessibility.md b/resources/views/docs/mobile/4/digging-deeper/accessibility.md similarity index 100% rename from resources/views/docs/mobile/4/super-native/accessibility.md rename to resources/views/docs/mobile/4/digging-deeper/accessibility.md diff --git a/resources/views/docs/mobile/4/concepts/authentication.md b/resources/views/docs/mobile/4/digging-deeper/authentication.md similarity index 100% rename from resources/views/docs/mobile/4/concepts/authentication.md rename to resources/views/docs/mobile/4/digging-deeper/authentication.md diff --git a/resources/views/docs/mobile/4/super-native/data-binding.md b/resources/views/docs/mobile/4/digging-deeper/data-binding.md similarity index 100% rename from resources/views/docs/mobile/4/super-native/data-binding.md rename to resources/views/docs/mobile/4/digging-deeper/data-binding.md diff --git a/resources/views/docs/mobile/4/concepts/databases.md b/resources/views/docs/mobile/4/digging-deeper/databases.md similarity index 98% rename from resources/views/docs/mobile/4/concepts/databases.md rename to resources/views/docs/mobile/4/digging-deeper/databases.md index 68aa80f1..70db2399 100644 --- a/resources/views/docs/mobile/4/concepts/databases.md +++ b/resources/views/docs/mobile/4/digging-deeper/databases.md @@ -24,7 +24,7 @@ When writing migrations, you need to consider any special recommendations for wo For example, prior to Laravel 11, SQLite foreign key constraints are turned off by default. If your application relies upon foreign key constraints, [you need to enable SQLite support for them](https://laravel.com/docs/database#configuration) before running your migrations. -**It's important to test your migrations on [prod builds](../getting-started/deployment#releasing) +**It's important to test your migrations on [prod builds](../publishing/introduction#releasing) before releasing updates!** You don't want to accidentally delete your user's data when they update your app. ## Seeding data with migrations diff --git a/resources/views/docs/mobile/4/concepts/deep-links.md b/resources/views/docs/mobile/4/digging-deeper/deep-links.md similarity index 100% rename from resources/views/docs/mobile/4/concepts/deep-links.md rename to resources/views/docs/mobile/4/digging-deeper/deep-links.md diff --git a/resources/views/docs/mobile/4/super-native/gestures.md b/resources/views/docs/mobile/4/digging-deeper/gestures.md similarity index 98% rename from resources/views/docs/mobile/4/super-native/gestures.md rename to resources/views/docs/mobile/4/digging-deeper/gestures.md index b5f81316..266ad503 100644 --- a/resources/views/docs/mobile/4/super-native/gestures.md +++ b/resources/views/docs/mobile/4/digging-deeper/gestures.md @@ -136,6 +136,6 @@ the native side plays it locally on touch. Three tools, three jobs: **`animate-*` props** for state-driven motion (a value changed — ease to it), **press feedback** for instant touch response, and **shared values** for finger-tracking or refresh-rate animation. For -motion *between screens*, see [Navigation](navigation#custom-transitions). +motion *between screens*, see [Navigation](../the-basics/routing#custom-transitions). diff --git a/resources/views/docs/mobile/4/super-native/lifecycle-hooks.md b/resources/views/docs/mobile/4/digging-deeper/lifecycle-hooks.md similarity index 97% rename from resources/views/docs/mobile/4/super-native/lifecycle-hooks.md rename to resources/views/docs/mobile/4/digging-deeper/lifecycle-hooks.md index 3cab6519..b5c2807b 100644 --- a/resources/views/docs/mobile/4/super-native/lifecycle-hooks.md +++ b/resources/views/docs/mobile/4/digging-deeper/lifecycle-hooks.md @@ -16,7 +16,7 @@ on top, **resumes** when those screens pop away, and is **unmounted** when it fi ## mount() Runs **once**, right after the screen is pushed onto the stack. This is where you load the screen's initial data -and read any [route params or navigation data](../super-native/navigation#reading-params-and-data). +and read any [route params or navigation data](../the-basics/routing#reading-params-and-data). ```php class ProductScreen extends NativeComponent diff --git a/resources/views/docs/mobile/4/concepts/push-notifications.md b/resources/views/docs/mobile/4/digging-deeper/push-notifications.md similarity index 100% rename from resources/views/docs/mobile/4/concepts/push-notifications.md rename to resources/views/docs/mobile/4/digging-deeper/push-notifications.md diff --git a/resources/views/docs/mobile/4/concepts/queues.md b/resources/views/docs/mobile/4/digging-deeper/queues.md similarity index 100% rename from resources/views/docs/mobile/4/concepts/queues.md rename to resources/views/docs/mobile/4/digging-deeper/queues.md diff --git a/resources/views/docs/mobile/4/super-native/reactivity.md b/resources/views/docs/mobile/4/digging-deeper/reactivity.md similarity index 98% rename from resources/views/docs/mobile/4/super-native/reactivity.md rename to resources/views/docs/mobile/4/digging-deeper/reactivity.md index 7f1c9f43..a1e1a690 100644 --- a/resources/views/docs/mobile/4/super-native/reactivity.md +++ b/resources/views/docs/mobile/4/digging-deeper/reactivity.md @@ -93,6 +93,6 @@ Accepted forms: `native:poll` (default 2s), `native:poll="500ms"` / `native:poll diff --git a/resources/views/docs/mobile/4/super-native/search.md b/resources/views/docs/mobile/4/digging-deeper/search.md similarity index 89% rename from resources/views/docs/mobile/4/super-native/search.md rename to resources/views/docs/mobile/4/digging-deeper/search.md index 86cb6431..0235e1d7 100644 --- a/resources/views/docs/mobile/4/super-native/search.md +++ b/resources/views/docs/mobile/4/digging-deeper/search.md @@ -9,7 +9,7 @@ A screen can present a native search bar in its navigation chrome and feed it fr a **static** corpus the platform filters for you, and a **dynamic** handler you implement for server- or database-backed results. -The search bar itself is shown by the [layout](layouts) chrome — via `NavBar::searchBar()` on a stack, or +The search bar itself is shown by the [layout](../the-basics/layouts) chrome — via `NavBar::searchBar()` on a stack, or `Tab::search()` on a tab. This page covers the component side: producing the results. ## Static search @@ -59,7 +59,7 @@ Or as a dedicated search tab: Tab::search('Search', icon: 'magnifyingglass', placeholder: 'Find anything'); ``` -See [Layouts](layouts) for where these builders live and how a layout wraps a screen. +See [Layouts](../the-basics/layouts) for where these builders live and how a layout wraps a screen.