Permalink
Browse files

feat(modal): Improve modal transitions, padding adjustments, and adit…

…ional features (#1024)

* [modal] Fix transitions

* Update modal.vue

* Update modal.vue

* [v-b-modal] Use new namespaced $root event

* [modal] Incorporate BvEvent

* Update modal.vue

* [modal] Scrolbar adjustments & observeDom

* Update modal.vue

* [modal] Add variants

* Update demo.html

* Update demo.js

* Update meta.json

* Update README.md

* [modal] Add modal-header-close slot

* Update meta.json

* [b-button-close] New functional component for close button

Used by b-modal and b-alert

* make b-button-close available

* Update button-close.js

* [button-close] Ensure click event propagation is stopped when disabled

* [modal] use b-btn-close functional component

* [alert] Use b-btn-close component

* Update modal.vue

* add b-button-close to b-button meta.json

* [tooltip.js] Update to use only new modal close namespaced event

* [tooltip+popover] Auto-append tooltip/popover to modal if in a modal

Save user from having to specify the modal as a container when tooltip/popover is inside a modal

* [popover.js] Use dom utils

* [dom utils] Add class and attribute methods

* Update dom.js

* [modal] Use new dom utils class/atttr methods

* Update dom.js

* Update dom.js

* Update dom.js

* [tooltip.js] Use new DOM utils methods

* [popover.js] Use new dom utils class/attribute methods

* [modal] Update docs

* fix: correct some typos

* fix: clear console errors

* fix: add const declarations

* [modal] Call onAfterEvent transition handler

* fix: evt names for modal triggering & is_visible typo

* fix: modal v-model typo

* fix(btn-close): allow for innerHTML override

* refactor(modal): use object for conditional props

* feat(docs): new modal examples

* Classes: Wrap in Boolean and remove dangling commas

* [modal] minor updates to docs
  • Loading branch information...
tmorehouse committed Sep 11, 2017
1 parent febecfc commit dd5ddb026a123de8f3dee48656950d27a228c607
@@ -1,9 +1,7 @@
{
"title": "Button",
"component": "bButton",
"components": [
"bLink"
],
"components": ["bLink", "bButtonClose"],
"events": [
{
"event": "click",
@@ -1,7 +1,8 @@
# Modals
> Modals are streamlined, but flexible dialog prompts powered by JavaScript.
They support a number of use cases from user notification to completely custom content and feature a handful of helpful sub-components, sizes, accessibility, and more.
> Modals are streamlined, but flexible dialog prompts powered by JavaScript and CSS. They
support a number of use cases from user notification to completely custom content and
feature a handful of helpful sub-components, sizes, variants, accessibility, and more.
```html
<template>
@@ -40,7 +41,7 @@ They support a number of use cases from user notification to completely custom c
this.name = '';
},
handleOk(e) {
e.cancel();
e.preventDefault();
if (!this.name) {
alert('Please enter your name');
} else {
@@ -50,20 +51,20 @@ They support a number of use cases from user notification to completely custom c
handleSubmit() {
this.names.push(this.name);
this.clearName();
this.$refs.modal1.hide()
this.$refs.modal1.hide();
}
}
}
</script>
<!-- modal.vue -->
<!-- modal-1.vue -->
```
`<b-modal>`, by default, has an **OK** and a **Close** button in the footer. These buttons can
`<b-modal>`, by default, has an **OK** and **Cancel** buttons in the footer. These buttons can
be customized by setting various props on the component. You can customize the size of the buttons,
disable the **OK** button, hide the **Close** button (i.e. OK Only), choose a variant (e.g. `danger`
for a red OK button) using the `ok-variant` and `close-variant` props, and provide custom
button content using the `ok-title` and `close-title` props, or using the named
disable the **OK** button, hide the **Cancel** button (i.e. OK Only), choose a variant (e.g. `danger`
for a red OK button) using the `ok-variant` and `cancel-variant` props, and provide custom
button content using the `ok-title` and `cancel-title` props, or using the named
slots `modal-ok` and `modal-cancel`.
`<b-modal>` supports close on ESC (enabled by default), close on backdrop click (enabled by default), and
@@ -72,109 +73,127 @@ props `no-close-on-esc`, `no-close-on-backdrop`, and `hide-header-close` respect
You can override the modal title via the named slot `modal-title`, override the
header completely via the `modal-header` slot, and override the footer completely
via the `modal-footer` slot.
via the `modal-footer` slot.
**Note**: when using the `modal-footer` slot, the default **OK** and **Close** buttons will not be present.
Also, if you use the `modal-header` slot, the default header `X` close button will not be present, nor can you use
the `modal-title` slot.
**Note**: when using the `modal-footer` slot, the default **OK** and **Cancel** buttons will not
be present. Also, if you use the `modal-header` slot, the default header `X` close button will
not be present, nor can you use the `modal-title` slot.
## Toggle Modal Visibility
There are several methods that you can employ to toggle the visibility of `<b-modal>`.
### Using `v-b-modal` directive (recommended)
Other elements can easily show modals using `v-b-modal` directive.
Other elements can easily show modals using the `v-b-modal` directive.
```html
<!-- Using modifiers -->
<b-btn v-b-modal.modal1>Show Modal</b-btn>
<b-btn v-b-modal.myModal>Show Modal</b-btn>
<!-- Using value -->
<b-btn v-b-modal="'modal1'">Show Modal</b-btn>
<b-btn v-b-modal="'myMmodal'">Show Modal</b-btn>
<!-- the modal -->
<b-modal id="modal1">
Hello From Modal 1!
<b-modal id="myMmodal">
Hello From My Modal!
</b-modal>
```
Focus will automatically be returned to the trigger element once the modal closes.
See the **Accessibility** section below for details.
See the **Accessibility** section below for details.
### Using `show()` and `hide()` component methods
You can access modal using `ref` attribute and then call the `show()` or `hide()` methods.
```html
<b-button @click="showModal">
Open Modal
</b-button>
<b-modal ref="my_modal">
Hello From My Modal!
<b-btn @click="hideModal">Close Me</b-btn>
</b-modal>
```
<template>
<b-button @click="showModal">
Open Modal
</b-button>
<b-modal ref="myModalRef" title="Using Component Methods">
<div class="d-block text-center">
<h3>Hello From My Modal!</h3>
</div>
<b-btn class="mt-3" variant="outline-danger" block @click="hideModal">Close Me</b-btn>
</b-modal>
</template>
```js
methods: {
showModal() {
this.$refs.my_modal.show();
},
hideModal() {
this.$refs.my_modal.hide();
<script>
export default {
methods: {
showModal() {
this.$refs.myModalRef.show();
},
hideModal() {
this.$refs.myModalRef.hide();
}
}
}
</script>
<!-- modal-2.vue -->
```
The `hide()` method accepts an optional argument. See section **Prevent Closing**
below for details.
### Using `v-model` property.
### Using `v-model` property
`v-model` property is always automatically synced with `<b-modal>` visible state
and you can show/hide using `v-model`.
```html
<b-button @click="modalShow = !modalShow">
Open Modal
</b-button>
<b-modal v-model="modalshow">
Hello From Modal!
</b-modal>
```
<template>
<b-button @click="modalShow = !modalShow">
Open Modal
</b-button>
<b-modal v-model="modalShow">
Hello From Modal!
</b-modal>
</template>
```js
data: {
modalShow: false
<script>
export default {
data: {
modalShow: false
}
}
</script>
<!-- modal-3.vue -->
```
When using the `v-model` property, do not use the `visible` property at the same time.
### Directly Emitting Events
### Emitting Events on $root
You can emit `show::modal` and `hide::modal` event on `$root` with first
argument which is the modal's id:
You can emit `bv::show::modal` and `bv::hide::modal` event on `$root` with the first
argument set to the modal's id. An optional second argument can specify the element
to return focus to once the modal is closed. The second argument can be a CSS selector,
and element reference, or a component reference.
```html
<b-button @click="showModal" ref="btnShow">
Open Modal
</b-button>
<b-modal id="modal1">
Hello From My Modal!
<b-modal @hidden="onHidden">
<div class="d-block">Hello From My Modal!</div>
<b-btn @click="hideModal">Close Me</b-btn>
</b-modal>
```
```js
methods: {
showModal() {
this.$root.$emit('show::modal','modal1');
this.$root.$emit('bv::show::modal','modal1');
},
hideModal() {
this.$root.$emit('hide::modal','modal1');
this.$root.$emit('bv::hide::modal','modal1');
},
onHidden(evt) {
// Return focus to our Open Modal button
// See accessibility below for additional return-focus methods
this.$refs.btnShow.$el.focus();
@@ -185,12 +204,12 @@ methods: {
## Prevent Closing
To prevent `<b-modal>` from closing (for example when validation fails)
you can call the `cancel()` method of the event object passed to your `ok` (**OK** button),
`cancel` (**Close** button) and `hide` event handlers.
To prevent `<b-modal>` from closing (for example when validation fails). you can call
the `preventDefault()` method of the event object passed to your `ok` (**OK** button),
`cancel` (**Cancel** button) and `hide` event handlers.
```html
<b-modal @hide="save">
<b-modal id="modalPrevent" @hide="save">
Hello From Modal!
<b-alert variant="danger" :show="message ? true : false">
{{ message }}
@@ -207,57 +226,110 @@ methods: {
save(e) {
if(!this.saved) {
this.message = 'Please save your work';
return e.cancel();
e.preventDefault();
} else {
this.message = null;
}
}
}
```
**Note**: events `ok` and `cancel` are emitted by modal's built in **OK** and **Close**
**Note**: events `ok` and `cancel` are emitted by modal's built in **OK** and **Cancel**
buttons respectively. These events will not be emitted, by default, if you have provided your own
buttons in the `modal-footer` slot or have hidden the footer. In this case use the `hide` event
to control cancelling of the modal close.
to control cancelling of the modal close. Event `hide` is always emitted, even if `ok` and `cancel`
are emitted.
The `close` event object contains a single property and a single method:
The `ok`, `cancel`, and `hide` event object contains several properties and methods:
| Property or Method | Type | Description
| ------------ | ------ | --------------------------------------------
| `e.cancel()` | Method | When called prevents the modal from closing
| `isOK` | Property | Will be one of: `true` (Default **OK** Clicked), `false` (Default **Close** clicked), the argument provided to the `hide()` method, or `undefined` otherwise (i.e. close on Esc, or close on backdrop click)
| `e.preventDefault()` | Method | When called prevents the modal from closing
| `trigger` | Property | Will be one of: `ok` (Default **OK** Clicked), `cancel` (Default **Cancel** clicked), `esc` (if the <kbd>ESC</kbd> key was pressed), `backdrop` (if the backdrop was clicked), `headerclose` (if the header X button was clicked), the argument provided to the `hide()` method, or `undefined` otherwise.
| `target` | Property | A reference to the modal element
| `vueTarget` | property | A reference to the modal's Vue VM instance
You can set the value of `isOK` by passing an argument to the component's
`hide()` method for advanced control.
You can set the value of `trigger` by passing an argument to the component's
`hide()` method for advanced control.
**Note:** `ok` and `cancel` events will be only emitted when the argument to `hide()` is strictly `true`
or `fase` respectively. The argument passed to `hide()` will be placed into the
`isOK` property of the close event object.
**Note:** `ok` and `cancel` events will be only emitted when the argument to `hide()` is strictly `ok`
or `cancel` respectively. The argument passed to `hide()` will be placed into the
`trigger` property of the event object.
## Modal sizing
Modals have two optional sizes, available via the prop `size`. These sizes kick in at certain
breakpoints to avoid horizontal scrollbars on narrower viewports. Valid optional sizes are
`lg`, or `sm`.
The width of `<b-modal>` can be set via the `size` prop to `lg`, `sm` or `md` (default).
```html
<div>
<b-btn v-b-modal.modallg variant="primary">Large modal</b-btn>
<b-btn v-b-modal.modalsm variant="primary">Small modal</b-btn>
<b-modal id="modallg" size="lg" title="Large Modal">
Hello Modal!
</b-modal>
<b-modal id="modalsm" size="sm" title="Small Modal">
Hello Modal!
</b-modal>
</div>
<!-- modal-sizes.vue -->
```
## Using the grid
Utilize the Bootstrap grid system within a modal by nesting `<b-container fluid>` within
the modal-body. Then, use the normal grid system `<b-row>` and `<b-col>` as you would
anywhere else.
## Tooltips and popovers
Tooltips and popovers can be placed within modals as needed. When modals are closed, any tooltips
and popovers within are also automatically dismissed. Tooltips and popovers are automatically
appended to the modal element (to ensure correct z-indexing), although you can override where
they are appended by specifying a container ID (refer to tooltip and popover docs for details).
```html
<div>
<b-btn v-b-modal.modalPopover>Show Modal</b-btn>
<b-modal id="modalPopover" title="Modal with Popover" ok-only>
<p>
This
<b-btn v-b-popover="'Popover inside a modal!'" title="Popover">
Button
</b-btn>
triggers a popover on click.
</p>
<p>
This <a href="#" v-b-tooltip title="Tooltip in a modal!">Link</a>
will show a tooltip on hover.
</p>
</b-modal>
</div>
<!-- modal-popover.vue -->
```
## Variants
Control the header, footer, and body background and text variants by setting the
`header-bg-variant`, `header-text-variant`, `body-bg-variant`, `body-text-variant`,
`footer-bg-variant`, and `footer-text-variant` props. Use any of the standard Bootstrap
variants such as `danger`, `warning`, `info`, `success`, `dark`, `light`, etc.
The variants for the bottom border of the header and top border of the footer can be
controlled by the `header-border-variant` and `footer-border-variant` props respectively.
## Accessibility
`<b-modal>` provides several accessibility features, including auto focus, return
focus, and keyboard (tab) _focus containment_.
For `aria-labelledby` and `aria-described` by attributes to appear on the
modal, you **must** supply an `id` attribute on `<b-modal>`. `aria-labeledby` will
modal, you **must** supply an `id` attribute on `<b-modal>`. `aria-labelledby` will
not be present if you have the header hidden.
### Auto Focus
`<b-modal>` will autofocus the first visible, non-disabled, focusable element found
in the modal, searching in the following order:
- Modal body
- Modal footer
- Modal header
If a focusable element is not found, then the entire modal will be focused.
`<b-modal>` will autofocus the modal container when opened.
You can pre-focus an element within the `<b-modal>` by listening to the `<b-modal>` `shown` event, and
call the element's `focus()` method. `<b-modal>` will not attempt to autofocus if
@@ -285,15 +357,6 @@ methods: {
}
```
To disable the auto-focus feature, add the prop `no-auto-focus` on
`<b-modal>`. This will disable searching for a focusable element within
body, footer, and header. With `no-auto-focus` set, the modal-content
will be focused instead, unless you have pre-focused an element within.
`no-auto-focus`may be required when you have modal with long body content (without
focusable items in th modal body) that causes the modal to overflow the
height of the viewport, and in-turn automatically scrolls down to the footer buttons.
### Returning focus to the triggering element on modal close
For accessibility reasons, it is desireable to return focus to the element
Oops, something went wrong.

0 comments on commit dd5ddb0

Please sign in to comment.