From a021b8430c6362fbe4881702b8353b7bbeace408 Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Sun, 27 Sep 2026 18:47:17 +0100 Subject: [PATCH 1/6] Fill Mobile v4 docs gaps around mobile-ui, list items, binding and builds Agents building a small app kept falling back to vendor source for things the docs didn't say. This covers the ones we could verify against nativephp/mobile 4.5.2 and nativephp/mobile-ui 0.6.0: - Installation and quick start now install and register nativephp/mobile-ui, and explain what breaks without it. - Replace stale nativephp/native-ui package references. - List item: attribute spelling (camelCase), boolean binding, handler argument order, and that the trailing icon button has no Blade handler in 0.6.0. Remove the @trailing-press example that did nothing. - Text input and data binding: when to debounce, and replace the non-existent tag in examples. - Development: where native:run leaves the simulator .app and debug .apk. - Testing: setup notes and how to target list row callbacks. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../mobile/4/digging-deeper/accessibility.md | 1 - .../mobile/4/digging-deeper/data-binding.md | 15 +++-- .../4/digging-deeper/lifecycle-hooks.md | 2 +- .../docs/mobile/4/digging-deeper/theming.md | 4 +- .../docs/mobile/4/edge-components/icon.md | 2 +- .../mobile/4/edge-components/introduction.md | 28 ++++++++ .../docs/mobile/4/edge-components/list.md | 65 +++++++++++++++++-- .../mobile/4/edge-components/text-input.md | 26 ++++++++ .../docs/mobile/4/getting-started/commands.md | 7 +- .../mobile/4/getting-started/development.md | 24 +++++++ .../mobile/4/getting-started/installation.md | 34 ++++++++++ .../mobile/4/getting-started/quick-start.md | 17 ++++- .../docs/mobile/4/testing/interactions.md | 26 +++++++- .../docs/mobile/4/testing/introduction.md | 18 +++++ .../views/docs/mobile/4/the-basics/layouts.md | 6 +- .../docs/mobile/4/the-basics/native-ui.md | 8 +++ 16 files changed, 257 insertions(+), 26 deletions(-) diff --git a/resources/views/docs/mobile/4/digging-deeper/accessibility.md b/resources/views/docs/mobile/4/digging-deeper/accessibility.md index 1c4e698fc..6b84270b4 100644 --- a/resources/views/docs/mobile/4/digging-deeper/accessibility.md +++ b/resources/views/docs/mobile/4/digging-deeper/accessibility.md @@ -87,7 +87,6 @@ The tappable trailing icon button on a [list item](../edge-components/list) take headline="Backups" trailingIconButton="info" trailing-a11y-label="Backup details" - @trailing-press="showBackupInfo" /> ``` @endverbatim diff --git a/resources/views/docs/mobile/4/digging-deeper/data-binding.md b/resources/views/docs/mobile/4/digging-deeper/data-binding.md index cf168e82f..64c237a3a 100644 --- a/resources/views/docs/mobile/4/digging-deeper/data-binding.md +++ b/resources/views/docs/mobile/4/digging-deeper/data-binding.md @@ -11,7 +11,7 @@ PHP side; change the property in PHP and the control reflects it on the next ren @verbatim ```blade static - + ``` @endverbatim @@ -29,7 +29,7 @@ render sees the current value. Any input-style EDGE component binds with `native:model`: -- [``](../edge-components/text-input) — string +- [``, `` and ``](../edge-components/text-input) — string - [``](../edge-components/toggle) / [``](../edge-components/checkbox) — boolean - [``](../edge-components/slider) — float - [``](../edge-components/radio-group) / [``](../edge-components/select) — string @@ -51,13 +51,18 @@ useful for text inputs where syncing on every character is wasteful: | `native:model.lazy` | Alias for `.blur`. | | `native:model.debounce.300ms` | After the user stops changing it for the given delay. | +For text the user types freely, prefer a short debounce such as `native:model.debounce.150ms`. A live binding sends +every keystroke to PHP, and when someone types quickly an earlier keystroke's value can come back after later ones and +overwrite them, so characters appear to vanish. See +[Text Input › Choosing a sync mode](../edge-components/text-input#choosing-a-sync-mode). + @verbatim ```blade static {{-- Sync only when the user leaves the field --}} - + {{-- Sync 500ms after typing stops --}} - + ``` @endverbatim @@ -88,7 +93,7 @@ something other than a public property — set the value and change handler dire @verbatim ```blade static - + ``` @endverbatim diff --git a/resources/views/docs/mobile/4/digging-deeper/lifecycle-hooks.md b/resources/views/docs/mobile/4/digging-deeper/lifecycle-hooks.md index 82415a31c..48663f6ee 100644 --- a/resources/views/docs/mobile/4/digging-deeper/lifecycle-hooks.md +++ b/resources/views/docs/mobile/4/digging-deeper/lifecycle-hooks.md @@ -104,7 +104,7 @@ value. @verbatim ```blade static - + ``` @endverbatim diff --git a/resources/views/docs/mobile/4/digging-deeper/theming.md b/resources/views/docs/mobile/4/digging-deeper/theming.md index 7a8418770..60d1d770f 100644 --- a/resources/views/docs/mobile/4/digging-deeper/theming.md +++ b/resources/views/docs/mobile/4/digging-deeper/theming.md @@ -9,7 +9,7 @@ Every SuperNative app has one visual identity, defined in a single theme. Instea element, you name **semantic tokens** — `primary`, `surface`, `on-surface` — and reference them everywhere. Change a token once and it updates across every screen, in both light and dark mode. -The theme is provided by the `nativephp/native-ui` plugin (which ships the components), but it governs the whole +The theme is provided by the `nativephp/mobile-ui` plugin (which ships the components), but it governs the whole app, so it's the visual contract for everything you build. ## Publishing the config @@ -138,7 +138,7 @@ 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). +(or `nativephp/mobile-ui` isn't installed). ### Reacting to changes diff --git a/resources/views/docs/mobile/4/edge-components/icon.md b/resources/views/docs/mobile/4/edge-components/icon.md index 0e45e309b..b257d74b5 100644 --- a/resources/views/docs/mobile/4/edge-components/icon.md +++ b/resources/views/docs/mobile/4/edge-components/icon.md @@ -127,7 +127,7 @@ If you'd rather skip the `@@use` import, fully-qualified cases work anywhere: +## Installing the components + +Every element in this section comes from the `nativephp/mobile-ui` plugin. Core `nativephp/mobile` defines the +rendering pipeline and a few PHP element classes, but the SwiftUI and Compose renderers for all of these elements, +including `` and ``, ship in the plugin. Install and register it: + +```shell +composer require nativephp/mobile-ui +php artisan vendor:publish --tag=nativephp-plugins-provider +php artisan native:plugin:register nativephp/mobile-ui +``` + +If the plugin isn't registered in `app/Providers/NativeServiceProvider.php`, plugin elements such as `button`, +`list_item` or `outlined_text_input` throw `Unknown native element type` when the screen renders, and the core-backed +ones (`text`, `column`, `row` and friends) render nothing on the device. The PHP classes live in the +`Native\Mobile\UI\Elements` namespace. See [Installation](../getting-started/installation#install-the-ui-components). + +## Attribute names + +Most attributes are written in kebab-case (`leading-icon`, `on-refresh`, `max-length`). A few elements, notably +[``](list#list-item), take camelCase attributes (`leadingIcon`, `trailingText`, +`leadingCheckbox`). Spell attributes exactly as each component's page lists them: an unrecognised spelling is +silently ignored rather than raising an error. + +Boolean attributes follow PHP truthiness. A bare attribute (`disabled`) or a bound value (`:disabled="$busy"`) works +as you'd expect, but a literal string such as `disabled="false"` is a non-empty string and counts as `true`. Bind +booleans with `:` whenever the value can be false. + ## The `native:` prefix is optional `` and `` compile to exactly the same thing — the prefix is optional. We use it throughout diff --git a/resources/views/docs/mobile/4/edge-components/list.md b/resources/views/docs/mobile/4/edge-components/list.md index 56b9bccc4..e3d7333dd 100644 --- a/resources/views/docs/mobile/4/edge-components/list.md +++ b/resources/views/docs/mobile/4/edge-components/list.md @@ -46,6 +46,21 @@ Accepts any EDGE elements as children. `` is the canonical chi A pre-styled Material3 row with a headline, optional supporting + overline text, and configurable leading + trailing content slots. + + @verbatim ```blade onTrailingPress()` on a `ListItem` + element, or attach a `trailing-menu` instead - `trailing-a11y-label` - Accessibility label for the trailing icon button (recommended whenever `trailingIconButton` is set). See [Accessibility](../digging-deeper/accessibility) -- `trailing-menu` - Attach a tap-to-open dropdown to the row's trailing edge. When set without an explicit trailing +- `trailing-menu` - Attach a tap-to-open dropdown to the row's trailing edge (`trailingMenu` also works). When set without an explicit trailing slot, an `ellipsis` icon button is auto-created as the anchor. See [Menus](menus) Independent of the mutually-exclusive slot above, a row can also show a stack of small status icons: @@ -109,9 +127,11 @@ All color props accept the full [color grammar](../digging-deeper/theming#color- - `leadingIconColor`, `trailingIconColor`, `trailingTextColor` - Colors for the slot content - `leadingIconBgColor` - Background color of the leading icon's circle -### State +### State and accessibility - `disabled` - Disable the row (optional, boolean, default: `false`) +- `a11y-label` / `a11y-hint` - Screen-reader label and hint for the whole row. See + [Accessibility](../digging-deeper/accessibility) - `tonalElevation` - Tonal elevation in dp [Android] - `shadowElevation` - Shadow elevation in dp [Android] @@ -124,8 +144,22 @@ All color props accept the full [color grammar](../digging-deeper/theming#color- - `on-leading-change` / `on-trailing-change` - Component method called when the leading/trailing checkbox or radio is toggled, receiving the new value. Without a handler the control renders as a static state glyph. -`onTrailingPress()` fires on both platforms when the trailing icon button is tapped. The trailing switch is -interactive on [Android] only. +The fluent `onTrailingPress()` fires on both platforms when the trailing icon button is tapped. It has no Blade +attribute in `nativephp/mobile-ui` 0.6.0; see `trailingIconButton` above. The trailing switch is interactive on +[Android] only. + +Handlers receive their arguments in this order: the arguments you wrote in the expression, then the value the control +sends. So `on-leading-change="toggleTask(@{{ $task->id }})"` calls `toggleTask($id, $checked)`: + +```php +public function toggleTask(int $id, bool $checked): void +{ + Task::whereKey($id)->update(['done' => $checked]); +} +``` + +`on-swipe-delete` and `@press` send no value, so `on-swipe-delete="deleteTask(@{{ $task->id }})"` calls +`deleteTask($id)`. To drive these from a test, see [Testing a list](#testing-a-list). ### Swipe actions @@ -224,7 +258,7 @@ The checkbox, swipe, and row press are three independent targets on one row: tap check('toggleTask(1)') // tap the leading checkbox: calls toggleTask(1, true) + ->press('deleteTask(1)') // swipe-to-delete fires a press at its callback + ->press('openTask(2)'); // tap the row +}); +``` + ## Element ```php 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 59cb2130f..09524ac8b 100644 --- a/resources/views/docs/mobile/4/edge-components/text-input.md +++ b/resources/views/docs/mobile/4/edge-components/text-input.md @@ -184,6 +184,32 @@ automatically, so the `@{{ $name }}` echo updates as you type. - `blur` — only fires on focus loss / submit - `debounce` — fires after `debounce-ms` of inactivity (300ms when unset), or immediately on blur / submit +### Choosing a sync mode + +Plain `native:model` is `live`: every keystroke is a round trip to PHP and a re-render. That's fine for short fields +and for screens that react to each character, but it has a cost when someone types quickly. With several keystrokes +in flight, the value PHP sends back for an earlier keystroke can land after the user has typed more, and in +`nativephp/mobile-ui` 0.6.0 that older value overwrites the field. The visible symptom is characters vanishing (and +sometimes coming back) while typing. + +For free-typed text, debounce the binding so only one sync goes out once the user pauses: + +@verbatim +```blade static + +``` +@endverbatim + +A short window like 150ms still feels live to the user. Reach for: + +- `native:model.debounce.150ms` for text the user types freely: titles, notes, chat messages, new-item fields +- `native:model.debounce.300ms` (or longer) for search and filter boxes that trigger a query +- `native:model.blur` for form fields you only read when the form is submitted +- plain `native:model` only when you need every character, such as a character counter, and the field is short + +Debounced and blurred fields always sync immediately on submit and on focus loss, so `@submit="add"` sees the full +text. + ## Caret and selection reporting `@selectionChange` reports caret position and text selection back to your component — for the cases where `@change` diff --git a/resources/views/docs/mobile/4/getting-started/commands.md b/resources/views/docs/mobile/4/getting-started/commands.md index 3e1b6d77b..975e49bd5 100644 --- a/resources/views/docs/mobile/4/getting-started/commands.md +++ b/resources/views/docs/mobile/4/getting-started/commands.md @@ -48,6 +48,11 @@ with `php artisan native:plugin:register`. +The debug builds `native:run` produces are left on disk: the iOS simulator app at +`nativephp/ios/build/Build/Products/Debug-iphonesimulator/NativePHP-simulator.app` and the Android APK at +`nativephp/android/app/build/outputs/apk/debug/app-debug.apk`. See +[Finding the built app](development#finding-the-built-app). + ### native:watch Watch for file changes and sync to a running mobile app. @@ -403,7 +408,7 @@ php artisan native:plugin:install-agent ### native-ui:generate-icons Generate the `App\Icons\Ios`, `App\Icons\Android`, and `App\Icons\AndroidOutlined` enums so you can reference icons as -typed, autocompletable enum cases. Ships with the [native-ui](https://github.com/nativephp/native-ui) plugin. +typed, autocompletable enum cases. Ships with the [`nativephp/mobile-ui`](https://github.com/NativePHP/mobile-ui) plugin. ```shell php artisan native-ui:generate-icons diff --git a/resources/views/docs/mobile/4/getting-started/development.md b/resources/views/docs/mobile/4/getting-started/development.md index 3e8542536..261a79c5e 100644 --- a/resources/views/docs/mobile/4/getting-started/development.md +++ b/resources/views/docs/mobile/4/getting-started/development.md @@ -109,6 +109,30 @@ It's better than scratching your head for an hour trying to figure out why your +## Finding the built app + +`native:run` builds a normal debug app and then installs it. The build output stays on disk afterwards, so you can +hand it to a teammate, install it on another simulator or emulator, or upload it to a device farm. + +| Platform | Command | Output | +|----------|---------|--------| +| iOS simulator | `php artisan native:run ios {simulator-udid}` | `nativephp/ios/build/Build/Products/Debug-iphonesimulator/NativePHP-simulator.app` | +| Android debug | `php artisan native:run android --build=debug` | `nativephp/android/app/build/outputs/apk/debug/app-debug.apk` | + +A few things to know: + +- The simulator `.app` is always named `NativePHP-simulator.app`, whatever your app is called. NativePHP sets the + bundle name inside it from your `APP_NAME`. It only runs on simulators, not on physical devices. +- Install the `.app` on any booted simulator with `xcrun simctl install booted path/to/NativePHP-simulator.app`, and + the `.apk` on any emulator or device with `adb install -r path/to/app-debug.apk`. +- `--build=profileable` on Android writes `apk/profileable/app-profileable.apk` instead. +- The `nativephp` directory is rebuilt by `native:install --force`, so copy anything you want to keep somewhere else. +- These are development builds. For signed release builds (`.ipa`, release `.apk` or `.aab`), use + [`native:package`](commands#nativepackage) or [Bifrost](../publishing/bifrost). + +To find a simulator's UDID, run `xcrun simctl list devices available`. For Android device serials, run +`adb devices`. + ## Working with Xcode or Android Studio On occasion, it is useful to compile your app from inside the target platform's dedicated development tools, Android diff --git a/resources/views/docs/mobile/4/getting-started/installation.md b/resources/views/docs/mobile/4/getting-started/installation.md index ae602ec28..b4d2627ea 100644 --- a/resources/views/docs/mobile/4/getting-started/installation.md +++ b/resources/views/docs/mobile/4/getting-started/installation.md @@ -12,6 +12,40 @@ iOS and Android. And it's a single command away: composer require nativephp/mobile ``` +## Install the UI components + +The native UI elements (``, ``, ``, the text inputs and the rest of the +[EDGE components](../edge-components/introduction)) ship in a separate plugin, `nativephp/mobile-ui`. Install it +alongside the core package: + +```shell +composer require nativephp/mobile-ui +``` + +Like every [plugin](../plugins/using-plugins), it has to be registered before its native code is compiled into your +app. Publish the `NativeServiceProvider` and register the plugin: + +```shell +php artisan vendor:publish --tag=nativephp-plugins-provider +php artisan native:plugin:register nativephp/mobile-ui +``` + +This adds `\Native\Mobile\UI\NativeUIServiceProvider::class` to the `plugins()` array in +`app/Providers/NativeServiceProvider.php`. Check it's there with `php artisan native:plugin:list`. + + + ### We love Laravel NativePHP for Mobile is built to work with Laravel. We recommend that you install it into a diff --git a/resources/views/docs/mobile/4/getting-started/quick-start.md b/resources/views/docs/mobile/4/getting-started/quick-start.md index cb6f8ddca..938725834 100644 --- a/resources/views/docs/mobile/4/getting-started/quick-start.md +++ b/resources/views/docs/mobile/4/getting-started/quick-start.md @@ -28,11 +28,18 @@ php artisan native:jump If you already have a Laravel app: ```bash -composer require nativephp/mobile +composer require nativephp/mobile nativephp/mobile-ui + +php artisan vendor:publish --tag=nativephp-plugins-provider +php artisan native:plugin:register nativephp/mobile-ui php artisan native:jump ``` +`nativephp/mobile-ui` provides the native UI elements (text, buttons, lists, inputs and so on). It must be registered +in `app/Providers/NativeServiceProvider.php` or your screens will render blank. See +[Installation](installation#install-the-ui-components). + Scan the QR code with Jump and you're off! ## Install & run @@ -41,8 +48,12 @@ If you've already got your [environment set up](environment-setup) to build mobi Studio, you can build and run your app locally: ```bash -# Install NativePHP for Mobile into a new Laravel app -composer require nativephp/mobile +# Install NativePHP for Mobile and its UI components into a new Laravel app +composer require nativephp/mobile nativephp/mobile-ui + +# Register the UI plugin so its native code is compiled in +php artisan vendor:publish --tag=nativephp-plugins-provider +php artisan native:plugin:register nativephp/mobile-ui # Ready your app to go native php artisan native:install diff --git a/resources/views/docs/mobile/4/testing/interactions.md b/resources/views/docs/mobile/4/testing/interactions.md index 179ec49f5..c20423c6a 100644 --- a/resources/views/docs/mobile/4/testing/interactions.md +++ b/resources/views/docs/mobile/4/testing/interactions.md @@ -35,7 +35,7 @@ element a `ref` and target it by name. A `ref` works in Blade on any element: Tap to vibrate - + ``` @endverbatim @@ -83,7 +83,7 @@ Each control fires the same event its native counterpart emits: - `changeTab($target, $index)` — switch a tab row to an index. - `dismissSheet($target)` — dismiss a bottom sheet. -Fields bound with `wire:model` sync their property as you'd expect: +Fields bound with `native:model` sync their property as you'd expect: ```php it('fills and submits the toast form', function () { @@ -95,6 +95,28 @@ it('fills and submits the toast form', function () { }); ``` +### List rows + +A [list item](../edge-components/list#list-item)'s checkbox, radio and swipe-to-delete callbacks are best targeted by +the expression you bound, since each row in a loop has its own: + +@verbatim +```blade static + +``` +@endverbatim + +```php +Native::test(Tasks::class) + ->check('toggleTask(1)') // calls toggleTask(1, true) + ->press('deleteTask(1)'); // swipe-to-delete arrives as a press +``` + ## Setting properties and calling methods Two lower-level tools reach the component directly. diff --git a/resources/views/docs/mobile/4/testing/introduction.md b/resources/views/docs/mobile/4/testing/introduction.md index 510da4d68..de72a8743 100644 --- a/resources/views/docs/mobile/4/testing/introduction.md +++ b/resources/views/docs/mobile/4/testing/introduction.md @@ -17,6 +17,24 @@ component's state. Rendering fidelity — how SwiftUI or Compose actually paints those elements on screen — is out of scope by design. The suite asserts on *what your component published*, exactly the layer you control from PHP. +## Setup + +The testing helpers ship with `nativephp/mobile`, in the `Native\Mobile\Testing` namespace. There's nothing extra to +install beyond your test runner. New Laravel apps ship with PHPUnit; to use Pest as these examples do: + +```shell +composer require pestphp/pest --dev --with-all-dependencies +./vendor/bin/pest --init +``` + +Tests boot your real application, so the plugins registered in `app/Providers/NativeServiceProvider.php` are what +the test renders against. If `nativephp/mobile-ui` isn't [registered](../getting-started/installation#install-the-ui-components), +a screen using `` or `` fails in the test with `Unknown native element type`, the +same as it would in the app. + +Put component tests in `tests/Feature` (which `pest --init` binds to your app's `TestCase`) and run them with +`php artisan test` or `./vendor/bin/pest`. + ## The `Native` entry point Every test starts from the `Native` facade. It has three entry points: diff --git a/resources/views/docs/mobile/4/the-basics/layouts.md b/resources/views/docs/mobile/4/the-basics/layouts.md index b3bb2a650..517dd4271 100644 --- a/resources/views/docs/mobile/4/the-basics/layouts.md +++ b/resources/views/docs/mobile/4/the-basics/layouts.md @@ -61,7 +61,7 @@ includes two reference layouts you can copy as a starting point: - `App\NativeComponents\Layouts\TabsLayout` - Title bar plus a 3-tab bottom nav. @verbatim -If you use the `nativephp/native-ui` plugin, its `native-ui-layouts` publish tag scaffolds a starter `` +If you use the `nativephp/mobile-ui` plugin, its `native-ui-layouts` publish tag scaffolds a starter `` Blade component that wraps a screen's content with safe-area handling and optional scrolling — copy it to `feed.blade.php`, `detail.blade.php`, and so on for multiple page archetypes. @endverbatim @@ -227,7 +227,7 @@ honors every tier everywhere. ## Drawer navigation -For a slide-out side drawer, mix the native-ui `HasLayoutDrawer` trait into your layout and return a `Drawer` from +For a slide-out side drawer, mix the mobile-ui `HasLayoutDrawer` trait into your layout and return a `Drawer` from `drawer()`. The content is any Blade view, so you build the drawer's UI with normal EDGE components: ```php @@ -342,7 +342,7 @@ the content too far. ## Floating overlay For a pill or banner that **floats over** every screen — a "servers nearby" chip, a now-playing capsule, a -sync-status badge — mix the native-ui `HasFloatingOverlay` trait into your layout and return a `FloatingOverlay` +sync-status badge — mix the mobile-ui `HasFloatingOverlay` trait into your layout and return a `FloatingOverlay` from `floatingOverlay()`. Unlike `bottomBar()`, it does **not** inset the content: it hovers on a top layer above the content and the tab bar, so nothing is pushed up. Return `null` and nothing floats. diff --git a/resources/views/docs/mobile/4/the-basics/native-ui.md b/resources/views/docs/mobile/4/the-basics/native-ui.md index 3106959a5..4018dca62 100644 --- a/resources/views/docs/mobile/4/the-basics/native-ui.md +++ b/resources/views/docs/mobile/4/the-basics/native-ui.md @@ -38,6 +38,14 @@ runtime without recompiling your app. Browse the full catalogue in the [EDGE Components](../edge-components/introduction) section. + + ## Structuring your app Once you're comfortable with the component syntax, two concepts organize your screens into an app: From 1044c9807acb808b02efdebc928022e2fb0e01c2 Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Sun, 27 Sep 2026 18:48:02 +0100 Subject: [PATCH 2/6] Point the starter kit at current mobile-ui and note DEBUG versioning for shared builds Co-Authored-By: Claude Opus 5.5 (1M context) --- .../docs/mobile/4/edge-components/text-input.md | 4 ++-- .../docs/mobile/4/getting-started/development.md | 3 +++ .../docs/mobile/4/getting-started/quick-start.md | 13 +++++++++++++ 3 files changed, 18 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 09524ac8b..eab069aa8 100644 --- a/resources/views/docs/mobile/4/edge-components/text-input.md +++ b/resources/views/docs/mobile/4/edge-components/text-input.md @@ -207,8 +207,8 @@ A short window like 150ms still feels live to the user. Reach for: - `native:model.blur` for form fields you only read when the form is submitted - plain `native:model` only when you need every character, such as a character counter, and the field is short -Debounced and blurred fields always sync immediately on submit and on focus loss, so `@submit="add"` sees the full -text. +Debounced and blurred fields flush any pending change on submit and on focus loss, before `@submit` fires. The +`@submit` handler also receives the field's text as its last argument, so `@submit="add"` calls `add($text)`. ## Caret and selection reporting diff --git a/resources/views/docs/mobile/4/getting-started/development.md b/resources/views/docs/mobile/4/getting-started/development.md index 261a79c5e..16ab8a0b3 100644 --- a/resources/views/docs/mobile/4/getting-started/development.md +++ b/resources/views/docs/mobile/4/getting-started/development.md @@ -127,6 +127,9 @@ A few things to know: the `.apk` on any emulator or device with `adb install -r path/to/app-debug.apk`. - `--build=profileable` on Android writes `apk/profileable/app-profileable.apk` instead. - The `nativephp` directory is rebuilt by `native:install --force`, so copy anything you want to keep somewhere else. +- Keep `NATIVEPHP_APP_VERSION=DEBUG` in `.env` for these builds. A `DEBUG` build re-extracts your Laravel app every + time it launches. With a fixed version such as `1.0.0`, an app that is already installed only re-extracts when the + version or build number changes, so installing a fresh build over an old one can keep showing the old screens. - These are development builds. For signed release builds (`.ipa`, release `.apk` or `.aab`), use [`native:package`](commands#nativepackage) or [Bifrost](../publishing/bifrost). diff --git a/resources/views/docs/mobile/4/getting-started/quick-start.md b/resources/views/docs/mobile/4/getting-started/quick-start.md index 938725834..516e37371 100644 --- a/resources/views/docs/mobile/4/getting-started/quick-start.md +++ b/resources/views/docs/mobile/4/getting-started/quick-start.md @@ -20,9 +20,22 @@ laravel new my-app --using=nativephp/mobile-starter --no-node cd my-app +composer require nativephp/mobile-ui:^0.6 + php artisan native:jump ``` +The starter kit already registers `nativephp/mobile-ui`, but it pins an older 0.3 release, so the `composer require` +line brings it up to date with these docs. + + + ### Existing Laravel app If you already have a Laravel app: From 5c85b57f3b8779cbe283c9a16bfd9d0aaccdd11d Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Sun, 27 Sep 2026 18:57:00 +0100 Subject: [PATCH 3/6] Document on-trailing-press and headline-line-through as post-0.6.0 list item attributes Co-Authored-By: Claude Opus 5.5 (1M context) --- .../mobile/4/digging-deeper/accessibility.md | 5 ++++ .../docs/mobile/4/edge-components/list.md | 24 ++++++++++++------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/resources/views/docs/mobile/4/digging-deeper/accessibility.md b/resources/views/docs/mobile/4/digging-deeper/accessibility.md index 6b84270b4..3c13e78a4 100644 --- a/resources/views/docs/mobile/4/digging-deeper/accessibility.md +++ b/resources/views/docs/mobile/4/digging-deeper/accessibility.md @@ -87,10 +87,15 @@ The tappable trailing icon button on a [list item](../edge-components/list) take headline="Backups" trailingIconButton="info" trailing-a11y-label="Backup details" + on-trailing-press="showBackupInfo" /> ``` @endverbatim +`on-trailing-press` needs the `nativephp/mobile-ui` release that includes +[NativePHP/mobile-ui#108](https://github.com/NativePHP/mobile-ui/pull/108). On 0.6.0, use the fluent +`->onTrailingPress()` instead. See [List › Events](../edge-components/list#events). + List rows group their content (headline, supporting text, leading and trailing decorations) into a single screen-reader focus stop; interactive trailing controls remain individually focusable. diff --git a/resources/views/docs/mobile/4/edge-components/list.md b/resources/views/docs/mobile/4/edge-components/list.md index e3d7333dd..b849dd106 100644 --- a/resources/views/docs/mobile/4/edge-components/list.md +++ b/resources/views/docs/mobile/4/edge-components/list.md @@ -53,8 +53,9 @@ content slots. `` takes its content, slot, color and elevation attributes in camelCase (`leadingIcon`, `trailingText`, `leadingCheckbox`, `headlineColor`). The kebab-case spellings (`leading-icon`, `leading-checkbox`) are silently ignored. Callback and array attributes are the exception and use kebab-case: `on-leading-change`, -`on-trailing-change`, `on-swipe-delete`, `leading-actions`, `trailing-actions`, `trailing-badges`, `trailing-menu` and -`trailing-a11y-label`. Everything below is listed with the spelling that works. +`on-trailing-change`, `on-trailing-press`, `on-swipe-delete`, `leading-actions`, `trailing-actions`, +`trailing-badges`, `trailing-menu`, `trailing-a11y-label` and `headline-line-through`. Everything below is listed with +the spelling that works. Bind boolean slots with `:` so a false value stays false: `:leadingCheckbox="$task->done"`. A literal `leadingCheckbox="false"` is a non-empty string and renders a checked box. @@ -78,6 +79,9 @@ Bind boolean slots with `:` so a false value stays false: `:leadingCheckbox="$ta - `headline` - Primary text (required, string) - `supporting` - Secondary text rendered below the headline (optional, string) - `overline` - Small caption rendered above the headline (optional, string) +- `headline-line-through` - Strike through the headline, e.g. for a completed todo (optional, boolean, default: + `false`). Bind it: `:headline-line-through="$todo->done"`. Not in `nativephp/mobile-ui` 0.6.0; it needs the + release that includes [NativePHP/mobile-ui#109](https://github.com/NativePHP/mobile-ui/pull/109) ### Leading slot (mutually exclusive) @@ -101,10 +105,8 @@ Bind boolean slots with `:` so a false value stays false: `:leadingCheckbox="$ta - `trailingCheckbox` - Boolean value for a trailing checkbox. Interactive when `on-trailing-change` is set; static glyph otherwise - `trailingSwitch` - Boolean value for a trailing switch [Android] -- `trailingIconButton` - Icon name for a trailing icon button. In `nativephp/mobile-ui` 0.6.0 there is no Blade - attribute that wires a handler to this button (`on-trailing-press` and `@trailing-press` are ignored), so from - Blade it renders but does nothing when tapped. Wire it with the fluent `->onTrailingPress()` on a `ListItem` - element, or attach a `trailing-menu` instead +- `trailingIconButton` - Icon name for a tappable trailing button. Handle taps with `on-trailing-press` (see + [Events](#events)) - `trailing-a11y-label` - Accessibility label for the trailing icon button (recommended whenever `trailingIconButton` is set). See [Accessibility](../digging-deeper/accessibility) - `trailing-menu` - Attach a tap-to-open dropdown to the row's trailing edge (`trailingMenu` also works). When set without an explicit trailing @@ -144,9 +146,13 @@ All color props accept the full [color grammar](../digging-deeper/theming#color- - `on-leading-change` / `on-trailing-change` - Component method called when the leading/trailing checkbox or radio is toggled, receiving the new value. Without a handler the control renders as a static state glyph. -The fluent `onTrailingPress()` fires on both platforms when the trailing icon button is tapped. It has no Blade -attribute in `nativephp/mobile-ui` 0.6.0; see `trailingIconButton` above. The trailing switch is interactive on -[Android] only. +- `on-trailing-press` - Component method called when the trailing icon button is tapped, on both platforms. This + attribute needs the `nativephp/mobile-ui` release that includes + [NativePHP/mobile-ui#108](https://github.com/NativePHP/mobile-ui/pull/108). In 0.6.0 it is silently ignored and + only the fluent `->onTrailingPress()` on a `ListItem` element works. `@trailing-press` never works: unknown `@name` + attributes are treated as child-component events and dropped from plain elements + +The trailing switch is interactive on [Android] only. Handlers receive their arguments in this order: the arguments you wrote in the expression, then the value the control sends. So `on-leading-change="toggleTask(@{{ $task->id }})"` calls `toggleTask($id, $checked)`: From e7073e7e7c20a02bf6081ae919a2370ba457b5d0 Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Sun, 27 Sep 2026 20:35:01 +0100 Subject: [PATCH 4/6] Lead with laravel new --using for the starter kit Co-Authored-By: Claude Opus 5.5 (1M context) --- .../mobile/4/getting-started/installation.md | 16 ++++++++++++++++ .../docs/mobile/4/getting-started/quick-start.md | 11 +++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/resources/views/docs/mobile/4/getting-started/installation.md b/resources/views/docs/mobile/4/getting-started/installation.md index b4d2627ea..fc05fa004 100644 --- a/resources/views/docs/mobile/4/getting-started/installation.md +++ b/resources/views/docs/mobile/4/getting-started/installation.md @@ -3,6 +3,22 @@ title: Installation order: 100 --- +## Start from the starter kit + +The quickest way to a working v4 app is the starter kit, which comes with NativePHP and its UI components already +installed and registered: + +```shell +laravel new my-app --using=nativephp/mobile-starter --no-node +cd my-app +composer require nativephp/mobile-ui:^0.6 +``` + +The starter kit currently pins an older `nativephp/mobile-ui` release, so the last line updates it. It won't be needed +once the starter kit moves to 0.6. Then skip ahead to [Run the NativePHP installer](#run-the-nativephp-installer). + +To add NativePHP to an existing Laravel app instead, follow the next two sections. + ## Install the Composer package NativePHP contains all the libraries, classes, commands, and interfaces that your application will need to work with diff --git a/resources/views/docs/mobile/4/getting-started/quick-start.md b/resources/views/docs/mobile/4/getting-started/quick-start.md index 516e37371..4d8221d90 100644 --- a/resources/views/docs/mobile/4/getting-started/quick-start.md +++ b/resources/views/docs/mobile/4/getting-started/quick-start.md @@ -13,7 +13,7 @@ Don't waste hours downloading, installing, and configuring Xcode and Android Stu ### New Laravel app -If you are creating new Laravel app, you can build using our starter kit: +The recommended way to start is our starter kit: ```bash laravel new my-app --using=nativephp/mobile-starter --no-node @@ -25,14 +25,13 @@ composer require nativephp/mobile-ui:^0.6 php artisan native:jump ``` -The starter kit already registers `nativephp/mobile-ui`, but it pins an older 0.3 release, so the `composer require` -line brings it up to date with these docs. +The starter kit already installs and registers `nativephp/mobile-ui`, but it currently pins an older 0.3 release. The +`composer require` line brings it up to date with these docs, and won't be needed once the starter kit moves to 0.6. From 103e8a305826a6ddaa3af7b40f016affdc1d3d21 Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Wed, 30 Sep 2026 12:15:12 +0100 Subject: [PATCH 5/6] Explain --no-node and Boost in the starter kit steps Co-Authored-By: Claude Opus 5.5 (1M context) --- resources/views/docs/mobile/4/getting-started/installation.md | 4 ++++ resources/views/docs/mobile/4/getting-started/quick-start.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/resources/views/docs/mobile/4/getting-started/installation.md b/resources/views/docs/mobile/4/getting-started/installation.md index fc05fa004..bfb3164c7 100644 --- a/resources/views/docs/mobile/4/getting-started/installation.md +++ b/resources/views/docs/mobile/4/getting-started/installation.md @@ -14,6 +14,10 @@ cd my-app composer require nativephp/mobile-ui:^0.6 ``` +`--no-node` skips the `npm install && npm run build` the installer runs by default, which a SuperNative app doesn't +need. `laravel new` also installs [Laravel Boost](https://laravel.com/ai/boost), which sets up AI agent guidelines for +the project; pass `--no-boost` to skip it. + The starter kit currently pins an older `nativephp/mobile-ui` release, so the last line updates it. It won't be needed once the starter kit moves to 0.6. Then skip ahead to [Run the NativePHP installer](#run-the-nativephp-installer). diff --git a/resources/views/docs/mobile/4/getting-started/quick-start.md b/resources/views/docs/mobile/4/getting-started/quick-start.md index 4d8221d90..7f60dcd2d 100644 --- a/resources/views/docs/mobile/4/getting-started/quick-start.md +++ b/resources/views/docs/mobile/4/getting-started/quick-start.md @@ -25,6 +25,10 @@ composer require nativephp/mobile-ui:^0.6 php artisan native:jump ``` +`--no-node` skips the `npm install && npm run build` the installer runs by default, which a SuperNative app doesn't +need. `laravel new` also installs [Laravel Boost](https://laravel.com/ai/boost), which sets up AI agent guidelines for +the project; pass `--no-boost` to skip it. + The starter kit already installs and registers `nativephp/mobile-ui`, but it currently pins an older 0.3 release. The `composer require` line brings it up to date with these docs, and won't be needed once the starter kit moves to 0.6. From 90e4c1dda0f2e2137d8efd92506b6d938bf7255a Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Wed, 30 Sep 2026 13:04:13 +0100 Subject: [PATCH 6/6] Drop the mobile-ui bump now the starter kit requires ^0.6 Co-Authored-By: Claude Opus 5.5 (1M context) --- .../views/docs/mobile/4/getting-started/installation.md | 4 +--- resources/views/docs/mobile/4/getting-started/quick-start.md | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/resources/views/docs/mobile/4/getting-started/installation.md b/resources/views/docs/mobile/4/getting-started/installation.md index bfb3164c7..097a81c6b 100644 --- a/resources/views/docs/mobile/4/getting-started/installation.md +++ b/resources/views/docs/mobile/4/getting-started/installation.md @@ -11,15 +11,13 @@ installed and registered: ```shell laravel new my-app --using=nativephp/mobile-starter --no-node cd my-app -composer require nativephp/mobile-ui:^0.6 ``` `--no-node` skips the `npm install && npm run build` the installer runs by default, which a SuperNative app doesn't need. `laravel new` also installs [Laravel Boost](https://laravel.com/ai/boost), which sets up AI agent guidelines for the project; pass `--no-boost` to skip it. -The starter kit currently pins an older `nativephp/mobile-ui` release, so the last line updates it. It won't be needed -once the starter kit moves to 0.6. Then skip ahead to [Run the NativePHP installer](#run-the-nativephp-installer). +Then skip ahead to [Run the NativePHP installer](#run-the-nativephp-installer). To add NativePHP to an existing Laravel app instead, follow the next two sections. diff --git a/resources/views/docs/mobile/4/getting-started/quick-start.md b/resources/views/docs/mobile/4/getting-started/quick-start.md index 7f60dcd2d..81a8bd84a 100644 --- a/resources/views/docs/mobile/4/getting-started/quick-start.md +++ b/resources/views/docs/mobile/4/getting-started/quick-start.md @@ -20,8 +20,6 @@ laravel new my-app --using=nativephp/mobile-starter --no-node cd my-app -composer require nativephp/mobile-ui:^0.6 - php artisan native:jump ``` @@ -29,8 +27,7 @@ php artisan native:jump need. `laravel new` also installs [Laravel Boost](https://laravel.com/ai/boost), which sets up AI agent guidelines for the project; pass `--no-boost` to skip it. -The starter kit already installs and registers `nativephp/mobile-ui`, but it currently pins an older 0.3 release. The -`composer require` line brings it up to date with these docs, and won't be needed once the starter kit moves to 0.6. +The starter kit already installs and registers `nativephp/mobile-ui`.