-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
270 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
const onInitialize = Symbol('onInitialize'); | ||
const onDestroy = Symbol('onDestroy'); | ||
const announceEvent = Symbol('announceEvent'); | ||
const announceMessage = Symbol('announceMessage'); | ||
|
||
const ARIA_RELEVANT = 'aria-relevant'; | ||
const ARIA_ATOMIC = 'aria-atomic'; | ||
const ARIA_LIVE = 'aria-live'; | ||
const ROLE = 'role'; | ||
|
||
export const defaultOptions = { | ||
expire: 7000, | ||
'drag:start': 'Picked up draggable element', | ||
'drag:stop': 'Dropped draggable element', | ||
}; | ||
|
||
/** | ||
* Announcement plugin | ||
* @class Announcement | ||
* @module Announcement | ||
*/ | ||
export default class Announcement { | ||
|
||
/** | ||
* Announcement constructor. | ||
* @constructs Announcement | ||
* @param {Draggable} draggable - Draggable instance | ||
*/ | ||
constructor(draggable) { | ||
|
||
/** | ||
* Draggable instance | ||
* @property draggable | ||
* @type {Draggable} | ||
*/ | ||
this.draggable = draggable; | ||
|
||
/** | ||
* Plugin options | ||
* @property options | ||
* @type {Object} | ||
*/ | ||
this.options = { | ||
...defaultOptions, | ||
...this.getOptions(), | ||
}; | ||
|
||
/** | ||
* Original draggable trigger method. Hack until we have onAll or on('all') | ||
* @property originalTriggerMethod | ||
* @type {Function} | ||
*/ | ||
this.originalTriggerMethod = this.draggable.trigger; | ||
|
||
/** | ||
* Live region element | ||
* @property liveRegion | ||
* @type {HTMLElement} | ||
*/ | ||
this.liveRegion = createRegion(); | ||
|
||
this[onInitialize] = this[onInitialize].bind(this); | ||
this[onDestroy] = this[onDestroy].bind(this); | ||
} | ||
|
||
/** | ||
* Attaches listeners to draggable | ||
*/ | ||
attach() { | ||
this.draggable | ||
.on('draggable:initialize', this[onInitialize]); | ||
} | ||
|
||
/** | ||
* Detaches listeners from draggable | ||
*/ | ||
detach() { | ||
this.draggable | ||
.off('draggable:destroy', this[onDestroy]); | ||
} | ||
|
||
/** | ||
* Returns passed in options | ||
*/ | ||
getOptions() { | ||
return this.draggable.options.announcements || {}; | ||
} | ||
|
||
/** | ||
* Announces event | ||
* @private | ||
* @param {AbstractEvent} event | ||
*/ | ||
[announceEvent](event) { | ||
const message = this.options[event.type]; | ||
|
||
if (message && (typeof message === 'string')) { | ||
this[announceMessage](message); | ||
} | ||
|
||
if (message && (typeof message === 'function')) { | ||
this[announceMessage](message(event)); | ||
} | ||
} | ||
|
||
/** | ||
* Announces message to screen reader | ||
* @private | ||
* @param {String} message | ||
*/ | ||
[announceMessage](message) { | ||
const element = document.createElement('div'); | ||
element.innerHTML = message; | ||
this.liveRegion.appendChild(element); | ||
return setTimeout(() => { | ||
this.liveRegion.removeChild(element); | ||
}, this.options.expire); | ||
} | ||
|
||
/** | ||
* Initialize hander | ||
* @private | ||
*/ | ||
[onInitialize]() { | ||
this.draggable.trigger = (event) => { | ||
this[announceEvent](event); | ||
this.originalTriggerMethod.call(this.draggable, event); | ||
}; | ||
|
||
document.body.appendChild(this.liveRegion); | ||
} | ||
|
||
/** | ||
* Destroy hander | ||
* @private | ||
*/ | ||
[onDestroy]() { | ||
this.draggable.trigger = this.originalTriggerMethod; | ||
document.body.removeChild(this.liveRegion); | ||
} | ||
} | ||
|
||
/** | ||
* Creates region element | ||
* @return {HTMLElement} | ||
*/ | ||
function createRegion() { | ||
const element = document.createElement('div'); | ||
|
||
element.setAttribute(ARIA_RELEVANT, 'additions'); | ||
element.setAttribute(ARIA_ATOMIC, 'false'); | ||
element.setAttribute(ARIA_LIVE, 'assertive'); | ||
element.setAttribute(ROLE, 'status'); | ||
|
||
element.style.position = 'fixed'; | ||
element.style.width = '1px'; | ||
element.style.height = '1px'; | ||
element.style.top = '-1px'; | ||
element.style.overflow = 'hidden'; | ||
|
||
return element; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
## Announcement | ||
|
||
The Announcement plugin listens to _all_ draggable events and allows you to define announcements via options for events | ||
that are read back through a screen reader. | ||
|
||
### API | ||
|
||
**`new Announcement(draggable: Draggable): Announcement`** | ||
To create an announcement plugin instance. | ||
|
||
### Options | ||
|
||
**`expire {Number}`** | ||
How long messages should stay inside the live region (in milliseconds). Default: `7000` | ||
|
||
**`'drag:start' {String|Function:String}`** | ||
Define an announcement on `drag:start`. Default: `Picked up draggable element` | ||
|
||
**`'drag:stop' {String|Function:String}`** | ||
Define an announcement on `drag:stop`. Default: `Dropped draggable element` | ||
|
||
**`'sortable:sorted' {String|Function:String}`** | ||
Define an announcement on `sortable:sorted`. No default | ||
|
||
**`'swappable:swapped' {String|Function:String}`** | ||
Define an announcement on `swappable:swapped`. No default | ||
|
||
**`'droppable:dropped' {String|Function:String}`** | ||
Define an announcement on `droppable:dropped`. No default | ||
|
||
_And any other events you can think of..._ | ||
|
||
### Examples | ||
|
||
#### Static messages | ||
|
||
```js | ||
import {Sortable} from '@shopify/draggable'; | ||
|
||
const announcements = { | ||
'drag:start': 'Draggable element picked up', | ||
'drag:stop': 'Draggable element dropped', | ||
'sortable:stopped': 'Draggable elements swapped', | ||
} | ||
|
||
const sortable = new Sortable(document.querySelectorAll('ul'), { | ||
draggable: 'li', | ||
announcements, | ||
}); | ||
``` | ||
|
||
#### Dynamic messages | ||
|
||
```js | ||
import {Sortable} from '@shopify/draggable'; | ||
|
||
const announcements = { | ||
'drag:start': (dragEvent) => { | ||
return `Picked up ${dragEvent.source.getAttribute('data-name')}`; | ||
}, | ||
|
||
'drag:stop': (dragEvent) => { | ||
return `Dropped ${dragEvent.source.getAttribute('data-name')}` | ||
}, | ||
|
||
'sortable:sorted': (sortableEvent) => { | ||
return `Sorted ${sortableEvent.dragEvent.source.getAttribute('data-name')} with ${sortableEvent.dragEvent.over.getAttribute('data-name')}`; | ||
}, | ||
} | ||
|
||
const sortable = new Sortable(document.querySelectorAll('ul'), { | ||
draggable: 'li', | ||
announcements, | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import Announcement, {defaultOptions} from './Announcement'; | ||
|
||
export default Announcement; | ||
export {defaultOptions}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,4 @@ | ||
import Mirror, {defaultOptions} from './Mirror'; | ||
|
||
export default Mirror; | ||
export { | ||
defaultOptions as defaultMirrorOption, | ||
}; | ||
export {defaultOptions}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,13 @@ | ||
import Mirror, {defaultMirrorOption} from './Mirror'; | ||
import Accessibility from './Accessibility'; | ||
export { | ||
default as Announcement, | ||
defaultOptions as defaultAnnouncementOptions, | ||
} from './Announcement'; | ||
|
||
export { | ||
default as Mirror, | ||
defaultOptions as defaultMirrorOptions, | ||
} from './Mirror'; | ||
|
||
export { | ||
Mirror, | ||
defaultMirrorOption, | ||
Accessibility, | ||
}; | ||
default as Accessibility, | ||
} from './Accessibility'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters