skateside / aria Goto Github PK
View Code? Open in Web Editor NEWA JavaScript WAI-ARIA library
License: MIT License
A JavaScript WAI-ARIA library
License: MIT License
This will require a little research to ensure that this is how states work, but how about a way to interpret the state attribute value as a boolean?
ARIA.asState = function (value) {
return typeof value === "string"
? (/^(?:\s*true\s*)?$/i).test(value)
: typeof value === "boolean"
? value
: (value !== undefined && value !== null);
};
Mainly thinking aloud here ๐
(function (ARIA) {
"use strict";
let observer = Symbol("WAI-ARIA observer");
ARIA.extendHidden({
observer,
addEventListener(element, event, handler) {
element.addEventListener(event, handler);
},
removeEventListener(element, event, handler) {
element.removeEventListener(event, handler);
},
dispatchEvent(element, event, detail = {}) {
element.dispatchEvent(new CustomEvent(event, {
bubbles: true,
cancelable: true,
detail
}));
}
});
ARIA.extend({
makeEventName(attribute) {
return `wai-aria__${ARIA.normalise(attribute)}`;
},
startListening(element) {
if (!element[ARIA.observer]) {
let observer = new MutationObserver(function (mutationsList) {
mutationsList.forEach(function (mutation) {
let {
type,
attributeName,
oldValue
} = mutation;
if (
type === "attributes"
&& attributeName.startsWith("aria-")
) {
ARIA.dispatchEvent(
element,
ARIA.makeEventName(attributeName),
{
value: ARIA.getDOMAttribute(attributeName),
oldValue
}
);
}
});
});
observer.observe(element, {
attributes: true,
attributeOldValue: true
});
element[ARIA.observer] = observer;
}
},
stopListening(element) {
if (element[ARIA.observer]) {
element[ARIA.observer].disconnect();
delete element[ARIA.observer];
}
},
on(element, attributes, handler) {
let list = new ARIA.list(attributes);
ARIA.startListening(element);
list
.toArray(ARIA.makeEventName)
.forEach(function (event) {
ARIA.addEventListener(element, event, handler);
});
},
off(element, attributes, handler) {
let list = new ARIA.list(attributes);
list
.toArray(ARIA.makeEventName)
.forEach(function (event) {
ARIA.removeEventListener(element, event, handler);
});
}
});
}(window.ARIA));
(function (ARIA) {
"use strict";
let preserveState = function (element, value, attribute) {
ARIA.setDOMAttribute(element, attribute, ARIA.asState(value));
};
ARIA.template = {};
ARIA.template.tablist = function (settings) {
ARIA.setRole(settings.tabList, "tablist");
settings.contents.forEach(function ({tab, panel}) {
ARIA.chain(tab)
.setRole("tab")
.makeFocusable()
.set({
controls: panel,
selected: preserveState
});
ARIA.chain(panel)
.setRole("tabpanel")
.makeFocusable()
.set({
labelledby: tab,
hidden: preserveState
});
});
let isSetting = false;
ARIA.on(tab, "selected", function (e) {
if (!isSetting) {
isSetting = true;
ARIA.set(panel, "hidden", !ARIA.asState(e.detail.value));
isSetting = false;
}
});
ARIA.on(panel, "hidden", function (e) {
if (!isSetting) {
isSetting = true;
ARIA.set(tab, "selected", !ARIA.asState(e.detail.value));
isSetting = false;
}
});
};
}(window.ARIA));
There's a couple of places where the library interacts with DOM elements directly. This shouldn't happen.
Fix ARIA.identify
so it doesn't directly interact with the DOM element and make the prefix settable.
ARIA.defaultIdentifyPrefix = "anonymous-element-";
ARIA.identify = function (element, prefix = ARIA.defaultIdentifyPrefix) {
let id = ARIA.getDOMAttribute(element, "id");
if (!id) {
do {
id = `${prefix}${expando}`;
expando += 1;
} while (ARIA.getById(id));
ARIA.setDOMAttribute(element, "id", id);
}
return id;
};
Modify ARIA.startListening
and ARIA.stopListening
so they don't directly interact with a DOM element. Replace ARIA.observer
with ARIA.observerStore
.
ARIA.observerStore = new WeakMap();
ARIA.extend({
startListening(element) {
let store = ARIA.observerStore;
if (!store.has(element)) {
let observer = new MutationObserver(
ARIA.createMutationHandler(element)
);
observer.observe(element, {
attributes: true,
attributeOldValue: true
});
store.set(element, observer);
}
},
stopListening(element) {
let store = ARIA.observerStore;
let observer = store.get(element);
if (observer) {
observer.disconnect();
store.delete(element);
}
}
});
Is it worth having functions that can help with making elements focusable?
// https://stackoverflow.com/q/1599660/557019
ARIA.FOCUSABLE = [
"a[href]",
"button",
"iframe",
"input:not([type=\"hidden\"]):not([type=\"file\"])",
"select",
"textarea",
"[tabindex]",
"[contentEditable=\"true\"]"
]
.map((sel) => `${sel}:not([disabled]):not([hidden]):not([inert])`)
.join(",");
ARIA.is = (element, selector) => element.matches(selector);
ARIA.makeFocusable = function (element) {
if (!ARIA.is(element, ARIA.FOCUSABLE)) {
ARIA.setDOMAttribute(element, "tabindex", -1);
}
};
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.