import React, { ReactNode, useState, useReducer, useLayoutEffect, useRef } from 'react'; import { mount } from '@cypress/react'; import { makePriorityHook } from '../usePriority'; const usePriority = makePriorityHook(); const FocusOnPriority = ( { id, children = null }: { id: string, children?: ReactNode } ) => { const forceUpdate = useReducer(() => [], [])[1] const ref = useRef(null); const hasPriority = usePriority(ref); if (!(hasPriority as any).__marked) { (hasPriority as any).__marked = true; let current = hasPriority.current Object.defineProperty(hasPriority, 'current', { get() { return current; }, set(value) { current = value; forceUpdate(); }, }) } useLayoutEffect(() => { if (hasPriority.current && ref.current) { ref.current!.focus(); } }, [hasPriority.current, ref]); return (
{children}
); }; it('allows sole element to take priority', () => { mount( ); cy.focused().should('have.id', 'only'); }); it('tracks priority of sibling elements in order', () => { mount(
); cy.focused().should('have.id', 'second'); }); it('tracks priority of nested elements in order', () => { mount( ); cy.focused().should('have.id', 'inner'); }); it('should switch priorities of sibling elements as needed', () => { const App = () => { const [visible, setVisible] = useState(true); return (
{visible && }
); }; mount(); cy.focused().should('have.id', 'second'); cy.get('button').first().click(); cy.focused().should('have.id', 'first'); }); it('should switch priorities of nested elements as needed', () => { const App = () => { const [visible, setVisible] = useState(true); return (
{visible && }
); }; mount(); cy.focused().should('have.id', 'inner'); cy.get('button').first().click(); cy.focused().should('have.id', 'outer'); }); it('should preserve priorities when non-prioritised item is removed', () => { const App = () => { const [visible, setVisible] = useState(true); return (
{visible && }
); }; mount(); cy.focused().should('have.id', 'second'); cy.get('button').first().click(); cy.get('button').first().should('have.focus'); }); it('should update priorities when new prioritised item is added', () => { const App = () => { const [visible, setVisible] = useState(false); return (
{visible && }
); }; mount(); cy.focused().should('have.id', 'second'); cy.get('button').first().click(); cy.focused().should('have.id', 'third'); });