Skip to content

Add support for Bootstrap 4 #64

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Mar 2, 2018
Merged

Add support for Bootstrap 4 #64

merged 9 commits into from
Mar 2, 2018

Conversation

mrk-j
Copy link
Contributor

@mrk-j mrk-j commented Feb 16, 2018

When merged this PR adds support for Bootstrap 4.

We added 3 new methods for the Menu class:

  • setTagName enables using another element as an <ul>
  • setWrapLinksInList can disable automatic the wrapping of links in <li>'s
  • setActiveClassOnLink can set the activeClass on the link instead of the <li>

To set the active class on the link we assume that the item supplied to renderItem implements HasHtmlAttributes. I think it is pretty safe to do so, but to be safe we added a check to see if the item implements HasHtmlAttributes.

The syntax to render a Bootstrap 4 menu looks like this:

$submenu = Menu::new()
    ->setTagName('div')
    ->addClass('dropdown-menu')
    ->setWrapLinksInList(false)
    ->setActiveClassOnLink(true)
    ->add(Link::to('/about', 'About')->addParentClass('nav-item')->addClass('dropdown-item'));

Menu::new()
    ->addClass('navbar-nav')
    ->add(Link::to('/', 'Home')->addParentClass('nav-item')->addClass('nav-link'))
    ->submenu(Link::to('#', 'Dropdown link')->addClass('nav-link dropdown-toggle')->setAttribute('data-toggle', 'dropdown'), $submenu->addParentClass('nav-item dropdown'))
    ->setActive(function (Link $link) {
        return $link->url() === '/about';
    })->render();

m-bosch and others added 4 commits February 7, 2018 11:27
- Enable custom tag
- Added option to not wrap links in <li>
- Added option to set active class on link
@mrk-j mrk-j mentioned this pull request Feb 16, 2018
@sebastiandedeyne
Copy link
Member

Hi @mrk-j,

Big thanks for this PR! Looking good, but I have a few comments, could you go through these before I merge?

  • Rename setWrapLinksInList to wrapLinksInList
  • Add an opposite method for setActiveClassOnLink (setActiveClassOnParent)
  • The booleans params should all have a default, since every operation should have it's own method

Also, I'd greatly appreciate if if you could add these new methods to the docs. No sweat if you don't have any extra time for this.

@mrk-j
Copy link
Contributor Author

mrk-j commented Feb 26, 2018

Hey @sebastiandedeyne,

I made the changes as you requested, I set the defaults of both methods to true. I think this makes sense, at least for the setActiveClassOnLink method.

Let me know what you think. If the PR is merged I will update the docs accordingly.

@sebastiandedeyne sebastiandedeyne merged commit a1207e9 into spatie:master Mar 2, 2018
@sebastiandedeyne
Copy link
Member

Looks great, huge thanks for this! 🎉

sebastiandedeyne added a commit that referenced this pull request Mar 2, 2018
@sebastiandedeyne
Copy link
Member

I ended up making some more API changes to open up more rendering options. Check out the release notes for the details: https://github.com/spatie/menu/releases/tag/2.5.0

@mallardduck
Copy link

I've been working to set up this library with Bootstrap 4; however, I've had some difficulties. This PR and the initial message were great to get me started. Using that and the changelog referenced I got something that 90% works - except one small bug. I'm wondering if this issue has another solution or would require a new feature.

First I'll explain and show the issue I'm dealing with. Here is an updated equivalent to the OP snippet:

// Main Nav
Menu::macro('mainTest', function () {
    $subnavLinkText = Link::to('#', 'Dropdown Link')->addClass('nav-link dropdown-toggle')
                      ->setAttribute('data-toggle', 'dropdown')->setAttribute('id', 'testDropdown')
                      ->setAttribute('role', 'button')->setAttribute('aria-expanded', 'false');

    return Menu::new()
        ->addClass('navbar-nav mr-auto')
        ->addItemParentClass('nav-item')
        ->addItemClass('nav-link')
        ->route('home', 'Home')
        ->submenu(
          $subnavLinkText,
          Menu::subnav()
          )
        ->setActiveFromRequest();
});

// Places Sub-Nav
Menu::macro('subnav', function () {
    return Menu::new()
        ->setWrapperTag('div')
        ->addClass('dropdown-menu')
        ->withoutParentTag()
        ->setActiveClassOnLink()
        ->setAttribute('aria-labelledby', 'testDropdown')
        ->addItemClass('dropdown-item')
        ->add(Link::to('/about', 'About'))
        ->addParentClass('dropdown');
});

Menu::mainTest()->render();

So the subnav macro generates our div element with the simple anchor links within. It's inserted into the main nav at the same level as the label as expected. However since it's within a nav-item the library is also applying the nav-link class to the div. The default state should only have the dorpdown-menu class it had applied; having this extra class causes subnavs to be visible by default.

@mrk-j are you still using this library to generate BS4 based menus with dropdowns - if so, do you have the same issue or is there a work around you use?

@mallardduck
Copy link

I just realized that looking it over #78 maybe related to the issue I'm describing. If that's the case then the solutions should be the same.

@mrk-j
Copy link
Contributor Author

mrk-j commented Nov 23, 2018

We use the library like this:

$menuBuilder = MenuBuilder::new()->addClass('navbar-nav');

$submenu = MenuBuilder::new()
    ->addClass('dropdown-menu')
    ->setWrapperTag('div')
    ->withoutParentTag(false)
    ->setActiveClassOnLink()
    ->addParentClass('nav-item')
    ->addParentClass('dropdown')
    ->setAttributes(['aria-labelledby' => 'navbarDropdownMenuLink']);

$submenu->add(Link::to('/page', 'Item')->addClass('dropdown-item'));

$link = Link::to('/url', 'Dropdown')
    ->addClass('nav-link')
    ->addClass('dropdown-toggle')
    ->setAttribute('id', 'navbarDropdownMenuLink')
    ->setAttribute('role', 'button')
    ->setAttribute('data-toggle', 'dropdown')
    ->setAttribute('aria-haspopup', 'true')
    ->setAttribute('aria-expanded', 'false');

$menuBuilder->submenu($link, $submenu);

This results in:

<ul class="navbar-nav">
    <li class="nav-item dropdown">
        <a href="/url" id="navbarDropdownMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="nav-link dropdown-toggle">Dropdown</a>
        <div aria-labelledby="navbarDropdownMenuLink" class="dropdown-menu">
            <a href="/page" class="dropdown-item">Item</a>
        </div>
    </li>
</ul>

@mallardduck
Copy link

Ahh. @mrk-j I see thank you so much!

So instead of letting the 'main' menu appling the nav-item and nav-link the subnav's get them. Thank you again for the reply on this! I'm still having some issues, but it's gotten me much closer. This tactic works amazing for subnavs, however when I want the main nav to have items as well things get wonky.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants