spatie / menu

Html menu generator

Home Page:https://freek.dev/414-a-modern-package-to-generate-html-menus

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ItemClass from parent menu cascades into submenu wrapper

bluec opened this issue · comments

Not easy to explain but it seems the addItemClass() from a menu gets applied to the container of the submenu.

An example is worth a thousand words... example Bootstrap 4 styled menu and submenu:

Menu::new()
    ->addClass('nav')
    ->addItemParentClass('nav-item')
    ->addItemClass('nav-link')

    ->link('#', 'Main Menu Link 1')
    ->link('#', 'Main Menu Link 2')
    ->submenu(
        Link::to('#', 'Sub Menu')
            ->addClass('nav-link nav-dropdown-toggle')
        ,
        Menu::new()
            ->addClass('nav-dropdown-items') // this has nav-link class from parent menu but it shouldn't
            ->addParentClass('nav-dropdown')
            ->addItemParentClass('nav-item')
            ->addItemClass('nav-link')
            ->link('#', 'Sub Menu Item 1')
            ->link('#', 'Sub Menu Item 2')
    );

This HTML is generated:

<ul class="nav">
    <li class="nav-item"><a href="#" class="nav-link">Main Menu Link 1</a></li>
    <li class="nav-item"><a href="#" class="nav-link">Main Menu Link 2</a></li>
    <li class="nav-dropdown nav-item"><a href="#" class="nav-link nav-dropdown-toggle">Sub Menu</a>
        <ul class="nav-dropdown-items nav-link">
            <li class="nav-item"><a href="#" class="nav-link">Sub Menu Item 1</a></li>
            <li class="nav-item"><a href="#" class="nav-link">Sub Menu Item 2</a></li>
        </ul>
    </li>
</ul>

This is what should be generated:

<ul class="nav">
    <li class="nav-item"><a href="#" class="nav-link">Main Menu Link 1</a></li>
    <li class="nav-item"><a href="#" class="nav-link">Main Menu Link 2</a></li>
    <li class="nav-dropdown nav-item"><a href="#" class="nav-link nav-dropdown-toggle">Sub Menu</a>
        <ul class="nav-dropdown-items">
            <li class="nav-item"><a href="#" class="nav-link">Sub Menu Item 1</a></li>
            <li class="nav-item"><a href="#" class="nav-link">Sub Menu Item 2</a></li>
        </ul>
    </li>
</ul>

I had the exact same issue as @bluec so I submitted a pull request to fix what I could see as being the problem and wrote a test to capture the use case above.

If for any reason @sebastiandedeyne decides not to merge in that pull request, I found a way around this by creating a class that inherits from the \Spatie\Menu\Menu:

<?php

namespace App\Http\Menus\Menu;

class MenuExtended extends \Spatie\Menu\Menu
{
    /**
     * Add a class to all items in the menu.
     *
     * @param string $class
     *
     * @return $this
     */
    public function addItemClass(string $class)
    {
        $this->applyToAll(function (\Spatie\Menu\Link $link) use ($class) {
            $link->addClass($class);
        });

        return $this;
    }
}

Or, if you are using the Laravel Menu package \Spatie\Menu\Laravel\Menu:

<?php

namespace App\Http\Menus\Menu;

class MenuExtended extends \Spatie\Menu\Laravel\Menu
{
    /**
     * Add a class to all items in the menu.
     *
     * @param string $class
     *
     * @return $this
     */
    public function addItemClass(string $class)
    {
        $this->applyToAll(function (\Spatie\Menu\Link $link) use ($class) {
            $link->addClass($class);
        });

        return $this;
    }
}

Since the Menu::new(), Menu::build() and Menu::blueprint() methods use late static binding, subsequent calls to build menus will use the overriding class above instead of the package classes.

Gonna close this, being handled in #88.

I am having the exact same issues. Sad to see, that the correcting PRs never got merged :(