UNPKG

@wordpress/compose

Version:
8 lines (7 loc) 3.6 kB
{ "version": 3, "sources": ["../../../src/hooks/use-focus-return/index.ts"], "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useRef, useEffect, useCallback } from '@wordpress/element';\n\nlet origin: Element | null = null;\n\n/**\n * Adds the unmount behavior of returning focus to the element which had it\n * previously as is expected for roles like menus or dialogs.\n *\n * @param onFocusReturn Overrides the default return behavior.\n * @return Element Ref.\n *\n * @example\n * ```ts\n * import { useFocusReturn } from '@wordpress/compose';\n *\n * const WithFocusReturn = () => {\n * const ref = useFocusReturn()\n * return (\n * <div ref={ ref }>\n * <Button />\n * <Button />\n * </div>\n * );\n * }\n * ```\n */\nfunction useFocusReturn(\n\tonFocusReturn?: () => void\n): React.RefCallback< HTMLElement > {\n\tconst ref = useRef< HTMLElement | null >( null );\n\tconst focusedBeforeMountRef = useRef< Element | null >( null );\n\tconst onFocusReturnRef = useRef< ( () => void ) | undefined >(\n\t\tonFocusReturn\n\t);\n\n\tuseEffect( () => {\n\t\tonFocusReturnRef.current = onFocusReturn;\n\t}, [ onFocusReturn ] );\n\n\treturn useCallback( ( node: HTMLElement | null ) => {\n\t\tif ( node ) {\n\t\t\t// Set ref to be used when unmounting.\n\t\t\tref.current = node;\n\n\t\t\t// Only set when the node mounts.\n\t\t\tif ( focusedBeforeMountRef.current ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst activeDocument =\n\t\t\t\tnode.ownerDocument.activeElement instanceof\n\t\t\t\twindow.HTMLIFrameElement\n\t\t\t\t\t? node.ownerDocument.activeElement.contentDocument\n\t\t\t\t\t: node.ownerDocument;\n\n\t\t\tfocusedBeforeMountRef.current =\n\t\t\t\tactiveDocument?.activeElement ?? null;\n\t\t} else if ( focusedBeforeMountRef.current ) {\n\t\t\tconst isFocused = ref.current?.contains(\n\t\t\t\tref.current?.ownerDocument.activeElement ?? null\n\t\t\t);\n\n\t\t\tif ( ref.current?.isConnected && ! isFocused ) {\n\t\t\t\torigin ??= focusedBeforeMountRef.current;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Defer to the component's own explicit focus return behavior, if\n\t\t\t// specified. This allows for support that the `onFocusReturn`\n\t\t\t// decides to allow the default behavior to occur under some\n\t\t\t// conditions.\n\t\t\tif ( onFocusReturnRef.current ) {\n\t\t\t\tonFocusReturnRef.current();\n\t\t\t} else {\n\t\t\t\tconst elementToFocus = (\n\t\t\t\t\t! focusedBeforeMountRef.current.isConnected\n\t\t\t\t\t\t? origin\n\t\t\t\t\t\t: focusedBeforeMountRef.current\n\t\t\t\t) as HTMLElement | SVGElement | null;\n\n\t\t\t\telementToFocus?.focus();\n\t\t\t}\n\t\t\torigin = null;\n\t\t}\n\t}, [] );\n}\n\nexport default useFocusReturn;\n"], "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAA+C;AAE/C,IAAI,SAAyB;AAwB7B,SAAS,eACR,eACmC;AACnC,QAAM,UAAM,uBAA8B,IAAK;AAC/C,QAAM,4BAAwB,uBAA0B,IAAK;AAC7D,QAAM,uBAAmB;AAAA,IACxB;AAAA,EACD;AAEA,gCAAW,MAAM;AAChB,qBAAiB,UAAU;AAAA,EAC5B,GAAG,CAAE,aAAc,CAAE;AAErB,aAAO,4BAAa,CAAE,SAA8B;AACnD,QAAK,MAAO;AAEX,UAAI,UAAU;AAGd,UAAK,sBAAsB,SAAU;AACpC;AAAA,MACD;AAEA,YAAM,iBACL,KAAK,cAAc,yBACnB,OAAO,oBACJ,KAAK,cAAc,cAAc,kBACjC,KAAK;AAET,4BAAsB,UACrB,gBAAgB,iBAAiB;AAAA,IACnC,WAAY,sBAAsB,SAAU;AAC3C,YAAM,YAAY,IAAI,SAAS;AAAA,QAC9B,IAAI,SAAS,cAAc,iBAAiB;AAAA,MAC7C;AAEA,UAAK,IAAI,SAAS,eAAe,CAAE,WAAY;AAC9C,mBAAW,sBAAsB;AACjC;AAAA,MACD;AAMA,UAAK,iBAAiB,SAAU;AAC/B,yBAAiB,QAAQ;AAAA,MAC1B,OAAO;AACN,cAAM,iBACL,CAAE,sBAAsB,QAAQ,cAC7B,SACA,sBAAsB;AAG1B,wBAAgB,MAAM;AAAA,MACvB;AACA,eAAS;AAAA,IACV;AAAA,EACD,GAAG,CAAC,CAAE;AACP;AAEA,IAAO,2BAAQ;", "names": [] }