Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
xxRockOnxx committed Feb 14, 2022
0 parents commit d007007
Show file tree
Hide file tree
Showing 9 changed files with 24,688 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.DS_Store
node_modules/
dist/

# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# vue-aria-focus-trap

A Vue.js component that implements WAI-ARIA focus trapping.

Inspired from [ARIA 1.2 Modal Dialog example](https://www.w3.org/TR/wai-aria-practices-1.2/examples/dialog-modal/dialog.html).

## Installation

```
# npm
npm install vue-aria-focus-trap
# Yarn
yarn add vue-aria-focus-trap
```

## Example

Check out the simple example application in the `dev` folder. [Link](./dev/App.vue).

## Contributing

Feel free opening Issues or Pull Requests. I'll check them out **whenever** I can.
16 changes: 16 additions & 0 deletions build/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import commonjs from "@rollup/plugin-commonjs"; // Convert CommonJS modules to ES6
import vue from "rollup-plugin-vue"; // Handle .vue SFC files

export default {
input: "src/index.js", // Path relative to package.json
output: {
name: "FocusTrap",
exports: "named",
},
plugins: [
vue({
compileTemplate: true, // Explicitly convert template to render function
}),
commonjs(),
],
};
231 changes: 231 additions & 0 deletions dev/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
<template>
<div>
<button
ref="trigger"
type="button"
@click="openDialog"
>
Add Delivery Address
</button>

<p style="margin-top: 16px;">
This component <b>only</b> handles the trapping of focus.<br/>
Unlike the example from the w3.org website, it doesn not handle:

<ul style="margin-top: 16px;">
<li>What child element to focus on open</li>
<li>Focusing of trigger element on close</li>
</ul>
</p>

<p>
<span>Source:</span>

<a href="https://www.w3.org/TR/wai-aria-practices-1.2/examples/dialog-modal/dialog.html">
https://www.w3.org/TR/wai-aria-practices-1.2/examples/dialog-modal/dialog.html
</a>
</p>

<FocusTrap
v-show="open"
id="dialog1"
role="dialog"
aria-labelledby="dialog1_label"
aria-modal="true"
>
<h2 id="dialog1_label" class="dialog_label">Add Delivery Address</h2>

<div class="dialog_form">
<div class="dialog_form_item">
<label>
<span class="label_text">Street:</span>
<input ref="input" type="text" class="wide_input" />
</label>
</div>

<div class="dialog_form_item">
<label>
<span class="label_text">City:</span>
<input type="text" class="city_input" />
</label>
</div>

<div class="dialog_form_item">
<label>
<span class="label_text">State:</span>
<input type="text" class="state_input" />
</label>
</div>

<div class="dialog_form_item">
<label>
<span class="label_text">Zip:</span>
<input type="text" class="zip_input" />
</label>
</div>

<div class="dialog_form_item">
<label for="special_instructions">
<span class="label_text">Special instructions:</span>
</label>
<input
id="special_instructions"
type="text"
aria-describedby="special_instructions_desc"
class="wide_input"
/>
<div class="label_info" id="special_instructions_desc">
For example, gate code or other information to help the driver find you
</div>
</div>
</div>

<div class="dialog_form_actions">
<button
type="button"
@click="closeDialog"
>
Cancel
</button>
</div>
</FocusTrap>
</div>
</template>

<script>
import FocusTrap from '../src';
export default {
components: {
FocusTrap,
},
data() {
return {
open: false,
}
},
methods: {
openDialog() {
this.open = true;
this.$nextTick(() => {
this.$refs.input.focus();
});
},
closeDialog() {
this.open = false;
this.$nextTick(() => {
this.$refs.trigger.focus();
});
}
}
}
</script>

<style>
@import "https://unpkg.com/sakura.css/css/sakura.css";
.hidden {
display: none;
}
label {
display: inline;
}
[role="dialog"] {
box-sizing: border-box;
padding: 15px;
border: 1px solid #000;
background-color: #fff;
min-height: 100vh;
}
@media screen and (min-width: 640px) {
[role="dialog"] {
position: absolute;
top: 2rem;
left: 50vw; /* move to the middle of the screen (assumes relative parent is the body/viewport) */
transform: translateX(
-50%
); /* move backwards 50% of this element's width */
min-width: calc(640px - (15px * 2)); /* == breakpoint - left+right margin */
min-height: auto;
box-shadow: 0 19px 38px rgb(0 0 0 / 12%), 0 15px 12px rgb(0 0 0 / 22%);
}
}
.dialog_label {
text-align: center;
}
.dialog_form {
margin: 15px;
}
.dialog_form .label_text {
box-sizing: border-box;
padding-right: 0.5em;
display: inline-block;
font-size: 16px;
font-weight: bold;
width: 30%;
text-align: right;
}
.dialog_form .label_info {
box-sizing: border-box;
padding-right: 0.5em;
font-size: 12px;
width: 30%;
text-align: right;
display: inline-block;
}
.dialog_form_item {
margin: 10px 0;
font-size: 0;
}
.dialog_form_item .wide_input {
box-sizing: border-box;
max-width: 70%;
width: 27em;
}
.dialog_form_item .city_input {
box-sizing: border-box;
max-width: 70%;
width: 17em;
}
.dialog_form_item .state_input {
box-sizing: border-box;
max-width: 70%;
width: 15em;
}
.dialog_form_item .zip_input {
box-sizing: border-box;
max-width: 70%;
width: 9em;
}
.dialog_form_actions {
text-align: right;
padding: 0 20px 20px;
}
.dialog_close_button {
float: right;
position: absolute;
top: 10px;
left: 92%;
height: 25px;
}
</style>
10 changes: 10 additions & 0 deletions dev/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Vue from "vue";
import App from "./App.vue";

Vue.config.productionTip = false;

const app = new Vue({
render: (h) => h(App),
});

app.$mount('#app');
Loading

0 comments on commit d007007

Please sign in to comment.