Skip to content

Commit

Permalink
feat(react-aria): active descendants imperative handle to toggle attr…
Browse files Browse the repository at this point in the history
…ibute visibility
  • Loading branch information
bsunderhus committed Mar 5, 2024
1 parent 931d37d commit e53fe69
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "feat: active descendants imperative handle to toggle attribute",
"packageName": "@fluentui/react-aria",
"email": "[email protected]",
"dependentChangeType": "patch"
}
4 changes: 4 additions & 0 deletions packages/react-components/react-aria/etc/react-aria.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,15 @@ export interface ActiveDescendantImperativeRef {
// (undocumented)
focus: (id: string) => void;
// (undocumented)
hideAttributes: () => void;
// (undocumented)
last: (options?: IteratorOptions) => string | undefined;
// (undocumented)
next: (options?: IteratorOptions) => string | undefined;
// (undocumented)
prev: (options?: IteratorOptions) => string | undefined;
// (undocumented)
showAttributes: () => void;
}

// @public (undocumented)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const activeDescendantContextDefaultValue: ActiveDescendantContextValue = {
last: noop,
next: noop,
prev: noop,
showAttributes: noop,
hideAttributes: noop,
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export interface ActiveDescendantImperativeRef {
blur: () => void;
active: () => string | undefined;
focus: (id: string) => void;
hideAttributes: () => void;
showAttributes: () => void;
}

export interface ActiveDescendantOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ export function useActiveDescendant<TActiveParentElement extends HTMLElement, TL
const focusVisibleRef = React.useRef(false);
const activeIdRef = React.useRef<string | null>(null);
const activeParentRef = React.useRef<TActiveParentElement>(null);
const attributeVisibilityRef = React.useRef(true);

const removeAttribute = React.useCallback(() => {
activeParentRef.current?.removeAttribute('aria-activedescendant');
}, []);
const setAttribute = React.useCallback((id?: string) => {
if (id) {
activeIdRef.current = id;
}
if (attributeVisibilityRef.current && activeIdRef.current) {
activeParentRef.current?.setAttribute('aria-activedescendant', activeIdRef.current);
}
}, []);

useOnKeyboardNavigationChange(isNavigatingWithKeyboard => {
focusVisibleRef.current = isNavigatingWithKeyboard;
Expand Down Expand Up @@ -42,9 +55,9 @@ export function useActiveDescendant<TActiveParentElement extends HTMLElement, TL
active.removeAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE);
}

activeParentRef.current?.removeAttribute('aria-activedescendant');
removeAttribute();
activeIdRef.current = null;
}, [activeParentRef, getActiveDescendant]);
}, [getActiveDescendant, removeAttribute]);

const focusActiveDescendant = React.useCallback(
(nextActive: HTMLElement | null) => {
Expand All @@ -55,15 +68,14 @@ export function useActiveDescendant<TActiveParentElement extends HTMLElement, TL
blurActiveDescendant();

scrollIntoView(nextActive, listboxRef.current);
activeParentRef.current?.setAttribute('aria-activedescendant', nextActive.id);
activeIdRef.current = nextActive.id;
setAttribute(nextActive.id);
nextActive.setAttribute(ACTIVEDESCENDANT_ATTRIBUTE, '');

if (focusVisibleRef.current) {
nextActive.setAttribute(ACTIVEDESCENDANT_FOCUSVISIBLE_ATTRIBUTE, '');
}
},
[activeParentRef, listboxRef, blurActiveDescendant],
[listboxRef, blurActiveDescendant, setAttribute],
);

const controller: ActiveDescendantImperativeRef = React.useMemo(
Expand Down Expand Up @@ -139,8 +151,24 @@ export function useActiveDescendant<TActiveParentElement extends HTMLElement, TL

return target?.id;
},
showAttributes() {
attributeVisibilityRef.current = true;
setAttribute();
},
hideAttributes() {
attributeVisibilityRef.current = false;
removeAttribute();
},
}),
[optionWalker, listboxRef, focusActiveDescendant, blurActiveDescendant, getActiveDescendant],
[
optionWalker,
listboxRef,
setAttribute,
removeAttribute,
focusActiveDescendant,
blurActiveDescendant,
getActiveDescendant,
],
);

React.useImperativeHandle(imperativeRef, () => controller);
Expand Down

0 comments on commit e53fe69

Please sign in to comment.