Icons - v2.1.1
Extension API Documentation
This guide is designed for third-party package developers who want to integrate with ArtisanPack UI Icons and register their own icon sets programmatically. The Extension API allows packages to register icon sets via event hooks without requiring users to manually configure them.
Overview
The ArtisanPack UI Icons package provides a dual registration system:
- Config-based registration - Users configure icon sets in
config/artisanpack/icons.php - Event-driven registration - Packages register icon sets programmatically via filter hooks
The event-driven system is perfect for packages that want to bundle their own icon sets and register them automatically when installed.
The ap.icons.register-icon-sets Filter Hook
The primary extension point is the ap.icons.register-icon-sets filter hook. This hook allows packages to register icon sets that will be merged with user-configured sets.
Basic Usage
use ArtisanPackUI\Icons\Registries\IconSetRegistration;
// In your package's service provider boot() method
addFilter('ap.icons.register-icon-sets', function (IconSetRegistration $registry) {
$registry->addSet(__DIR__ . '/../../resources/icons', 'mypackage');
return $registry;
});
Hook Parameters
The filter hook receives an IconSetRegistration registry instance and must return it after adding your icon sets via the addSet() or addSets() methods.
IconSetRegistration Class
The IconSetRegistration class provides a structured way to define icon sets for event-driven registration.
Constructor
public function __construct(
public string $path,
public string $prefix,
public ?string $disk = null
)
Parameters
$path(string, required): Absolute path to the directory containing SVG files$prefix(string, required): Unique prefix for the icon set (e.g., 'mypackage', 'admin')$disk(string, optional): Laravel filesystem disk name (defaults to local filesystem)
Usage Examples
Basic Registration
use ArtisanPackUI\Icons\Registries\IconSetRegistration;
$iconSet = new IconSetRegistration(
path: __DIR__ . '/../resources/icons',
prefix: 'admin'
);
With Custom Disk
$iconSet = new IconSetRegistration(
path: 'icons/custom',
prefix: 'cloud',
disk: 's3'
);
Implementation Patterns
Single Icon Set Registration
For packages that provide one icon set:
<?php
namespace MyPackage\Providers;
use Illuminate\Support\ServiceProvider;
use ArtisanPackUI\Icons\Registries\IconSetRegistration;
class MyPackageServiceProvider extends ServiceProvider
{
public function boot()
{
// Register your package's icon set
addFilter('ap.icons.register-icon-sets', function ($sets) {
$sets[] = new IconSetRegistration(
path: __DIR__ . '/../../resources/icons',
prefix: 'mypackage'
);
return $sets;
});
}
}
Multiple Icon Sets Registration
For packages that provide multiple themed icon sets:
public function boot()
{
addFilter('ap.icons.register-icon-sets', function (IconSetRegistration $registry) {
// Register multiple themed icon sets
$iconSets = [
'admin' => __DIR__ . '/../../resources/icons/admin',
'user' => __DIR__ . '/../../resources/icons/user',
'sys' => __DIR__ . '/../../resources/icons/system',
];
foreach ($iconSets as $prefix => $path) {
$registry->addSet($path, $prefix);
}
return $registry;
});
}
Conditional Registration
Register icon sets based on configuration or environment:
public function boot()
{
addFilter('ap.icons.register-icon-sets', function ($sets) {
// Only register if the package is configured to provide icons
if (config('mypackage.provide_icons', true)) {
$sets[] = new IconSetRegistration(
path: __DIR__ . '/../../resources/icons',
prefix: 'mypackage'
);
}
// Register additional sets based on features
if (config('mypackage.admin_icons', false)) {
$sets[] = new IconSetRegistration(
path: __DIR__ . '/../../resources/icons/admin',
prefix: 'myadmin'
);
}
return $sets;
});
}
Dynamic Path Resolution
Handle different installation contexts:
public function boot()
{
addFilter('ap.icons.register-icon-sets', function ($sets) {
// Resolve path based on package installation location
$iconPath = $this->resolveIconPath();
if ($iconPath && is_dir($iconPath)) {
$sets[] = new IconSetRegistration(
path: $iconPath,
prefix: 'dynamic'
);
}
return $sets;
});
}
private function resolveIconPath(): ?string
{
// Try multiple possible locations
$possiblePaths = [
__DIR__ . '/../../resources/icons',
resource_path('vendor/mypackage/icons'),
storage_path('app/mypackage/icons'),
];
foreach ($possiblePaths as $path) {
if (is_dir($path)) {
return $path;
}
}
return null;
}
Advanced Usage
Validation and Error Handling
public function boot()
{
addFilter('ap.icons.register-icon-sets', function ($sets) {
try {
$iconPath = __DIR__ . '/../../resources/icons';
// Validate path exists and is readable
if (!is_dir($iconPath) || !is_readable($iconPath)) {
\Log::warning("MyPackage icons directory not found or not readable: {$iconPath}");
return $sets;
}
// Check for SVG files
$svgFiles = glob($iconPath . '/*.svg');
if (empty($svgFiles)) {
\Log::info("MyPackage icons directory contains no SVG files: {$iconPath}");
return $sets;
}
$sets[] = new IconSetRegistration(
path: $iconPath,
prefix: 'mypackage'
);
\Log::info("MyPackage registered " . count($svgFiles) . " icons with prefix 'mypackage'");
} catch (\Exception $e) {
\Log::error("Failed to register MyPackage icons: " . $e->getMessage());
}
return $sets;
});
}
Priority and Ordering
If registration order matters, you can use priority parameters:
// Register with high priority (early registration)
addFilter('ap.icons.register-icon-sets', function ($sets) {
// Critical system icons registered first
array_unshift($sets, new IconSetRegistration(
path: __DIR__ . '/../../resources/icons/critical',
prefix: 'critical'
));
return $sets;
}, 5); // Lower number = higher priority
// Register with normal priority
addFilter('ap.icons.register-icon-sets', function ($sets) {
$sets[] = new IconSetRegistration(
path: __DIR__ . '/../../resources/icons',
prefix: 'mypackage'
);
return $sets;
}, 10); // Default priority
Conflict Resolution
The system handles conflicts between different registration sources with the following precedence:
- Config-based registrations (highest priority)
- Event-driven registrations (by registration order)
Avoiding Conflicts
Choose Unique Prefixes
// Good - unique and descriptive
$sets[] = new IconSetRegistration(
path: __DIR__ . '/../../resources/icons',
prefix: 'mycompany-admin'
);
// Avoid - too generic
$sets[] = new IconSetRegistration(
path: __DIR__ . '/../../resources/icons',
prefix: 'admin' // Could conflict with other packages
);
Check for Existing Prefixes
addFilter('ap.icons.register-icon-sets', function ($sets) {
// Check if our preferred prefix is already in use
$existingPrefixes = array_column($sets, 'prefix');
$prefix = 'mypackage';
if (in_array($prefix, $existingPrefixes)) {
$prefix = 'mypackage-alt'; // Use fallback prefix
\Log::warning("MyPackage icon prefix conflict detected, using fallback: {$prefix}");
}
$sets[] = new IconSetRegistration(
path: __DIR__ . '/../../resources/icons',
prefix: $prefix
);
return $sets;
});
Package Publishing Best Practices
Directory Structure
Organize your package's icons for easy maintenance:
packages/mypackage/
├── resources/
│ └── icons/
│ ├── actions/
│ │ ├── save.svg
│ │ └── cancel.svg
│ ├── navigation/
│ │ ├── home.svg
│ │ └── back.svg
│ └── status/
│ ├── success.svg
│ └── error.svg
└── src/
└── MyPackageServiceProvider.php
Icon Naming Conventions
Follow consistent naming for better developer experience:
- Use kebab-case:
user-profile.svg,arrow-left.svg - Be descriptive:
trash-can.svginstead ofdelete.svg - Group logically:
nav-home.svg,nav-settings.svg
Documentation
Document your icon set in your package's README:
## Icons
This package automatically registers icon components with the `mypackage` prefix:
- `<x-icon-mypackage-save />` - Save action icon
- `<x-icon-mypackage-cancel />` - Cancel action icon
- `<x-icon-mypackage-home />` - Home navigation icon
### Disabling Icons
To disable automatic icon registration:
```php
// config/mypackage.php
return [
'provide_icons' => false,
];
Usage Examples
The complete usage examples with proper prefixes and styling classes are available in your package documentation.
Testing Extension Integration
Unit Tests
Test your icon registration logic:
<?php
namespace Tests\Unit;
use Tests\TestCase;
use ArtisanPackUI\Icons\Registries\IconSetRegistration;
class IconRegistrationTest extends TestCase
{
public function test_package_registers_icon_set()
{
// Simulate the filter hook
$sets = [];
$sets = apply_filters('ap.icons.register-icon-sets', $sets);
// Assert your package's icon set is registered
$prefixes = array_column($sets, 'prefix');
$this->assertContains('mypackage', $prefixes);
// Find your package's registration
$myPackageSet = collect($sets)->first(fn($set) => $set->prefix === 'mypackage');
$this->assertNotNull($myPackageSet);
$this->assertInstanceOf(IconSetRegistration::class, $myPackageSet);
}
public function test_icon_files_exist()
{
$iconPath = __DIR__ . '/../../resources/icons';
$this->assertDirectoryExists($iconPath);
$svgFiles = glob($iconPath . '/*.svg');
$this->assertNotEmpty($svgFiles, 'No SVG files found in icon directory');
}
}
Integration Tests
Test that icons render correctly:
public function test_package_icons_render_in_blade()
{
// Assuming you have a test icon file
$iconPath = __DIR__ . '/../../resources/icons/test.svg';
file_put_contents($iconPath, '<svg><circle r="10"/></svg>');
$view = $this->blade('<x-icon-mypackage-test />');
$this->assertStringContains('<svg', $view);
$this->assertStringContains('<circle r="10"/>', $view);
unlink($iconPath); // Cleanup
}
Troubleshooting for Extension Developers
Common Issues
Icons Not Appearing
- Check registration timing: Ensure your filter hook runs before the icons are processed
- Verify paths: Use absolute paths and ensure directories exist
- Check prefixes: Ensure your prefix doesn't conflict with existing ones
Performance Issues
- Lazy validation: Don't perform expensive operations in the filter hook
- Cache paths: Store resolved paths to avoid repeated filesystem checks
Memory Issues
- Don't load SVG content in the registration phase - let blade-ui-kit handle loading
- Use generators for large icon sets if needed
Debug Output
Add debugging to your registration:
addFilter('ap.icons.register-icon-sets', function ($sets) {
if (app()->environment('local')) {
\Log::debug('MyPackage registering icons', [
'path' => __DIR__ . '/../../resources/icons',
'prefix' => 'mypackage',
'existing_sets_count' => count($sets)
]);
}
$sets[] = new IconSetRegistration(
path: __DIR__ . '/../../resources/icons',
prefix: 'mypackage'
);
return $sets;
});
Next Steps
- Review Architecture Overview to understand the complete system
- Check Usage Examples for implementation patterns
- See Migration Guide for upgrading considerations
- Learn about Service Provider integration details