npm package: @morsedigital/vanilla-responsive-navigation
Description: Responsive navigation module written in vanilla JavaScript
Author: Ian Hatton
Latest version: 1.4.0

# vanilla-responsive-navigation

### Synopsis
A responsive navigation module written in vanilla JavaScript.

### Installation
```
npm install @morsedigital/vanilla-responsive-navigation
```

### Running tests
```
npm run test
```

### Example Instantiation
```javascript
const ResponsiveNavigationClass = require('@morsedigital/vanilla-responsive-navigation');

const primaryNavigation = new ResponsiveNavigationClass(
  'primary-navigation',
  {
    list_id: 'primary-navigation-list'
    , toggle_id: 'primary-navigation-toggle'
  }
);

if (primaryNavigation && primaryNavigation.hasOwnProperty('config')){
  primaryNavigation._init();
}
```

### Configuration
A new instance of ResponsiveNavigationClass can contain the following in its configuration object:
```javascript
new ResponsiveNavigationClass({
  dropdownClass: // String. Class for a list item which contains a child ul. Default is "dropdown-parent"
  , flyout: // Boolean. Determines whether or not a class is added to the body when the navigation is visible. If you have more than one navigation on the page, make sure you're not setting this to true everywhere. Default is false
  , list_id: // String. Id for the main ul in the navigation. Default is "responsive-navigation-list"
  , toggle_id: // String. Id for the main toggle. Default is "responsive-navigation-toggle"
  , toggle_mobile_id: // String. Id for the mobile toggle. This is only needed if flyout has been set to true. Default is null
});
```

### Example HTML structure (non-flyout)
```html
<nav class="primary-navigation" id="primary-navigation" role="navigation">
  <a href="#" id="primary-navigation-toggle" class="primary-navigation-toggle" aria-controls="navigation" aria-expanded="false" aria-hidden="true" aria-label="navigation menu" role="button">
    Toggle menu
  </a>
  <ul id="primary-navigation-list" class="primary-navigation-list">
    <li>
      <a href="/regular-link">Regular link</a>
    </li>
    <li class="dropdown-parent">
      <a href="#">Parent link</a>
      <ul>
        <li>
          <a href="/child-link-1">Child link 1</a>
        </li>
        <li>
          <a href="/child-link-2">Child link 2</a>
        </li>
      </ul>
    </li>
  </ul>
</nav>
```

### Example HTML structure (flyout)
```html
<nav class="primary-navigation" id="primary-navigation" role="navigation">
  <a href="#" id="primary-navigation-toggle" class="primary-navigation-toggle" aria-controls="navigation" aria-expanded="false" aria-hidden="true" aria-label="navigation menu" role="button">
    Toggle menu
  </a>
  <ul id="primary-navigation-list" class="primary-navigation-list">
    <li class="primary-navigation-header">
      <!-- This is the mobile toggle which is used to close the navigation when it's open -->
      <a href="#" id="primary-nav-toggle-mobile">
        Toggle menu (flyout)
      </a>
    </li>
    <li>
      <a href="/regular-link">Regular link</a>
    </li>
    <li class="dropdown-parent">
      <a href="#">Parent link</a>
      <ul>
        <li>
          <a href="/child-link-1">Child link 1</a>
        </li>
        <li>
          <a href="/child-link-2">Child link 2</a>
        </li>
      </ul>
    </li>
  </ul>
</nav>
```

### CSS
As a bare minimum, you'll require the following, or similar CSS:

#### (non-flyout)
```scss
.primary-nav-list {
  display: none;

  &.open {
    display: block;
  }
}
```

#### (Flyout)
##### Non-responsive
(base styles)
```scss
body {
  position: relative;
}
```

##### Responsive
(styles which are applied at different breakpoints)
```scss
@include breakpoint($mobile-breakpoint) {
  body {
    &.nav-open {
      .primary-nav-list {
        width: percentage(2/3);
      }
    }
  }

  .primary-nav-list {
    right: -(percentage(2/3));
    width: percentage(2/3);
  }
}

@include breakpoint($mobile-and-tablet-breakpoint) {
  body {
    &.nav-open {
      .primary-navigation-list {
        right: 0;
      }
    }
  }

  .primary-navigation-list {
    position: fixed;
    top: 0;
    @include transition(right 0.2s ease-in-out);

    li {
      float: left;
      width: 100%;
    }

    .dropdown {
      display: none;
    }

    .dropdown-parent {
      & > a {
        position: relative;

        &:after {
          content: "\25b6";
          position: absolute;
          top: 15px;
          right: 10px;
        }

        &.open {
          &:after {
            content: "\25bc";
          }
        }
      }
    }
  }

  .primary-navigation-toggle {
    display: block;
    float: right;
    position: relative;
    top: 10px;
  }
}

@include breakpoint($tablet-breakpoint) {
  body {
    &.nav-open {
      .primary-nav-list {
        width: percentage(1/2);
      }
    }
  }

  .primary-nav-list {
    right: -(percentage(1/2));
    width: percentage(1/2);
  }
}

@include breakpoint($desktop-breakpoint) {
  .primary-navigation-list {
    .dropdown {
      display: none;
      overflow: hidden;
      position: absolute;
      left: 0;
      top: 100%;

      li {
        clear: both;
        white-space: nowrap;
        width: 100%;
      }
    }

    .dropdown-parent {
      position: relative;

      &:hover {
        .dropdown {
          display: block !important; /* Needs !important to override JS */
        }
      }
    }
  }

  .primary-navigation-header, .primary-navigation-toggle {
    display: none;
  }
}
```