UNPKG

@wordpress/compose

Version:
8 lines (7 loc) 3.5 kB
{ "version": 3, "sources": ["../../../src/hooks/use-focus-return/index.js"], "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useRef, useEffect, useCallback } from '@wordpress/element';\n\n/** @type {Element|null} */\nlet origin = 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 {() => void} [onFocusReturn] Overrides the default return behavior.\n * @return {React.RefCallback<HTMLElement>} Element Ref.\n *\n * @example\n * ```js\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( onFocusReturn ) {\n\t/** @type {React.MutableRefObject<null | HTMLElement>} */\n\tconst ref = useRef( null );\n\t/** @type {React.MutableRefObject<null | Element>} */\n\tconst focusedBeforeMount = useRef( null );\n\tconst onFocusReturnRef = useRef( onFocusReturn );\n\tuseEffect( () => {\n\t\tonFocusReturnRef.current = onFocusReturn;\n\t}, [ onFocusReturn ] );\n\n\treturn useCallback( ( node ) => {\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 ( focusedBeforeMount.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\tfocusedBeforeMount.current = activeDocument?.activeElement ?? null;\n\t\t} else if ( focusedBeforeMount.current ) {\n\t\t\tconst isFocused = ref.current?.contains(\n\t\t\t\tref.current?.ownerDocument.activeElement\n\t\t\t);\n\n\t\t\tif ( ref.current?.isConnected && ! isFocused ) {\n\t\t\t\torigin ??= focusedBeforeMount.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\t/** @type {null|HTMLElement} */ (\n\t\t\t\t\t! focusedBeforeMount.current.isConnected\n\t\t\t\t\t\t? origin\n\t\t\t\t\t\t: focusedBeforeMount.current\n\t\t\t\t)?.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;AAG/C,IAAI,SAAS;AAwBb,SAAS,eAAgB,eAAgB;AAExC,QAAM,UAAM,uBAAQ,IAAK;AAEzB,QAAM,yBAAqB,uBAAQ,IAAK;AACxC,QAAM,uBAAmB,uBAAQ,aAAc;AAC/C,gCAAW,MAAM;AAChB,qBAAiB,UAAU;AAAA,EAC5B,GAAG,CAAE,aAAc,CAAE;AAErB,aAAO,4BAAa,CAAE,SAAU;AAC/B,QAAK,MAAO;AAEX,UAAI,UAAU;AAGd,UAAK,mBAAmB,SAAU;AACjC;AAAA,MACD;AAEA,YAAM,iBACL,KAAK,cAAc,yBACnB,OAAO,oBACJ,KAAK,cAAc,cAAc,kBACjC,KAAK;AAET,yBAAmB,UAAU,gBAAgB,iBAAiB;AAAA,IAC/D,WAAY,mBAAmB,SAAU;AACxC,YAAM,YAAY,IAAI,SAAS;AAAA,QAC9B,IAAI,SAAS,cAAc;AAAA,MAC5B;AAEA,UAAK,IAAI,SAAS,eAAe,CAAE,WAAY;AAC9C,mBAAW,mBAAmB;AAC9B;AAAA,MACD;AAMA,UAAK,iBAAiB,SAAU;AAC/B,yBAAiB,QAAQ;AAAA,MAC1B,OAAO;AAC0B,SAC/B,CAAE,mBAAmB,QAAQ,cAC1B,SACA,mBAAmB,UACpB,MAAM;AAAA,MACV;AACA,eAAS;AAAA,IACV;AAAA,EACD,GAAG,CAAC,CAAE;AACP;AAEA,IAAO,2BAAQ;", "names": [] }