Skip to content

Commit

Permalink
chore: use internal aria-hidden impl
Browse files Browse the repository at this point in the history
  • Loading branch information
segunadebayo committed Apr 26, 2022
1 parent 95a187d commit 47250c3
Show file tree
Hide file tree
Showing 10 changed files with 52 additions and 44 deletions.
1 change: 0 additions & 1 deletion examples/vue-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
"@emotion/css",
"@floating-ui/dom",
"@vue/runtime-core",
"aria-hidden",
"epic-spinners",
"focus-trap",
"form-serialize",
Expand Down
3 changes: 2 additions & 1 deletion packages/machines/combobox/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@zag-js/core": "^0.0.0",
"@zag-js/popper": "^0.0.0",
"@zag-js/dom-utils": "^0.0.0",
"@zag-js/aria-hidden": "^0.0.0",
"@zag-js/types": "^0.0.0",
"scroll-into-view-if-needed": "^2.2.28"
},
Expand All @@ -44,4 +45,4 @@
"test:ci": "yarn test --ci --runInBand",
"test:watch": "yarn test --watch --updateSnapshot"
}
}
}
21 changes: 18 additions & 3 deletions packages/machines/combobox/src/combobox.machine.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ariaHidden } from "@zag-js/aria-hidden"
import { createMachine, guards, ref } from "@zag-js/core"
import {
createLiveRegion,
Expand All @@ -22,6 +23,7 @@ export function machine(ctx: UserDefinedContext = {}) {
uid: "",
loop: true,
openOnClick: false,
ariaHidden: true,
activeId: null,
activeOptionData: null,
inputValue: "",
Expand Down Expand Up @@ -165,7 +167,13 @@ export function machine(ctx: UserDefinedContext = {}) {

suggesting: {
tags: ["open", "focused"],
activities: ["trackPointerDown", "scrollOptionIntoView", "computePlacement", "trackOptionNodes"],
activities: [
"trackPointerDown",
"scrollOptionIntoView",
"computePlacement",
"trackOptionNodes",
"ariaHideOutside",
],
entry: ["focusInput", "invokeOnOpen"],
on: {
ARROW_DOWN: {
Expand Down Expand Up @@ -226,7 +234,7 @@ export function machine(ctx: UserDefinedContext = {}) {

interacting: {
tags: ["open", "focused"],
activities: ["scrollOptionIntoView", "trackPointerDown", "computePlacement"],
activities: ["scrollOptionIntoView", "trackPointerDown", "computePlacement", "ariaHideOutside"],
entry: "focusMatchingOption",
on: {
ARROW_DOWN: [
Expand Down Expand Up @@ -319,6 +327,10 @@ export function machine(ctx: UserDefinedContext = {}) {
},

activities: {
ariaHideOutside(ctx) {
if (!ctx.ariaHidden) return
return ariaHidden([dom.getInputEl(ctx), dom.getListboxEl(ctx), dom.getToggleBtnEl(ctx)])
},
computePlacement(ctx) {
return getPlacement(dom.getControlEl(ctx), dom.getPositionerEl(ctx), {
placement: "bottom",
Expand Down Expand Up @@ -367,7 +379,10 @@ export function machine(ctx: UserDefinedContext = {}) {
if (evt.doc) ctx.doc = ref(evt.doc)
ctx.uid = evt.id
nextTick(() => {
ctx.liveRegion = createLiveRegion({ level: "assertive", document: ctx.doc })
ctx.liveRegion = createLiveRegion({
level: "assertive",
document: ctx.doc,
})
})
},
setActiveId(ctx, evt) {
Expand Down
4 changes: 4 additions & 0 deletions packages/machines/combobox/src/combobox.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ type PublicContext = DirectionProperty & {
* Whether to allow custom values or free values in the input
*/
allowCustomValue?: boolean
/**
* Whether to hide all elements besides the combobox parts. Useful for accessibility
*/
ariaHidden?: boolean
/**
* Function called to validate the input value
*/
Expand Down
4 changes: 2 additions & 2 deletions packages/machines/dialog/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"@zag-js/core": "^0.0.0",
"@zag-js/dom-utils": "^0.0.0",
"@zag-js/types": "^0.0.0",
"aria-hidden": "^1.1.3",
"@zag-js/aria-hidden": "^0.0.0",
"focus-trap": "^6.7.1",
"scroll-into-view-if-needed": "^2.2.28"
},
Expand All @@ -45,4 +45,4 @@
"test:ci": "yarn test --ci --runInBand",
"test:watch": "yarn test --watch --updateSnapshot"
}
}
}
9 changes: 3 additions & 6 deletions packages/machines/dialog/src/dialog.machine.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createMachine, guards, ref, subscribe } from "@zag-js/core"
import { addDomEvent, nextTick, preventBodyScroll, trackPointerDown } from "@zag-js/dom-utils"
import { runIfFn } from "@zag-js/utils"
import { hideOthers } from "aria-hidden"
import { ariaHidden } from "@zag-js/aria-hidden"
import { createFocusTrap, FocusTrap } from "focus-trap"
import { dom } from "./dialog.dom"
import { store } from "./dialog.store"
Expand Down Expand Up @@ -126,12 +126,9 @@ export function machine(ctx: UserDefinedContext = {}) {
}
},
hideContentBelow(ctx) {
let unhide: VoidFunction
let unhide: VoidFunction | undefined
nextTick(() => {
const el = dom.getUnderlayEl(ctx)
try {
unhide = hideOthers(el)
} catch {}
unhide = ariaHidden([dom.getUnderlayEl(ctx)])
})
return () => unhide?.()
},
Expand Down
4 changes: 2 additions & 2 deletions packages/machines/popover/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"@zag-js/types": "^0.0.0",
"@zag-js/popper": "^0.0.0",
"@zag-js/utils": "^0.0.0",
"aria-hidden": "^1.1.3",
"@zag-js/aria-hidden": "^0.0.0",
"focus-trap": "^6.7.1"
},
"scripts": {
Expand All @@ -46,4 +46,4 @@
"test:ci": "yarn test --ci --runInBand",
"test:watch": "yarn test --watch --updateSnapshot"
}
}
}
10 changes: 3 additions & 7 deletions packages/machines/popover/src/popover.machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from "@zag-js/dom-utils"
import { getPlacement } from "@zag-js/popper"
import { next, runIfFn } from "@zag-js/utils"
import { hideOthers } from "aria-hidden"
import { ariaHidden } from "@zag-js/aria-hidden"
import { createFocusTrap, FocusTrap } from "focus-trap"
import { dom } from "./popover.dom"
import { MachineContext, MachineState, UserDefinedContext } from "./popover.types"
Expand Down Expand Up @@ -146,13 +146,9 @@ export function machine(ctx: UserDefinedContext = {}) {
},
hideContentBelow(ctx) {
if (!ctx.modal) return
let unhide: VoidFunction
let unhide: VoidFunction | undefined
nextTick(() => {
const el = dom.getContentEl(ctx)
if (!el) return
try {
unhide = hideOthers(el)
} catch {}
unhide = ariaHidden([dom.getContentEl(ctx), dom.getTriggerEl(ctx)])
})
return () => unhide?.()
},
Expand Down
31 changes: 17 additions & 14 deletions packages/utilities/aria-hidden/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
// Credits: https://github.com/adobe/react-spectrum/blob/main/packages/@react-aria/overlays/src/ariaHideOutside.ts

let map = new WeakMap<Element, number>()
const elementCountMap = new WeakMap<Element, number>()

export type AriaHiddenOptions = {
exclude: HTMLElement[]
document: Document
root?: HTMLElement
function isLiveRegion(node: Node, win: typeof window): node is HTMLElement {
return node instanceof win.HTMLElement && node.dataset.liveAnnouncer === "true"
}

export function ariaHidden(options: AriaHiddenOptions) {
const { exclude, document: doc, root = doc.body } = options
export function ariaHidden(targets: Array<HTMLElement | null>, rootEl?: HTMLElement) {
const exclude = targets.filter(Boolean) as HTMLElement[]
if (exclude.length === 0) return

const doc = exclude[0].ownerDocument || document
const win = doc.defaultView ?? window

const visibleNodes = new Set<Element>(exclude)
const hiddenNodes = new Set<Element>()

const root = rootEl ?? doc.body

const walker = doc.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, {
acceptNode(node) {
// If this node is a live announcer, add it to the set of nodes to keep visible.
if (node instanceof win.HTMLElement && node.dataset.liveAnnouncer === "true") {
if (isLiveRegion(node, win)) {
visibleNodes.add(node)
}

Expand All @@ -44,7 +47,7 @@ export function ariaHidden(options: AriaHiddenOptions) {
})

const hide = (node: Element) => {
let refCount = map.get(node) ?? 0
let refCount = elementCountMap.get(node) ?? 0

// If already aria-hidden, and the ref count is zero, then this element
// was already hidden and there's nothing for us to do.
Expand All @@ -57,7 +60,7 @@ export function ariaHidden(options: AriaHiddenOptions) {
}

hiddenNodes.add(node)
map.set(node, refCount + 1)
elementCountMap.set(node, refCount + 1)
}

let node = walker.nextNode() as Element
Expand All @@ -76,7 +79,7 @@ export function ariaHidden(options: AriaHiddenOptions) {
if (![...visibleNodes, ...hiddenNodes].some((node) => node.contains(change.target))) {
//@ts-expect-error
for (const node of change.addedNodes) {
if (node instanceof win.HTMLElement && node.dataset.liveAnnouncer === "true") {
if (isLiveRegion(node, win)) {
visibleNodes.add(node)
} else if (node instanceof win.Element) {
hide(node)
Expand All @@ -92,16 +95,16 @@ export function ariaHidden(options: AriaHiddenOptions) {
observer.disconnect()

for (let node of hiddenNodes) {
let count = map.get(node)
let count = elementCountMap.get(node)

if (count === 1) {
node.removeAttribute("aria-hidden")
map.delete(node)
elementCountMap.delete(node)
continue
}

if (count !== undefined) {
map.set(node, count - 1)
elementCountMap.set(node, count - 1)
}
}
}
Expand Down
9 changes: 1 addition & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2613,13 +2613,6 @@ argparse@^1.0.7:
dependencies:
sprintf-js "~1.0.2"

aria-hidden@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.1.3.tgz#bb48de18dc84787a3c6eee113709c473c64ec254"
integrity sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA==
dependencies:
tslib "^1.0.0"

aria-query@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b"
Expand Down Expand Up @@ -9838,7 +9831,7 @@ [email protected], tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==

tslib@^1.0.0, tslib@^1.8.1:
tslib@^1.8.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
Expand Down

0 comments on commit 47250c3

Please sign in to comment.