Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: renatodeleao/a11y-vue-dialog
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.4.3
Choose a base ref
...
head repository: renatodeleao/a11y-vue-dialog
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref

Commits on May 1, 2020

  1. fix: edge case of unwanted mouseup propagation

    Fixes pseudo drags from dialog to backdrop closing the dialog.
    Pseudo becuase it's not a drag, it's a selection that can go out of bounds.
    
    Prevents mouseup that started inside (dialogRef mousedown) but was released outside (backdropRef) to bubble  and also trigger backdrop click, consequentially closing the dialog.
    
    ⚠️ Note: for cases when backdropRef wraps the dialog content,
       so it's also our root, that's why it's affected by children
       events bubbling
    renatodeleao committed May 1, 2020
    Copy the full SHA
    f61af1a View commit details
  2. 0.4.4

    renatodeleao committed May 1, 2020
    Copy the full SHA
    6ec53b9 View commit details

Commits on May 5, 2020

  1. Copy the full SHA
    352c63d View commit details
  2. fix: remove complicated and not working cache mechanism on resetData

    we we're caching anything, because on open the querySelector methods would run again anyways. So to this right we need to think about it more
    renatodeleao committed May 5, 2020
    Copy the full SHA
    a2e67a4 View commit details
  3. fix: listen to attribute changes on mutation observer

    - otherwise v-show elements would be caught as new focusableChildren.
    - move getter under next-tick so that `v-if` elements can be caugh as well
    renatodeleao committed May 5, 2020
    Copy the full SHA
    9a9d684 View commit details
  4. fix: our _isFocusable() definition to include only visible element

    an invisible element (or inisde a hidden parent) is not focusable, so we need to remove those from the array.
    
    - Included jQuery :visible method definition, as it's smoother than computedStyles.
    renatodeleao committed May 5, 2020
    Copy the full SHA
    bec2b59 View commit details
  5. fix: #21 handling focus mutations with conditionals

    Some actions might trigger conditionals that change focus references within the dialog.
    Some could be added some removed. We were already updating those in the mutation observer (now
    updated with style changes as well for v-show), but if the focused element was removed itself
    focus was lost and the dialog could be closed with escape key.
    
    Among other problems this now moves focus to the next focusable element within the dialog
    or first it it doesn't exists. That guarantes that event if activeElement disappears, focus is kept
    trapped inside dialog.
    
    update: listen to focus to determine focuswed element in the focus tree
    
    this was done on trapFocus(), but it would only trigger the current if we actually tab our way there. If we click a button we didn't knew what was his position in current focusable tree.
    
    We now save it as instance property
    
    update: move focus to next element within the dialog if current disappears
    
    - after an async action the trigger might be removed or hidden, in both cases we move focus to the next element, it doesn't exist we go back to first.
    
    This fixes #21
    renatodeleao committed May 5, 2020
    Copy the full SHA
    a61be19 View commit details
  6. Copy the full SHA
    6a33e09 View commit details
  7. Copy the full SHA
    360f974 View commit details
  8. 0.4.5

    renatodeleao committed May 5, 2020
    Copy the full SHA
    dce7abb View commit details

Commits on May 6, 2020

  1. fix: proper focus management after dialog focusable mutations

    I've worked super hard on this. It might look so simple but there's so many edges cases. I've written my best in comments, so rely on them for this commit description.
    
    TD;DR - this keeps focus trap (inside dialog) and sequential focus tabbing after an event that removes/disables current focused element moves focus to body. Note that this event can also mutate focus siblings, so quest for find the next/prev focusable element is not linear.
    
    Here's the more simplistic demo that we mimic:
    https://codepen.io/ohsimtabem/pen/QWjarqg
    
    But much more complex scenarios can happen (check the playground for wild examples)
    renatodeleao committed May 6, 2020
    Copy the full SHA
    bfade5b View commit details
  2. Copy the full SHA
    4abef9f View commit details
  3. 0.4.6

    renatodeleao committed May 6, 2020
    Copy the full SHA
    24c43e3 View commit details

Commits on Jun 9, 2020

  1. add: focus-visible polyfill as dev dependency

    for debugging purposes.
    renatodeleao committed Jun 9, 2020
    Copy the full SHA
    9b45d54 View commit details
  2. hotfix: focus-visibile trigger false positives on mutated active element

    TL;DR for a brief moment focus-visible plugin sets document.activeElement to body(proably due to the blur() event on their codebase). that trigger our code to "think" that the active element was mutated — when hidden/removed focus moves to body. So we though that our tabbed element was deleted initiation that spaghetti of finding next, but since nothing was removed, focus visible set "next" to body, so our modal started from fist focus element again. Result we were always trapped in the same element. Solution is to wrap verification in an empty setTimout, that moves our code to the next queue, and in that place focus-visible has done its thing and active element is back to normal.
    
    This reveals the fragility of my focusTrap code. I know that is overengineered, but looking at other dialog/modal implementations it seems to me that either i'm not seeing something obvious, or nobody ecounters edge cases as frequent as me.
    
    closes #23. But #22 is desperately need 🆘
    renatodeleao committed Jun 9, 2020
    Copy the full SHA
    214225b View commit details
  3. 0.4.7

    renatodeleao committed Jun 9, 2020
    Copy the full SHA
    4760274 View commit details

Commits on Jun 10, 2020

  1. 0.4.8

    renatodeleao committed Jun 10, 2020
    Copy the full SHA
    47b59f1 View commit details

Commits on Jul 17, 2020

  1. build(deps): bump lodash from 4.17.15 to 4.17.19

    Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
    - [Release notes](https://github.com/lodash/lodash/releases)
    - [Commits](lodash/lodash@4.17.15...4.17.19)
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Jul 17, 2020
    Copy the full SHA
    fa13077 View commit details

Commits on Jul 31, 2020

  1. build(deps): bump elliptic from 6.5.2 to 6.5.3

    Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.2 to 6.5.3.
    - [Release notes](https://github.com/indutny/elliptic/releases)
    - [Commits](indutny/elliptic@v6.5.2...v6.5.3)
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Jul 31, 2020
    Copy the full SHA
    122cc50 View commit details

Commits on Aug 7, 2020

  1. build(deps): bump prismjs from 1.20.0 to 1.21.0

    Bumps [prismjs](https://github.com/PrismJS/prism) from 1.20.0 to 1.21.0.
    - [Release notes](https://github.com/PrismJS/prism/releases)
    - [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
    - [Commits](PrismJS/prism@v1.20.0...v1.21.0)
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Aug 7, 2020
    Copy the full SHA
    a4e973f View commit details

Commits on Sep 4, 2020

  1. build(deps-dev): bump node-sass from 4.13.0 to 4.13.1

    Bumps [node-sass](https://github.com/sass/node-sass) from 4.13.0 to 4.13.1.
    - [Release notes](https://github.com/sass/node-sass/releases)
    - [Changelog](https://github.com/sass/node-sass/blob/master/CHANGELOG.md)
    - [Commits](sass/node-sass@v4.13.0...v4.13.1)
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Sep 4, 2020
    Copy the full SHA
    bf9bbe8 View commit details

Commits on Sep 30, 2020

  1. fixup!: propper main field in package.json

    This fixes issues when using the package in not transpile configured
    environments. I'll give jest as an example since it usually doesn't
    transpile node_modules due speed.
    
    Side-effect:
    - updates rollup config to not use pkg.main as entry point but a
    regular path instead.
    renatodeleao committed Sep 30, 2020
    Copy the full SHA
    6d54cd5 View commit details
  2. Merge pull request #25 from renatodeleao/dependabot/npm_and_yarn/loda…

    …sh-4.17.19
    
    build(deps): bump lodash from 4.17.15 to 4.17.19
    renatodeleao authored Sep 30, 2020
    Copy the full SHA
    421b5e4 View commit details
  3. Merge pull request #26 from renatodeleao/dependabot/npm_and_yarn/elli…

    …ptic-6.5.3
    
    build(deps): bump elliptic from 6.5.2 to 6.5.3
    renatodeleao authored Sep 30, 2020
    Copy the full SHA
    83cabc3 View commit details
  4. Merge pull request #27 from renatodeleao/dependabot/npm_and_yarn/pris…

    …mjs-1.21.0
    
    build(deps): bump prismjs from 1.20.0 to 1.21.0
    renatodeleao authored Sep 30, 2020
    Copy the full SHA
    4f46825 View commit details
  5. Merge pull request #28 from renatodeleao/dependabot/npm_and_yarn/node…

    …-sass-4.13.1
    
    build(deps-dev): bump node-sass from 4.13.0 to 4.13.1
    renatodeleao authored Sep 30, 2020
    Copy the full SHA
    1dfbe86 View commit details
  6. 0.4.9

    renatodeleao committed Sep 30, 2020
    Copy the full SHA
    eba760d View commit details

Commits on Oct 5, 2020

  1. refactor!: replaced internal focus management per focus-trap pkg

    Because i'm just a regular guy with dyslexi, trying to do some frontend and there are way clever folks out there doing magic in the focus trap business! I had way too much heaches because of it, the code had so many hacks to make i barely work so and super glad to see them gone, special since focus-trap community seems vibrant!
    
    - Add focus-trap as dependency
    - Removed all code related with focus management
    - removed tests related with focus management
    renatodeleao committed Oct 5, 2020
    Copy the full SHA
    1a49e12 View commit details
  2. Copy the full SHA
    9f54416 View commit details
  3. Merge pull request #29 from renatodeleao/feat/focus-trap-next

    Feat: focus trap next
    renatodeleao authored Oct 5, 2020
    Copy the full SHA
    3b8c499 View commit details
  4. 0.5.0

    renatodeleao committed Oct 5, 2020
    Copy the full SHA
    b2c8b61 View commit details

Commits on Oct 7, 2020

  1. fix(focus-trap): only querySelector valid autofocus elements

    avoids moving initial focus to invalid <div autofocus> which aren't focusable anyways. If people want invalid els to be focusable, they can pass it via focusRef (by binding it to an invalid element) or via focusTrapCreateOptions object, but by default we won't do it because it promotes a bad practice.
    renatodeleao committed Oct 7, 2020
    Copy the full SHA
    70eb72e View commit details
  2. Copy the full SHA
    6898e2e View commit details
  3. 0.5.1

    renatodeleao committed Oct 7, 2020
    Copy the full SHA
    7719aac View commit details

Commits on Oct 18, 2020

  1. fix: allow "role=alertdialog" to be closed on escape

    This assumption was based on the description of https://github.com/edenspiekermann/a11y-dialog#usage-as-a-modal.
    
    But reading the spec, I don't find a reference to prevent alertdialog dismiss with the `Esc` key. Actually the aria example is dismissable by escape key
    
    https://www.w3.org/TR/wai-aria-practices-1.1/examples/dialog-modal/alertdialog.html
    
    That being said, the backdrop click is still prevented with the role "alertdialog" because the spec also says that "keyboard and mouse interactions only operate within the dialog." and currently our backdrop is outside the dialgoRoot element (although) it's not invalid to move it inside (never tested it) - so this requires further thought
    renatodeleao committed Oct 18, 2020
    Copy the full SHA
    16d08f9 View commit details
  2. 0.5.2

    renatodeleao committed Oct 18, 2020
    Copy the full SHA
    1e3a3b5 View commit details
  3. Copy the full SHA
    19ce22e View commit details

Commits on Nov 30, 2020

  1. feat: remove preventBackgroundScroll prop and side-effects

    adding overflow hidden to body might sound a reasonable default but can actually break custom layouts that don't use body as their default scroller element. Also it's fairly known that iOS safari doesn't respond to overflow:hidden on body so a more powerful js solution is usually required.
    
    By these reasons i decided to deprecate this default implementation (which are just 3 lines that you can add to your custom wrapper anyways), and replaced it with event emits: that way you have full control over the preventBackgroundScroll solution.
    
    For now the method exposes siblingCount flag as play load to make sure the code does not ran in nested dialog scenario (since an overflow solution might already be applied),  but keeping track of this could also be done at the wrapper level. I'll leave it for now since it's is just a children count of portal-target.
    renatodeleao committed Nov 30, 2020
    Copy the full SHA
    0aa3a1f View commit details
  2. Copy the full SHA
    d120948 View commit details
  3. Copy the full SHA
    4cfebc8 View commit details
  4. docs: deprecation instructions of preventBackgroundScrolling

    how to achieve the same thing using events.
    renatodeleao committed Nov 30, 2020
    Copy the full SHA
    fb6f28b View commit details
  5. Copy the full SHA
    edb7373 View commit details
  6. 0.6.0

    renatodeleao committed Nov 30, 2020
    Copy the full SHA
    423df2b View commit details

Commits on Dec 11, 2020

  1. build(deps): bump ini from 1.3.5 to 1.3.7

    Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7.
    - [Release notes](https://github.com/isaacs/ini/releases)
    - [Commits](npm/ini@v1.3.5...v1.3.7)
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Dec 11, 2020
    Copy the full SHA
    665d8f6 View commit details

Commits on Dec 14, 2020

  1. Merge pull request #30 from renatodeleao/dependabot/npm_and_yarn/ini-…

    …1.3.7
    
    build(deps): bump ini from 1.3.5 to 1.3.7
    renatodeleao authored Dec 14, 2020
    Copy the full SHA
    14b5f1a View commit details

Commits on Mar 1, 2021

  1. build(deps): bump prismjs from 1.21.0 to 1.23.0

    Bumps [prismjs](https://github.com/PrismJS/prism) from 1.21.0 to 1.23.0.
    - [Release notes](https://github.com/PrismJS/prism/releases)
    - [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
    - [Commits](PrismJS/prism@v1.21.0...v1.23.0)
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Mar 1, 2021
    Copy the full SHA
    288a9a5 View commit details

Commits on Mar 9, 2021

  1. build(deps): bump elliptic from 6.5.3 to 6.5.4

    Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.3 to 6.5.4.
    - [Release notes](https://github.com/indutny/elliptic/releases)
    - [Commits](indutny/elliptic@v6.5.3...v6.5.4)
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Mar 9, 2021
    Copy the full SHA
    b9c15e2 View commit details

Commits on Mar 14, 2021

  1. Merge pull request #32 from renatodeleao/dependabot/npm_and_yarn/elli…

    …ptic-6.5.4
    
    build(deps): bump elliptic from 6.5.3 to 6.5.4
    renatodeleao authored Mar 14, 2021
    Copy the full SHA
    e9709cf View commit details
  2. Merge pull request #31 from renatodeleao/dependabot/npm_and_yarn/pris…

    …mjs-1.23.0
    
    build(deps): bump prismjs from 1.21.0 to 1.23.0
    renatodeleao authored Mar 14, 2021
    Copy the full SHA
    eb98a3d View commit details
  3. dev: you regular vue cli app for playground

    removes breaking warnings and errors when using latest version of portal-vue. Also removes the need for colabs to have vue-cli installed globally and use the local version instead
    
    LinusBorg/portal-vue#201
    renatodeleao committed Mar 14, 2021
    Copy the full SHA
    8636d3d View commit details
Showing with 14,118 additions and 5,466 deletions.
  1. +55 −104 README.md
  2. +4 −5 docs/.vuepress/config.js
  3. +8 −6 docs/guide/README.md
  4. +106 −0 docs/guide/advanced-tips.md
  5. +85 −48 docs/guide/advanced-usage.md
  6. +61 −0 docs/guide/basic-usage.md
  7. +22 −4 docs/guide/events.md
  8. +0 −56 docs/guide/installation-and-usage.md
  9. +0 −8 docs/guide/portal-vue.md
  10. +11 −29 docs/guide/props.md
  11. +0 −100 docs/guide/renderless-usage.md
  12. +13 −0 docs/guide/slot-scope.md
  13. +0 −35 docs/guide/slots.md
  14. +5 −4 docs/guide/thanks.md
  15. +13 −14 package.json
  16. +23 −0 playground/.gitignore
  17. +0 −80 playground/DialogExample.vue
  18. +0 −48 playground/Playground.vue
  19. +29 −0 playground/README.md
  20. +3 −0 playground/babel.config.js
  21. +81 −0 playground/package.json
  22. BIN playground/public/favicon.ico
  23. +17 −0 playground/public/index.html
  24. +215 −0 playground/src/App.vue
  25. BIN playground/src/assets/logo.png
  26. +131 −0 playground/src/components/BasicDialog.vue
  27. +113 −0 playground/src/components/DialogExample.vue
  28. +122 −0 playground/src/components/HelloWorld.vue
  29. +8 −0 playground/src/main.js
  30. +12 −0 playground/vue.config.js
  31. +8,913 −0 playground/yarn.lock
  32. +0 −20 postcss.config.js
  33. +8 −24 rollup.config.js
  34. +366 −0 src/A11yDialog.vue
  35. +0 −330 src/A11yVueDialog.vue
  36. +0 −467 src/A11yVueDialogRenderless.vue
  37. +68 −93 src/__tests__/{A11yVueDialogRenderless.spec.js → A11yDialog.spec.js}
  38. +0 −42 src/components/Skeleton.vue
  39. +3 −36 src/index.js
  40. +0 −38 src/styles/_config.scss
  41. +0 −83 src/styles/_skeleton.scss
  42. +0 −111 src/styles/_tools.scss
  43. +0 −60 src/styles/a11y-vue-dialog.scss
  44. +25 −0 src/utils.js
  45. +3,598 −3,621 yarn.lock
159 changes: 55 additions & 104 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
## Why another modal/dialog plugin

- ✅ Accessibility first — Focus trap + keyboard navigation + aria-attributes
- ✅ Universal: works in `vue@2` and `vue@3` 🚧
- ✅ Renderless/headless: no assumptions about styles or markup. You have full control.
- ✅ Accessibility first — Focus trap<sup>[1]</sup> + keyboard navigation + aria-attributes
- ✅ Fully controlled component
- ✅ Pure vue, no wrapping.
- ✅ Simplicity + size
- 🕸 Nested dialogs ([questionable pattern](https://github.com/edenspiekermann/a11y-dialog#nested-dialogs), not recommended, but possible because [it happens](https://cl.ly/be43f69393f7))
- 🚧 _renderless version_
- 🕸 Nested dialogs ([questionable pattern](https://github.com/edenspiekermann/a11y-dialog#nested-dialogs), not recommended, but possible because [it happens](https://cl.ly/be43f69393f7)) and it's actually in WAI-ARIA [examples](https://www.w3.org/TR/wai-aria-practices-1.1/examples/dialog-modal/dialog.html) so...

Detailed documentation and additional info is available [at documentation site](https://renatodeleao.github.io/a11y-vue-dialog/)

@@ -16,136 +17,86 @@ npm i a11y-vue-dialog
# or
yarn add a11y-vue-dialog
```

```js
// portal vue is binstalled as dependency, and it's required
import PortalVue from "portal-vue";
Vue.use(PortalVue);

// add the component
import A11yVueDialog from "a11y-vue-dialog";
// if you want to register globally
Vue.use(A11yVueDialog);
yarn add a11y-dialog
```

## Usage

```html
<a11y-vue-dialog :open="true">
<p>This slot content will be rendered wherever the <portal-target name="a11y-vue-dialogs">
is located. (we adivse at the bottom of your root component)</p>
</a11y-vue-dialog>
```

```html
<portal-target name="a11y-vue-dialogs" multiple />
```

## Renderless version
A renderless version provides all the functionality required to build a proper `Dialog`, but gives zero f*cks about your markup and styles. The default `scopedSlot` props help you bind the accessibility attributes and event listeners to your markup elements, but semantics and styling layer it's now the consumer full responsibility.

> Each `ref` suffixed slotProp is an object that contains a "props" and "listeners" keys to be attached to elements via `v-bind` and `v-on` respectively
| slotProp | type | desc
| ------------| -------- | ---- |
| open | Boolean | prop forwarding for portal v-if
| close | Function | method forwarding for closing the dialog
| backdropRef | Object | for the backdrop element
| dialogRef | Object | for the main dialog element
| closeRef | Object | for attaching close buttons/actions
| titleRef | Object | For attaching dialog title, accessibility
| focusRef | Object | For cherry-picking the first focusable element on open
A renderless/headless component provides all the functionality required to build a proper `Dialog`, but gives zero f*cks about your styles. As such you have full control over it and have to DYI. Here's a basic example on how to do it:

### Example
```html
<!-- compose into you own markup, MyDialog.vue -->
```vue
<!-- AppBaseDialog.vue -->
<template>
<a11y-vue-dialog-renderless
v-bind="$props"
@close="$emit('close')"
#default="{ open, closeFn, backdropRef, dialogRef, titleRef, closeRef, focusRef }"
>
<portal to="a11y-vue-dialogs" v-if="open">
<div class="youclasses"
v-bind="backdropRef.props"
v-on="backdropRef.listeners"
>
<div
class="youclasses__element"
v-bind="dialogRef.props"
v-on="dialogRef.listeners"
>
<h1 v-bind="titleRef.props">Title</h1>
<button
v-bind="closeRef.props"
v-on="closeRef.listeners"
>
x
</button>
<section>
<!-- autofocus would also work on this case, but not every focusable element supports it -->
<input
type="text"
placeholder="I will get focused first because i'm the focus ref"
v-bind="focusRef.props"
/>
<slot />
</section>
<footer>
<button @click="closeFn">Cancel</button>
<button @click="emit('confirm')">Confirm</button>
</footer>
</div>
<a11y-dialog
v-bind="$attrs"
v-on="$listeners"
v-slot:default="{ rootRef, dialogRef, titleRef, closeRef }"
>
<div v-bind="rootRef.prop">
<!-- Bindings do the accessibility attributes for you -->
<div v-bind="dialogRef.props" v-on="dialogRef.listeners">
<h1 v-bind="titleRef.props">{{ title }}</h1>
<button v-bind="closeRef.props" v-on="closeRef.listeners">
</div>
</portal>
</a11y-vue-dialog-renderless>
</div>
...
<slot />
</a11y-dialog>
</template>
<script>
import { A11yVueDialogRenderless } from "a11y-vue-dialog";
import { Portal } from "portal-vue";
import { A11yDialog } from 'a11y-dialog'
export default {
name: 'MyDialog',
components: {
A11yVueDialogRenderless,
Portal
},
extends: { A11yVueDialogRenderless },
props: ['open', 'role'],
name: 'AppBaseDialog',
components: { A11yDialog },
props: {
title: {
type: String,
required: true
}
}
}
</script>
```

### Then re-use and conquer

```html
<!-- page.vue -->
```vue
<!-- At any View.vue, after import AppBaseDialog -->
<template>
<div id="page">

<button @click="openMyModal = true">
<my-dialog
open="openMyModal"
<button @click="isDialogOpen = true">
<app-base-dialog
title="Hello world"
:open="isDialogOpen"
@close="openMyModal = false"
@confirm="handSubmit"
/>
>
My markup, my rules.
</my-dialog>
</app-base-dialog>
</div>
</template>
```

- Here's a [codesandbox to play with](https://codesandbox.io/s/renderless-a11y-vue-dialog-q5lqk?file=/src/components/DialogConfirm.vue)
- Checkout [this example](https://github.com/edenspiekermann/a11y-dialog#expected-dom-structure) for what's the minimum expected markup for an accessible dialog
Voilá, checkout a [working example on CodeSandbox](https://codesandbox.io/s/renderless-a11y-vue-dialog-demo-0-8-0-beta-1-3igsm9).


## Docs

Detailed documentation and additional info is available [at documentation site](https://renatodeleao.github.io/a11y-vue-dialog/)

## Play

A playground is used to test the component locally. It uses [`vue/cli` instant prototyping feature](https://cli.vuejs.org/guide/prototyping.html), so the downside is that you have to install it globally.

- Clone this repo
- `yarn install`
- Then, just run `yarn play`

## Colophon
Thanks to all this packages for inspiration and guidance.

- `portal-vue|vue-simple-portal` from [@LinusBorg](https://github.com/LinusBorg) which makes escaping overflow traps easy peasy
- `a11y-dialog` (vanilla) from `@KittyGiraudel` to lead the path that ended here
- `vue-a11y-dialog` (wrapper around ^) from `@morkro` for the motivation to build a pure vue alternative to it.
- All build tools used to make this a reality!
## License
MITq
MIT © Renato de Leão
9 changes: 4 additions & 5 deletions docs/.vuepress/config.js
Original file line number Diff line number Diff line change
@@ -23,13 +23,12 @@ module.exports = {
sidebarDepth: 2,
sidebar: [
'/guide/',
['/guide/installation-and-usage', "Getting Started"],
['/guide/advanced-usage', "Advanced Usage"],
['/guide/renderless-usage', "Renderless Usage (new)"],
['/guide/basic-usage', "Getting Started"],
['/guide/advanced-usage', "Full Example"],
['/guide/props', "Props"],
['/guide/slots', "Slots"],
['/guide/slot-scope', "Slot scope"],
['/guide/events', "Events"],
['/guide/portal-vue', "Why portal-vue?"],
['/guide/advanced-tips', "Advanced tips"],
['/guide/thanks', "Thanks"],
]
}
14 changes: 8 additions & 6 deletions docs/guide/README.md
Original file line number Diff line number Diff line change
@@ -3,16 +3,18 @@ title: Introduction
---
## Why another modal/dialog plugin

- ✅ Accessibility first — Focus trap + keyboard navigation + aria-attributes
- ✅ Universal: works in `vue@2` and `vue@3` 🚧
- ✅ Renderless/headless: no assumptions about styles or markup. You have full control.
- ✅ Accessibility first — Focus trap<sup>[1]</sup> keyboard navigation + aria-attributes
- ✅ Fully controlled component
- ✅ Pure vue, no wrapping.
- ✅ Simplicity + size
- 🕸 Nested dialogs ([questionable pattern](https://github.com/edenspiekermann/a11y-dialog#nested-dialogs), not recommended, but possible because [it happens](https://cl.ly/be43f69393f7))
- 🚧 _renderless version_
- 🕸 Nested dialogs ([questionable pattern](https://github.com/edenspiekermann/a11y-dialog#nested-dialogs), not recommended, but possible because [it happens](https://cl.ly/be43f69393f7)) and it's actually in WAI-ARIA [examples](https://www.w3.org/TR/wai-aria-practices-1.1/examples/dialog-modal/dialog.html) so...

#### Footnotes
1. Since `v0.5.0` focus trap is powered by the awesome [`focus-trap`](https://github.com/focus-trap/focus-trap) — go and give them some ✨

## Why Not ...?

My inspiration for this package was accessibility-first. There are a lot of vue dialog/modals out there that treat accessibility as sideeffect not a feature. A11y-vue-dialog provides you an out-of-the-box accessible dialog, with just enought functionallity to get you running in seconds, and just enough props and events to make it adaptable to any usecase.
## Why Not ...?

There are a lot of dialog/modal plugins out there, if your looking for a fully fledged plugin, theres a list in the thanks you section that might help :)
Because there are a lot of vue dialog/modals out there that treat accessibility as side-effect not a feature. Also most of them ship with preset markup/styles and you can't use your own components markup with them: this makes this package a little bit more verbose to setup, but way more flexible to adapt to almost any scenario.
106 changes: 106 additions & 0 deletions docs/guide/advanced-tips.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
## Teleporting
This component should work with any `portal|teleport` solution. We don't ship one as a dependency because it's not a requirement from a wai-aria guidelines standpoint. That being said, I could not recommend enough the usage of one, to escape common rendering gotchas with dialogs — the overflow trap.

| Package | When |
|---------|------|
| [vue-simple-portal](https://github.com/LinusBorg/vue-simple-portal) | The lightweight (`3kb`) portal package for vue 2. If don't have any other portal solution on your app, this is the way to go |
| [vue-portal](https://github.com/LinusBorg/portal-vue) | From the same creator, more robust than the previous and intended for more advanced usecases than simple dialogs. |

if you already have any of the packages mentioned above or are using a custom solution, see the "usage with portal" chapter for instructions.

### Usage with `vue-simple-portal`

This demo uses [vue-simple-portal](https://github.com/LinusBorg/vue-simple-portal#transitions), but it would be more or less the same with any `portal` solution

```vue
<template>
<portal v-if="open">
<a11y-dialog>
<!-- your implementation like above -->
</a11y-dialog>
</portal>
</template>
<script>
import { Portal } from '@linusborg/vue-simple-portal'
export default {
components: { Portal, A11yDialog }
}
</script>
```

### Combine with `<transition>`


>When you use a `<transition>` as the root element of the portal and then remove the portal (i.e. with v-if) or set its disabled prop to true, no leave transition will happen.
>While this is to expected, as the same thing would happen if you removed a div that contains a `<transition>`, it often trips people up, which is why it's mentioned here.
> [vue-simple-portal](https://github.com/LinusBorg/vue-simple-portal#transitions)
_if you really need to apply the `v-if` to portal, check the example in the link above_

But based on the info above, this also works fine:

```vue
<template>
<portal>
<!--
[1] note the v-if is applied to transition not portal.
could also be applied to the component itself
-->
<transition name="fade" appear v-if="open">
<a11y-dialog
:open="open"
v-bind="$attrs"
v-on="$listeners"
#default="slotProps"
>
<!-- your implementation -->
</a11y-dialog>
</transition>
</portal>
</template>
```

## Prevent background scrolling
Before `v0.6.x` the plugin exposed a `preventBackgroundScrolling` boolean prop that basically toggled `overflow:hidden` on body when open/close. It sounds like a reasonable default but:
- it's very very opinionated. Can actually break custom layouts that don't use `body` as their default scroller element.
- also it's fairly known that iOS safari doesn't respond to `overflow:hidden` on body so a more powerful js solution is usually required to make it work.

By these reasons i decided to deprecate this default implementation (which are just a few lines that you can add to your custom wrapper anyways), and replaced it with event emits:

``` vue
<template>
<a11y-dialog
:open="dialogOpen"
@close="dialogOpen = false"
@show="preventScroll(true, $event)"
@hide="preventScroll(false, $event)"
>
<p>This slot content will be rendered wherever the <portal-target> with name 'a11y-dialogs'
is located.</p>
</a11y-dialog>
</template>
```
```js
export default {
data(){
return {
dialogOpen: false
}
},
/**
* Similar to legacy preventBackgroundScrolling implementation
* @param {Boolean} prevent - add/remove style body
* @param {Boolean} hasSiblings - if it's not the only dialog open
*/
preventScroll(prevent, hasSiblings) {
if (hasSiblings) return

if (prevent) document.body.setProperty('overflow', 'hidden')
else document.body.removeProperty('overflow')
}
}
```

So when creating your custom wrapper you can add your own `preventBackgroundScrolling` prop and apply your own custom implementation using events.
Loading