diff --git a/config/docs.php b/config/docs.php index fa3fabd0..c1e7695d 100644 --- a/config/docs.php +++ b/config/docs.php @@ -59,7 +59,7 @@ 1 => ['1.0', '1.1'], 2 => ['2.0'], 3 => ['3.0', '3.1', '3.2', '3.3'], - 4 => ['4.0', '4.1', '4.2', '4.3', '4.4', '4.5', '4.6'], + 4 => ['4.0', '4.1', '4.2', '4.3', '4.4', '4.5', '4.6', '4.7'], ], ], @@ -86,7 +86,7 @@ 'mobile-ui' => [ 'name' => 'nativephp/mobile-ui', 'baseline' => '0.3', - 'released_versions' => ['0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7'], + 'released_versions' => ['0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9'], ], ], diff --git a/resources/views/docs/mobile/4/edge-components/bottom-nav.md b/resources/views/docs/mobile/4/edge-components/bottom-nav.md index cee4c63e..da63f651 100644 --- a/resources/views/docs/mobile/4/edge-components/bottom-nav.md +++ b/resources/views/docs/mobile/4/edge-components/bottom-nav.md @@ -141,6 +141,9 @@ shorthand) override it per platform. Each override accepts a generated enum case ``` @endverbatim +[Custom icons](icon#custom-icons) work here too: put an SVG in `resources/icons` +and pass `custom:` as `icon` or as either override. + ### Search tab Mark one item with the boolean `search` attribute to make it present a native search field instead of navigating. diff --git a/resources/views/docs/mobile/4/edge-components/icon.md b/resources/views/docs/mobile/4/edge-components/icon.md index 0e45e309..61867102 100644 --- a/resources/views/docs/mobile/4/edge-components/icon.md +++ b/resources/views/docs/mobile/4/edge-components/icon.md @@ -8,7 +8,7 @@ order: 230 Displays a platform-native icon. On iOS, icons render as [SF Symbols](https://developer.apple.com/sf-symbols/); on Android, as [Material Icons](https://fonts.google.com/icons?icon.set=Material+Icons). You don't need to worry about the differences — use one consistent icon name and EDGE's smart mapping system translates it to the right platform -symbol automatically. +symbol automatically. When no system icon fits, you can ship [your own SVG icons](#custom-icons). @verbatim ```blade @@ -151,6 +151,8 @@ through a four-tier resolution strategy: This approach means you can use intuitive icon names for common cases, leverage direct platform icons for advanced use cases, and get consistent results across iOS and Android. +A name that starts with `custom:` points at one of your [custom icons](#custom-icons) instead. + ### iOS (SF Symbols) On iOS, icons render as SF Symbols. Manual mappings convert common icon names to their SF Symbol equivalents. @@ -219,6 +221,144 @@ For Blade components whose tag only takes a single `icon` string, pick the platf ``` @endverbatim +## Custom icons + + + +Ship your own icons as SVG files. When NativePHP builds your app, it turns each one into a native icon: a template image +in the iOS asset catalog, with its vector data kept, and a VectorDrawable on Android. + +Custom icons are tinted in one color, the same way system icons are. They take the color you give ``, and +a tab follows the bar's active and inactive colors. You can use them in tab bars, top-bar actions and their menus, +``, and the icon props of other EDGE components such as buttons and list items. + +Tab bars, top-bar actions and their menus need `nativephp/mobile` 4.7. `` and icons in other EDGE +components also need `nativephp/mobile-ui` 0.9. + +### Adding an icon + +Save each icon as `resources/icons/.svg`, directly in that folder rather than in a subfolder. The file name is the +icon's name. It must be lowercase kebab-case: letters, numbers and single hyphens, such as `git-commit-vertical`. A +`.svg` file with any other name fails the build. Files that aren't `.svg` are ignored. + +Here's `resources/icons/git-commit-vertical.svg`, downloaded from [Lucide](https://lucide.dev): + +```xml + + + + + +``` + + + +### Using an icon + +Pass `custom:` anywhere an icon name goes: + +@verbatim +```blade static + +``` +@endverbatim + +The same string works in any `icon` attribute, such as ``. + +In PHP, `Icon::custom()` builds that string for you. It throws an `InvalidArgumentException` if the name isn't +lowercase kebab-case: + +```php +use Native\Mobile\Edge\Layouts\Builders\NavAction; +use Native\Mobile\Edge\Layouts\Builders\Tab; +use Native\Mobile\Icon\Icon; + +// A tab in your layout's tabBar() +Tab::link('Log', '/log', Icon::custom('git-commit-vertical')); + +// A top-bar action, or an item in its menu +NavAction::make('star')->icon(Icon::custom('star'))->press('toggleStar'); +``` + +`Icon::custom('star')` returns the string `'custom:star'`, so you can pass the string itself if you prefer. This +`Icon` class shares its short name with the [`Icon` element](#element). If a file needs both, alias one of them: +`use Native\Mobile\Icon\Icon as CustomIcon;`. + +### Per-platform custom icons + +The `ios` and `android` overrides take custom icons too, so you can use your icon on one platform and keep the system +icon on the other: + +```php +use App\Icons\AndroidOutlined; +use Native\Mobile\Edge\Layouts\Builders\NavAction; +use Native\Mobile\Icon\Icon; + +// Your bell on iOS, the outlined Material bell on Android +NavAction::make('alerts')->icon(Icon::custom('bell'), android: AndroidOutlined::Notifications); + +// The system bell on Android, your bell on iOS +NavAction::make('alerts')->icon('bell', ios: Icon::custom('bell')); +``` + +In Blade, pass the string: + +@verbatim +```blade static + +``` +@endverbatim + +### Which SVGs work + +SVGs downloaded from Lucide, [Tabler](https://tabler.io/icons) and similar stroked sets, or from +[Material Symbols](https://fonts.google.com/icons), work as they are. NativePHP supports: + +- `path`, `circle`, `ellipse`, `line`, `rect` (including rounded corners), `polyline` and `polygon`, with or without + `g` groups around them +- Strokes as well as fills. Lucide's style of `stroke-width="2"`, round caps and joins, `fill="none"` and + `currentColor` is kept +- The presentation attributes `fill`, `stroke`, `stroke-width`, `stroke-linecap`, `stroke-linejoin`, + `stroke-miterlimit`, `fill-rule`, `opacity`, `fill-opacity` and `stroke-opacity`, set on the shape or inherited from + a parent `svg` or `g`. They also work inside a `style` attribute +- Any `viewBox`. Icons are scaled so their longer side is 24pt on iOS and 24dp on Android, so a 24×24 Lucide icon and + a 960×960 Material Symbols icon come out the same size. A file without a `viewBox` needs numeric `width` and `height` + +`title`, `desc`, comments and an empty `defs` are ignored. Because icons are tinted in one color, the color in the file +doesn't matter as long as there's only one: `currentColor`, `black` and any single hex or `rgb()` color all become the +tint. + +Anything else fails the build with an error that names the file, the element and the attribute. That includes: + +- `transform` attributes +- Gradients, patterns, masks, clip paths and filters +- `use`, `symbol` and `marker` elements, and anything inside `defs` +- `text`, `image` and `foreignObject` elements +- `