diff --git a/CHANGELOG.md b/CHANGELOG.md
index 55132de..3bbc3f7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,8 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+### Added
+
+- The views also answer to the canonical `laranail/confetti` namespace
+ (`view('laranail/confetti::components.scripts')`), registered by
+ package-tools over the same paths as `laranail-confetti`, published overrides
+ included. A naming test asserts both forms against the live view finder.
+
### Changed
+- The package renders through `laranail/confetti::` (`ConfettiTags::VIEW`).
+ `laranail-confetti::` still resolves the same files.
+- Requires `laranail/package-tools ^0.1.3`, the first release that registers
+ both namespace forms.
- `laranail::confetti.install` now extends laranail/package-tools'
`InstallCommand` and takes laranail/console's display API and run lifecycle
from its `InteractsWithConsoleServices` and `InteractsWithConsoleWriter`
diff --git a/composer.json b/composer.json
index a4c27de..660ee9a 100644
--- a/composer.json
+++ b/composer.json
@@ -45,7 +45,7 @@
"illuminate/view": "^13.0",
"laranail/console": "^0.1",
"laranail/enumerator": "^0.1",
- "laranail/package-tools": "^0.1"
+ "laranail/package-tools": "^0.1.3"
},
"require-dev": {
"filament/filament": "^4.0 || ^5.0",
diff --git a/docs/architecture.md b/docs/architecture.md
index 4bb155d..56b2f81 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -196,11 +196,17 @@ Everything this package registers is prefixed, and none of it is called just
| Surface | Name | Used as |
|---|---|---|
| Blade component | `laranail-confetti` | `` |
-| View namespace | `laranail-confetti` | `view('laranail-confetti::components.scripts')` |
+| View namespace | `laranail/confetti` (canonical), `laranail-confetti` (alias) | `view('laranail/confetti::components.scripts')` |
| Route middleware | `laranail-confetti` | `->middleware('laranail-confetti')` |
| Artisan commands | `laranail::confetti.` | `php artisan laranail::confetti.doctor` |
| Alpine component | `laranailConfetti` | `
` |
+The view namespace answers to both spellings over the same paths. `laranail/confetti`
+is canonical, because it is the composer package name, and the package renders
+through it. `laranail-confetti` is kept, not deprecated: it is the spelling a
+Blade tag needs, and overrides published to
+`resources/views/vendor/laranail-confetti` keep winning under either name.
+
Laravel keeps view namespaces, component prefixes and middleware aliases in flat
maps keyed by that name. Two packages claiming the same key do not collide
loudly; the second silently replaces the first, and it surfaces much later as a
diff --git a/src/Providers/ConfettiServiceProvider.php b/src/Providers/ConfettiServiceProvider.php
index dac0044..995a685 100644
--- a/src/Providers/ConfettiServiceProvider.php
+++ b/src/Providers/ConfettiServiceProvider.php
@@ -42,6 +42,10 @@ public function configurePackage(Package $package): void
$package
->name('laranail/confetti')
->hasConfigFile()
+ // Declared under the hyphen form so overrides already published to
+ // resources/views/vendor/laranail-confetti keep winning; package-tools
+ // registers the canonical `laranail/confetti` namespace over the same
+ // paths, and the package renders through that one.
->hasViews('laranail-confetti')
->hasAssets()
->hasBladeComponentNamespace(
diff --git a/src/View/ConfettiTags.php b/src/View/ConfettiTags.php
index 531ed8c..0dede80 100644
--- a/src/View/ConfettiTags.php
+++ b/src/View/ConfettiTags.php
@@ -20,7 +20,11 @@
*/
final readonly class ConfettiTags
{
- public const string VIEW = 'laranail-confetti::components.scripts';
+ /**
+ * The view, under the canonical `laranail/confetti` namespace. The `laranail-confetti` namespace
+ * still resolves the same file, including an override published under it.
+ */
+ public const string VIEW = 'laranail/confetti::components.scripts';
public function __construct(
private ConfettiConfig $config,
diff --git a/tests/Feature/FilamentPluginTest.php b/tests/Feature/FilamentPluginTest.php
index ebab72d..a4f2794 100644
--- a/tests/Feature/FilamentPluginTest.php
+++ b/tests/Feature/FilamentPluginTest.php
@@ -76,7 +76,7 @@ function renderPanelHook(Panel $panel, string $hook): string
ConfettiPlugin::make()->register($panel);
- $expected = view('laranail-confetti::components.scripts', [
+ $expected = view('laranail/confetti::components.scripts', [
'enabled' => true,
'bootJson' => app(BootConfig::class)->toJson(),
'scriptTag' => app(ScriptTagBuilder::class)->render(),
diff --git a/tests/Feature/InjectionTest.php b/tests/Feature/InjectionTest.php
index 5b04099..50fcaaa 100644
--- a/tests/Feature/InjectionTest.php
+++ b/tests/Feature/InjectionTest.php
@@ -19,7 +19,7 @@
// A page that already carries the component.
Route::get('/explicit', fn (): string => ''
- . view('laranail-confetti::components.scripts', [
+ . view('laranail/confetti::components.scripts', [
'enabled' => true,
'bootJson' => app(BootConfig::class)->toJson(),
'scriptTag' => app(ScriptTagBuilder::class)->render(),
diff --git a/tests/Feature/NamingConventionTest.php b/tests/Feature/NamingConventionTest.php
index 62aacf1..c533991 100644
--- a/tests/Feature/NamingConventionTest.php
+++ b/tests/Feature/NamingConventionTest.php
@@ -4,6 +4,11 @@
use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Blade;
+use Simtabi\Laranail\Confetti\View\ConfettiTags;
+use Simtabi\Laranail\Package\Tools\Testing\NamingScope;
+use Simtabi\Laranail\Package\Tools\Testing\AssertsRegisteredNames;
+
+uses(AssertsRegisteredNames::class);
/**
* Every public name this package claims is prefixed with the org and the slug.
@@ -29,6 +34,22 @@
expect($hints)->not->toHaveKey('confetti');
});
+it('registers both view namespace forms over the same paths, and renders through the canonical one', function (): void {
+ // basePath is resources/: package-tools v0.1.3 defaults ownership to the
+ // package root, which also claims vendor/ and tests/ registrations (fixed in v0.1.4).
+ $scope = NamingScope::for('laranail/confetti', 'Simtabi\\Laranail\\Confetti\\', basePath: dirname(__DIR__, 2) . '/resources');
+
+ expect($this->assertViewNamespacesScoped($scope, atLeast: 2))
+ ->toContain('laranail/confetti', PREFIX);
+
+ $hints = View::getFinder()->getHints();
+
+ expect($hints['laranail/confetti'])->toBe($hints[PREFIX]);
+ expect(ConfettiTags::VIEW)->toStartWith('laranail/confetti::');
+ expect(view('laranail-confetti::components.scripts')->getPath())
+ ->toBe(view(ConfettiTags::VIEW)->getPath());
+});
+
it('registers its Blade components under the org-scoped prefix', function (): void {
$namespaces = new ReflectionProperty(Blade::getFacadeRoot(), 'classComponentNamespaces')
->getValue(Blade::getFacadeRoot());
diff --git a/tests/Feature/SessionTransportTest.php b/tests/Feature/SessionTransportTest.php
index c19d102..9a46c92 100644
--- a/tests/Feature/SessionTransportTest.php
+++ b/tests/Feature/SessionTransportTest.php
@@ -75,7 +75,7 @@
return redirect('/page');
});
- Route::middleware('web')->get('/page', fn (): Factory|View => view('laranail-confetti::components.scripts', [
+ Route::middleware('web')->get('/page', fn (): Factory|View => view('laranail/confetti::components.scripts', [
'enabled' => true,
'bootJson' => app(BootConfig::class)->toJson(),
'scriptTag' => app(ScriptTagBuilder::class)->render(),