Permalink
Browse files

fix(dropdowns): Migration to popper.js positioning (#913)

* update dropdown.vue

* Update nav-item-dropdown.vue

* [dropdown.js mixin]: Incorporate popper.js

* Update README.md
  • Loading branch information...
tmorehouse committed Aug 23, 2017
1 parent 590cead commit 116cb3e19d52c636f0c3a9d38d887a72788a4a48
Showing with 260 additions and 103 deletions.
  1. +45 −21 docs/components/dropdown/README.md
  2. +15 −11 lib/components/dropdown.vue
  3. +20 −8 lib/components/nav-item-dropdown.vue
  4. +180 −63 lib/mixins/dropdown.js
@@ -3,8 +3,15 @@
> Dropdowns are toggleable, contextual overlays for displaying lists of links and actions
in a dropdown menu format.
**Beta Warning: Dropwdown is currently under re-development to align with Boostrap
V4.beta CSS and code changes. Positioning and placement are not yet working**
`<b-dropdown>` (or known by its shorter alias of `<b-dd>`) components are toggleable,
contextual overlays for displaying lists of links and more. They’re toggled by
clicking (or pressing space or enter when focused), not by hovering; this is an
[intentional design decision](http://markdotto.com/2012/02/27/bootstrap-explained-dropdowns/).
>**Note:** _Dropdowns are built on a third party library, [Popper.js](https://popper.js.org/),
which provides dynamic positioning and viewport detection. Dropdown requires
that the `popper.js` library to be loaded into your propject, or if using CDN
version of Bootstrap-Vue load popper **before** Bootstrap-Vue!_
**Example:** Various usage
@@ -52,6 +59,7 @@ V4.beta CSS and code changes. Positioning and placement are not yet working**
<b-dropdown id="ddown5" text="Dropdown using buttons as menu items" class="m-md-2">
<b-dropdown-item-button>I'm a button</b-dropdown-item-button>
<b-dropdown-item-button>I'm also a button</b-dropdown-item-button>
<b-dropdown-item-button disabled>I'm a button, but disabled!</b-dropdown-item-button>
<b-dropdown-item-button>I don't look like a button, but I am!</b-dropdown-item-button>
</b-dropdown>
@@ -60,14 +68,26 @@ V4.beta CSS and code changes. Positioning and placement are not yet working**
<!-- dropdown.vue -->
```
## Menu alignment
## Positioning
### Menu left and right alignment
The dropdown menu can either be left aligned (default) or right aligned with respect
to the button above it. To have the dropdown aligned on the right, set the `right` prop.
## Dropup
### Dropup
Turn your dropdown menu into a drop-up menu by setting the `dropup` prop.
### Auto "flipping"
By default, dropdowns may flip to the top, or to the bottom, based on
their current position in the viewport. To disable this auto-flip feature, set
the `no-flip` prop.
### Menu offset
Like to move your menu away from the toggle buttons a bit? Then use the `offset`
prop to specify the number of pixels to push away from the toggle button
- pased as a number, or specify the distance in CSS units (i.e. `0.3rem`,
`4px`, `1.2em`, etc) passed as a string.
## Split button support
Create a split dropdown button, where the left button provides standard
@@ -80,11 +100,12 @@ dropdown buttons.
Set the `size` prop to either `sm` for small button(s), or `lg` for large button(s).
Note chaging the size of the button(s) does not affect the size of the menu items.
>**Note:** _changing the size of the button(s) does not affect the size of the menu items!_
## Button contextual variants
The dropdown buttons can have one of the standard Boostrap contextual variants applied
by setting the prop `variant` to `success`, `info`, `danger`, `link` etc.
by setting the prop `variant` to `success`, `primary`, `info`, `danger`, `link` etc.
See [`<b-button>`](./button) for a list of supported contextual variants.
@@ -100,32 +121,35 @@ component or markup may break keyboard navigation.
| `<b-dropdown-header>` | A header item, used to help identify a group of dropdown items. | `<b-dd-header>`
| `<b-dropdown-divider>` | A divider / spacer which can be used to separate dropdown items. | `<b-dd-divider>`
_Note: Nested sub-menus are **not** supported._
>**Note:** _Nested sub-menus are **not** supported._
## Accessibility
Providing a unique `id` prop ensures ARIA compliance by automatically adding
the appropriate `aria-*` attributes in the rendered markup.
The default ARIA role is set to `menu`, but you can change this default to another role
(such as `navigation`) via the `role` prop, depending on your user case.
### Accessibility with Headers
When using `<b-dropdown-header>` components in the dropdown menu, it is reccomended to add an
`id` attribute to the header, and then set the `aria-describedby` attribite (set to the `id`
value of the associated header) on each following dropdown items associated with the header.
This will provide users of assitive technologies (i.e. sight-impared users) context about
the dropdown item:
When using `<b-dropdown-header>` components in the dropdown menu, it is recommended to add an
`id` attribute to the header, and then set the `aria-describedby` attribute (set to the `id`
value of the associated header) on each following dropdown items under that header.
This will provide users of assistive technologies (i.e. sight-impaired users) additional
context about the dropdown item:
```html
<template>
<div>
<b-dropdown id="ddown_hdrs" text="Dropdown Button sm" variant="primary" class="m-md-2">
<b-dropdown-header id="header1">Heading 1</b-dropdown-header>
<b-dropdown-item aria-describedby="header1">Action</b-dropdown-item>
<b-dropdown-item aria-describedby="header1">Another action</b-dropdown-item>
<b-dropdown-header id="header2">Heading 2</b-dropdown-header>
<b-dropdown-item aria-describedby="header2">Some Action</b-dropdown-item>
<b-dropdown-item aria-describedby="header2">Some other action</b-dropdown-item>
<b-dropdown-header id="header1">Groups</b-dropdown-header>
<b-dropdown-item aria-describedby="header1">Add</b-dropdown-item>
<b-dropdown-item aria-describedby="header1">Delete</b-dropdown-item>
<b-dropdown-header id="header2">Users</b-dropdown-header>
<b-dropdown-item aria-describedby="header2">Add</b-dropdown-item>
<b-dropdown-item aria-describedby="header2">Delete</b-dropdown-item>
<b-dropdown-divider></b-dropdown-divider>
<b-dropdown-item>Something else here...</b-dropdown-item>
<b-dropdown-item>Something <strong>not</strong> associated with user</b-dropdown-item>
<b-dropdown-item disabled>Disabled action</b-dropdown-item>
</b-dropdown>
</div>
@@ -138,7 +162,7 @@ Dropdowns support keyboard navigation, emulating native `<select>` behaviour.
| Keypress | Action
| -------- | ------
| <kbd>DOWN</kbd> | Will highlight the next lower non-disabled item in the menu.
| <kbd>UP</kbd> | Will highlight the next higher non-disbled item in the menu.
| <kbd>UP</kbd> | Will highlight the next higher non-disabled item in the menu.
| <kbd>ENTER</kbd> or <kbd>SPACE</kbd> | Will click the highlighted menu item.
| <kbd>ESC</kbd> | Will close the dropdown and return focus to the trigger button.
| <kbd>TAB</kbd> | Will close the dropdown and jump to the next focusable control on the page.
@@ -2,35 +2,35 @@
<div :id="safeId()" :class="dropdownClasses">
<b-button :id="safeId('_BV_button_')"
:class="{'dropdown-toggle': !split}"
v-if="split"
ref="button"
:aria-haspopup="split ? null : 'true'"
:aria-expanded="split ? null : (visible ? 'true' : 'false')"
:aria-haspopup="split ? 'true' : null"
:aria-expanded="split ? (visible ? 'true' : 'false') : null"
:variant="variant"
:size="size"
:disabled="disabled"
@click.stop.prevent="click"
>
<slot name="button-content"><slot name="text">{{text}}</slot></slot>
</b-button>
<b-button :id="safeId('_BV_toggle_')"
:class="['dropdown-toggle','dropdown-toggle-split']"
v-if="split"
:class="['dropdown-toggle',{'dropdown-toggle-split': split}]"
ref="toggle"
:aria-haspopup="split ? 'true' : null"
:aria-expanded="split ? (visible ? 'true' : 'false') : null"
:aria-haspopup="split ? null : 'true'"
:aria-expanded="split ? null : (visible ? 'true' : 'false')"
:variant="variant"
:size="size"
:disabled="disabled"
@click.stop.prevent="toggle"
>
<span class="sr-only">{{toggleText}}</span>
<span v-if="split" class="sr-only">{{toggleText}}</span>
<slot v-else name="button-content"><slot name="text">{{text}}</slot></slot>
</b-button>
<div :class="menuClasses"
ref="menu"
role="menu"
:role="role"
:aria-labelledby="safeId(split ? '_BV_toggle_' : '_BV_button_')"
@mouseover="onMouseOver"
@keyup.esc="onEsc"
@@ -67,14 +67,18 @@
variant: {
type: String,
default: null
},
role: {
type: String,
default: 'menu'
}
},
computed: {
dropdownClasses() {
return [
'btn-group',
'b-dropdown',
'dropdown',
'btn-group',
this.dropup ? 'dropup' : '',
this.visible ? 'show' : ''
];
@@ -1,22 +1,22 @@
<template>
<li :id="safeId()" :class="dropdownClasses">
<a :class="['nav-link', dropdownToggle, {disabled}]"
<a :class="toggleClasses"
href="#"
ref="button"
:id="safeId('_BV_button_')"
aria-haspopup="true"
:aria-expanded="visible ? 'true' : 'false'"
:disabled="disabled"
@click.stop.prevent="toggle($event)"
@keydown.enter.stop.prevent="toggle($event)"
@keydown.space.stop.prevent="toggle($event)"
@click.stop.prevent="toggle"
@keydown.enter.stop.prevent="toggle"
@keydown.space.stop.prevent="toggle"
>
<slot name="button-content"><slot name="text"><span v-html="text"></span></slot></slot>
</a>
<div :class="menuClasses"
role="menu"
:role="role"
ref="menu"
:aria-labelledby="safeId('_BV_button_')"
@mouseover="onMouseOver"
@@ -37,8 +37,9 @@
export default {
mixins: [idMixin, dropdownMixin],
computed: {
dropdownToggle() {
return this.noCaret ? '' : 'dropdown-toggle';
isNav() {
// Signal to dropdown mixin that we are in a navbar
return true;
},
dropdownClasses() {
return [
@@ -49,10 +50,17 @@
this.visible ? 'show' : ''
];
},
toggleClasses() {
return [
'nav-link',
this.noCaret ? '' : 'dropdown-toggle',
this.disabled ? disabled : ''
];
},
menuClasses() {
return [
'dropdown-menu',
this.right ? 'dropdown-menu-right': '',
this.right ? 'dropdown-menu-right': 'dropdown-menu-left',
this.visible ? 'show' : ''
];
}
@@ -61,6 +69,10 @@
noCaret: {
type: Boolean,
default: false
},
role: {
type: String,
default: 'menu'
}
}
};
Oops, something went wrong.

0 comments on commit 116cb3e

Please sign in to comment.