Created
September 30, 2018 12:32
-
-
Save Skateside/d595151f253d65739777a55282e606d7 to your computer and use it in GitHub Desktop.
Thinking aloud about a WAI-ARIA library
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
let types = [ | |
[Aria.Property, [ | |
"atomic", | |
]], | |
[Aria.ReferenceCollection, [ | |
"controls", | |
]], | |
[Aria.State, [ | |
"busy", | |
"current", | |
]], | |
[Aria.Collection, [ | |
]], | |
[Aria.Reference, [ | |
]] | |
]; | |
class Aria { | |
constructor(element) { | |
this.element = element; | |
this.controls = new Aria.Collection(this.element, "controls"); | |
} | |
} | |
Object.assign(Aria, { | |
identify() { | |
}, | |
asArray() { | |
}, | |
isNode() { | |
} | |
}); | |
class Aria.Property { | |
constructor(element, attribute) { | |
// Wouldn't it be nicer to have a single MutationObserver listening for | |
// all WAI-ARIA attribute changes? | |
let observer = new MutationObserver((mutations) => { | |
mutations.forEach((mutation) => { | |
if ( | |
mutation.type === "attributes" | |
&& mutation.attributeName === this.attribute | |
) { | |
this.property.set( | |
element.getAttribute(mutation.attributeName) | |
); | |
} | |
}); | |
}); | |
observer.observe(element, { | |
attributes: true | |
}); | |
this.observer = observer; | |
this.attribute = this.normalise(attribute); | |
this.set(this.getAttribute()); | |
} | |
stopObserving() { | |
this.observer.disconnect(); | |
} | |
normalise(attribute) { | |
let normal = String(attribute).toLowerCase(); | |
if (!normal.startsWith("aria-")) { | |
normal = `aria-${normal}`; | |
} | |
return normal; | |
} | |
interpret(value) { | |
return value; | |
} | |
set(value) { | |
this.setAttribute(this.interpret(value)); | |
} | |
get() { | |
return this.getAttribute(); | |
} | |
has() { | |
return this.hasAttribute(); | |
} | |
remove() { | |
return this.removeAttribute(); | |
} | |
setAttribute(value) { | |
if (!this.isSetting) { | |
this.isSetting = true; | |
if (value) { | |
this.element.setAttribute(this.attribute, value); | |
} else { | |
this.removeAttribute(); | |
} | |
this.isSetting = false; | |
} | |
} | |
getAttribute() { | |
return this.element.getAttribute(this.attribute); | |
} | |
hasAttribute() { | |
return this.element.hasAttribute(this.attribute); | |
} | |
removeAttribute() { | |
this.element.removeAttribute(this.attribute); | |
} | |
} | |
class Aria.State extends Aria.Property { | |
interpret(value) { | |
return ( | |
value === "mixed" | |
? value | |
: value === "true" | |
); | |
} | |
} | |
// Aria.List | |
// https://github.com/Skateside/aria/blob/upgrade/v2/src/util.js#L64 | |
class Aria.Collection extends Aria.Property { | |
constructor(element, attribute) { | |
super(element, attribute); | |
this.list = new Aria.List(this.getAttribute()); | |
} | |
set(value) { | |
this.list.forEach((value) => this.list.remove(value)); | |
this.list.add(Aria.asArray(value)); | |
} | |
add(...values) { | |
this.list.add(...values.map((value) => this.interpret(value))); | |
this.setAttribute(this.list); | |
} | |
remove(...values) { | |
this.list.remove(...values.map((value) => this.interpret(value))); | |
this.setAttribute(this.list); | |
} | |
constains(value) { | |
return this.list.contains(this.interpret(value)); | |
} | |
} | |
class Aria.Reference extends Aria.Property { | |
interpret(value) { | |
return Aria.Reference.interpret(value); | |
}, | |
getRef() { | |
return document.getElementById(this.get()); | |
} | |
} | |
Aria.Reference.interpret = function (value) { | |
return ( | |
Aria.isNode(value) | |
? Aria.identify(value) | |
: value | |
); | |
}; | |
class Aria.ReferenceCollection extends Aria.Collection { | |
interpret(value) { | |
return Aria.Reference.interpret(value); | |
} | |
} | |
// https://github.com/LeaVerou/bliss/issues/49 | |
Object.defineProperty(Node.prototype, "aria", { | |
configurable: true, | |
get: function getter() { | |
Object.defineProperty(Node.prototype, "aria", { | |
get: undefined | |
}); | |
Object.defineProperty(this, "aria", { | |
get: new Aria(this) | |
}); | |
Object.defineProperty(Node.prototype, "aria", { | |
get: getter | |
}); | |
return this.aria; | |
} | |
}); | |
element.aria.controls.add(button); | |
button.aria.role.add("button"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Playing with lists and references.