Skip to content

Commit

Permalink
feat: add track markers
Browse files Browse the repository at this point in the history
  • Loading branch information
theKashey committed Mar 7, 2019
1 parent 51affc3 commit 34c34c2
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 23 deletions.
13 changes: 13 additions & 0 deletions __tests__/__snapshots__/index.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Specs hides cross 1`] = `"<div><div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\">hide me 1</div><div>not me 2</div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\"><div>not me 3</div></div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\">hide me 4</div><div aria-hidden=\\"true\\" data-aria-hidden=\\"true\\">I am already hidden! 5</div></div><div>dont touch me 6</div></div>"`;
exports[`Specs hides cross 2`] = `"<div><div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\">hide me 1</div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\">not me 2</div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\"><div>not me 3</div></div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\">hide me 4</div><div aria-hidden=\\"true\\" data-aria-hidden=\\"true\\">I am already hidden! 5</div></div><div>dont touch me 6</div></div>"`;
exports[`Specs hides cross 3`] = `"<div><div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\">hide me 1</div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\">not me 2</div><div><div>not me 3</div></div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\">hide me 4</div><div aria-hidden=\\"true\\" data-aria-hidden=\\"true\\">I am already hidden! 5</div></div><div>dont touch me 6</div></div>"`;
exports[`Specs hides cross markers 1`] = `"<div><div><div aria-hidden=\\"true\\" marker2=\\"true\\">hide me 1</div><div marker2=\\"true\\" aria-hidden=\\"true\\">not me 2</div><div><div>not me 3</div></div><div aria-hidden=\\"true\\" marker2=\\"true\\">hide me 4</div><div aria-hidden=\\"true\\" marker2=\\"true\\">I am already hidden! 5</div></div><div>dont touch me 6</div></div>"`;
exports[`Specs hides multiple 1`] = `"<div><div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\">hide me 1</div><div>not me 2</div><div><div>not me 3</div></div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\">hide me 4</div><div aria-hidden=\\"true\\" data-aria-hidden=\\"true\\">I am already hidden! 5</div></div><div>dont touch me 6</div></div>"`;
exports[`Specs hides single 1`] = `"<div><div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\">hide me 1</div><div>not me 2</div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\"><div>not me 3</div></div><div data-aria-hidden=\\"true\\" aria-hidden=\\"true\\">hide me 4</div><div aria-hidden=\\"true\\" data-aria-hidden=\\"true\\">I am already hidden! 5</div></div><div>dont touch me 6</div></div>"`;
132 changes: 125 additions & 7 deletions __tests__/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,132 @@
import * as React from 'react';
import {shallow} from 'enzyme';
import {mount} from 'enzyme';
import {hideOthers} from "../src";

describe('Specs', () => {
const setup = () => {
const factory = () => {
const parent = React.createRef<any>();
const target1 = React.createRef<any>();
const target2 = React.createRef<any>();
const targetOutside1 = React.createRef<any>();
const wrapper = mount(
<div>
<div ref={parent}>
<div>hide me 1</div>
<div ref={target1}>not me 2</div>
<div>
<div ref={target2}>not me 3</div>
</div>
<div ref={targetOutside1}>hide me 4</div>
<div aria-hidden>I am already hidden! 5</div>
</div>
<div>dont touch me 6</div>
</div>
);
const base = wrapper.html();

return {

};
base, wrapper,
parent, target1, target2, targetOutside1,
}
};

it('Foo', () => {
expect(1).toEqual(1);

const getNearestAttribute = (node, name, parent) => {
const attr = node.getAttribute(name);
if (attr) {
return attr;
}
if (node === parent || !node.parentNode) {
return null;
}
return getNearestAttribute(node.parentNode, name, parent)
}

it('hides single', () => {
const {
base, parent, target1, target2, targetOutside1, wrapper
} = factory();

const unhide = hideOthers(target1.current, parent.current);
expect(wrapper.update().html()).toMatchSnapshot();

expect(getNearestAttribute(target1.current, 'aria-hidden', parent)).toBe(null);
expect(getNearestAttribute(target2.current, 'aria-hidden', parent)).toBe("true");
expect(getNearestAttribute(targetOutside1.current, 'aria-hidden', parent)).toBe("true");

unhide();
expect(wrapper.html()).toEqual(base);
});

it('hides multiple', () => {
const {
base, parent, target1, target2, targetOutside1, wrapper
} = factory();

const unhide = hideOthers([target1.current, target2.current], parent.current);
expect(wrapper.html()).toMatchSnapshot();

expect(getNearestAttribute(target1.current, 'aria-hidden', parent)).toBe(null);
expect(getNearestAttribute(target2.current, 'aria-hidden', parent)).toBe(null);
expect(getNearestAttribute(targetOutside1.current, 'aria-hidden', parent)).toBe("true");

unhide();
expect(wrapper.html()).toEqual(base);
});

it('hides cross', () => {
const {
base, parent, target1, target2, targetOutside1, wrapper
} = factory();

const unhide1 = hideOthers(target1.current, parent.current);
expect(wrapper.html()).toMatchSnapshot();

expect(getNearestAttribute(target1.current, 'aria-hidden', parent)).toBe(null);
expect(getNearestAttribute(target2.current, 'aria-hidden', parent)).toBe("true");
expect(getNearestAttribute(targetOutside1.current, 'aria-hidden', parent)).toBe("true");
expect(getNearestAttribute(targetOutside1.current, 'data-aria-hidden', parent)).toBe("true");

const unhide2 = hideOthers(target2.current, parent.current);

expect(getNearestAttribute(target1.current, 'aria-hidden', parent)).toBe("true");
expect(getNearestAttribute(target2.current, 'aria-hidden', parent)).toBe("true");
expect(getNearestAttribute(targetOutside1.current, 'aria-hidden', parent)).toBe("true");
expect(getNearestAttribute(targetOutside1.current, 'data-aria-hidden', parent)).toBe("true");

expect(wrapper.html()).toMatchSnapshot();
unhide1();

expect(getNearestAttribute(target1.current, 'aria-hidden', parent)).toBe("true");
expect(getNearestAttribute(target2.current, 'aria-hidden', parent)).toBe(null);
expect(getNearestAttribute(targetOutside1.current, 'aria-hidden', parent)).toBe("true");
expect(getNearestAttribute(targetOutside1.current, 'data-aria-hidden', parent)).toBe("true");

expect(wrapper.html()).toMatchSnapshot();
unhide2();

expect(wrapper.html()).toEqual(base)
});

it('hides cross markers', () => {
const {
base, parent, target1, target2, targetOutside1, wrapper
} = factory();

const unhide1 = hideOthers(target1.current, parent.current, 'marker1');
expect(getNearestAttribute(targetOutside1.current, 'marker1', parent)).toBe("true");

const unhide2 = hideOthers(target2.current, parent.current, 'marker2');

expect(getNearestAttribute(targetOutside1.current, 'marker1', parent)).toBe("true");
expect(getNearestAttribute(targetOutside1.current, 'marker2', parent)).toBe("true");

unhide1();

expect(getNearestAttribute(targetOutside1.current, 'marker1', parent)).toBe(null);

expect(wrapper.html()).toMatchSnapshot();
unhide2();

expect(wrapper.html()).toEqual(base)
});
});
12 changes: 10 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,18 @@
"files": [
"dist"
],
"keywords": ["DOM", "aria", "hidden", "inert"],
"keywords": [
"DOM",
"aria",
"hidden",
"inert"
],
"homepage": "https://github.com/theKashey/aria-hidden#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/theKashey/aria-hidden.git"
},
"dependencies": {
"tslib": "^1.0.0"
}
}
}
73 changes: 60 additions & 13 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,84 @@ export type Undo = () => void;

const defaultParent = typeof document !== 'undefined' ? document.body : null;

export const hideOthers = (target: HTMLElement, parentNode = defaultParent): Undo => {
const originalValues = new Map();
let counterMap = new WeakMap<HTMLElement, number>();
let uncontrolledNodes = new WeakMap<HTMLElement, boolean>();
let markerMap: Record<string, WeakMap<HTMLElement, number>> = {};
let lockCount = 0;

export const hideOthers = (originalTarget: HTMLElement | HTMLElement[], parentNode = defaultParent, markerName = "data-aria-hidden"): Undo => {
const targets = Array.isArray(originalTarget) ? originalTarget : [originalTarget];

if (!markerMap[markerName]) {
markerMap[markerName] = new WeakMap();
}
const markerCounter = markerMap[markerName];
const hiddenNodes: HTMLElement[] = [];

const deep = (parent: HTMLElement | null) => {
if (!parent || parent === target) {
return;
}

Array.prototype.forEach.call(parent.children, (node: HTMLElement) => {
if (node.contains(target)) {
if (targets.some(target => node.contains(target))) {
deep(node);
} else {
const attr = node.getAttribute('aria-hidden');
const alreadyHidden = attr !== null && attr !== 'false';
if (alreadyHidden) {
return
const counterValue = (counterMap.get(node) || 0) + 1;
const markerValue = (markerCounter.get(node) || 0) + 1;

counterMap.set(node, counterValue);
markerCounter.set(node, markerValue);
hiddenNodes.push(node);

if (counterValue === 1 && alreadyHidden) {
uncontrolledNodes.set(node, true);
}

if (markerValue === 1) {
node.setAttribute(markerName, 'true');
}

if (!alreadyHidden) {
node.setAttribute('aria-hidden', 'true')
}
originalValues.set(node, attr);
node.setAttribute('aria-hidden', 'true')
}
})
};

deep(parentNode);

lockCount++;

return () => {
originalValues.forEach((hiddenAttr, node) => {
if (hiddenAttr === null) {
node.removeAttribute('aria-hidden')
} else {
node.setAttribute('aria-hidden', hiddenAttr)
hiddenNodes.forEach(node => {
const counterValue = counterMap.get(node) - 1;
const markerValue = markerCounter.get(node) - 1;

counterMap.set(node, counterValue);
markerCounter.set(node, markerValue);

if (!counterValue) {
if (!uncontrolledNodes.has(node)) {
node.removeAttribute('aria-hidden')
}
uncontrolledNodes.delete(node)
}
})

if (!markerValue) {
node.removeAttribute(markerName);
}
});

lockCount--;
if (!lockCount) {
// clear
counterMap = new WeakMap();
counterMap = new WeakMap();
uncontrolledNodes = new WeakMap();
markerMap = {};
}
}
};
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8549,7 +8549,7 @@ ts-react-toolbox@^0.1.22:
webpack-cli "^2.1.3"
webpack-dev-server "^3.1.1"

tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0:
tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==
Expand Down

0 comments on commit 34c34c2

Please sign in to comment.