UNPKG

react-aria

Version:
1 lines 7.37 kB
{"mappings":";;;;;;;AAAA;;;;;;;;;;CAUC;;;;;;AAiCM,SAAS,yCACd,KAAuB,EACvB,GAAkC;IAElC,MAAM,EACJ,cAAc,SAAS,EACvB,mBAAmB,cAAc,eACjC,cAAc,cACf,GAAG;IACJ,IAAI,CAAC,aAAa,aAAa,GAAG,CAAA,GAAA,eAAO,EAAE;IAC3C,4FAA4F;IAC5F,mFAAmF;IACnF,uDAAuD;IACvD,CAAA,GAAA,yCAAc,EAAE;QACd,aAAa,CAAC,CAAE,CAAA,IAAI,OAAO,IAAI,IAAI,OAAO,CAAC,aAAa,EAAE,QAAQ,mBAAkB;IACtF;IACA,MAAM,aAAC,SAAS,EAAC,GAAG,CAAA,GAAA,yCAAQ;IAC5B,MAAM,gBAAgB,cAAc,SAAS,gBAAgB;IAC7D,IAAI,eAAe,CAAA,GAAA,wCAAiB,EAAE;IAEtC,MAAM,YAAkC,CAAA;QACtC,gCAAgC;QAChC,IAAI,CAAC,CAAA,GAAA,yCAAW,EAAE,EAAE,aAAa,EAAE,CAAA,GAAA,yCAAa,EAAE,KAChD;QAEF,IACE,AAAC,gBAAgB,gBAAgB,EAAE,GAAG,KAAK,gBAC1C,gBAAgB,cAAc,EAAE,GAAG,KAAK;YAEzC,IAAI,eACF,aAAa,aAAa;iBAE1B,aAAa,SAAS;eAEnB,IACL,AAAC,gBAAgB,gBAAgB,EAAE,GAAG,KAAK,eAC1C,gBAAgB,cAAc,EAAE,GAAG,KAAK;YAEzC,IAAI,eACF,aAAa,SAAS;iBAEtB,aAAa,aAAa;eAEvB,IAAI,EAAE,GAAG,KAAK,OAAO;YAC1B,qDAAqD;YACrD,oDAAoD;YACpD,oDAAoD;YACpD,kDAAkD;YAClD,EAAE,eAAe;YACjB,YAAY,OAAO,GAAG,CAAA,GAAA,yCAAe;YACrC,IAAI,EAAE,QAAQ,EACZ,aAAa,UAAU;iBAEvB,aAAa,SAAS;YAExB;QACF,OACE,wEAAwE;QACxE;QAGF,iEAAiE;QACjE,EAAE,eAAe;QACjB,EAAE,cAAc;IAClB;IAEA,qEAAqE;IACrE,MAAM,cAAc,CAAA,GAAA,aAAK,EAAsB;IAC/C,MAAM,SAAyC,CAAA;QAC7C,IAAI,CAAC,CAAA,GAAA,yCAAW,EAAE,EAAE,aAAa,EAAE,EAAE,aAAa,KAAK,CAAC,YAAY,OAAO,EACzE,YAAY,OAAO,GAAG,CAAA,GAAA,yCAAa,EAAE;IAEzC;IAEA,+EAA+E;IAC/E,oFAAoF;IACpF,8EAA8E;IAC9E,MAAM,UAA0C,CAAA;QAC9C,IACE,YAAY,OAAO,IACnB,CAAC,CAAA,GAAA,yCAAW,EAAE,EAAE,aAAa,EAAE,EAAE,aAAa,KAC9C,CAAA,GAAA,yCAAW,EAAE,IAAI,OAAO,EAAE,CAAA,GAAA,yCAAa,EAAE,KACzC;YACA,YAAY,OAAO,EAAE;YACrB,YAAY,OAAO,GAAG;QACxB;IACF;IAEA,OAAO;QACL,cAAc;YACZ,GAAG,CAAA,GAAA,yCAAa,EAAE,OAAO;gBAAC,WAAW;YAAI,EAAE;YAC3C,MAAM,CAAC,cAAc,YAAY;YACjC,oBAAoB;YACpB,cAAc;YACd,mBAAmB,aAAa,OAAO,iBAAiB;YACxD,kBAAkB,CAAC,cAAc,YAAY;YAC7C,gBAAgB,CAAC,cAAc,UAAU;YACzC,eAAe,CAAC,cAAc,SAAS;QACzC;IACF;AACF","sources":["packages/react-aria/src/toolbar/useToolbar.ts"],"sourcesContent":["/*\n * Copyright 2023 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {AriaLabelingProps, Orientation, RefObject} from '@react-types/shared';\nimport {createFocusManager} from '../focus/FocusScope';\nimport {filterDOMProps} from '../utils/filterDOMProps';\nimport {FocusEventHandler, HTMLAttributes, KeyboardEventHandler, useRef, useState} from 'react';\nimport {getActiveElement, getEventTarget, nodeContains} from '../utils/shadowdom/DOMFunctions';\nimport {useLayoutEffect} from '../utils/useLayoutEffect';\nimport {useLocale} from '../i18n/I18nProvider';\n\nexport interface AriaToolbarProps extends AriaLabelingProps {\n /**\n * The orientation of the entire toolbar.\n *\n * @default 'horizontal'\n */\n orientation?: Orientation;\n}\n\nexport interface ToolbarAria {\n /**\n * Props for the toolbar container.\n */\n toolbarProps: HTMLAttributes<HTMLElement>;\n}\n\n/**\n * Provides the behavior and accessibility implementation for a toolbar.\n * A toolbar is a container for a set of interactive controls with arrow key navigation.\n *\n * @param props - Props to be applied to the toolbar.\n * @param ref - A ref to a DOM element for the toolbar.\n */\nexport function useToolbar(\n props: AriaToolbarProps,\n ref: RefObject<HTMLElement | null>\n): ToolbarAria {\n const {\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n orientation = 'horizontal'\n } = props;\n let [isInToolbar, setInToolbar] = useState(false);\n // should be safe because re-calling set state with the same value it already has is a no-op\n // this will allow us to react should a parent re-render and change its role though\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useLayoutEffect(() => {\n setInToolbar(!!(ref.current && ref.current.parentElement?.closest('[role=\"toolbar\"]')));\n });\n const {direction} = useLocale();\n const shouldReverse = direction === 'rtl' && orientation === 'horizontal';\n let focusManager = createFocusManager(ref);\n\n const onKeyDown: KeyboardEventHandler = e => {\n // don't handle portalled events\n if (!nodeContains(e.currentTarget, getEventTarget(e) as HTMLElement)) {\n return;\n }\n if (\n (orientation === 'horizontal' && e.key === 'ArrowRight') ||\n (orientation === 'vertical' && e.key === 'ArrowDown')\n ) {\n if (shouldReverse) {\n focusManager.focusPrevious();\n } else {\n focusManager.focusNext();\n }\n } else if (\n (orientation === 'horizontal' && e.key === 'ArrowLeft') ||\n (orientation === 'vertical' && e.key === 'ArrowUp')\n ) {\n if (shouldReverse) {\n focusManager.focusNext();\n } else {\n focusManager.focusPrevious();\n }\n } else if (e.key === 'Tab') {\n // When the tab key is pressed, we want to move focus\n // out of the entire toolbar. To do this, move focus\n // to the first or last focusable child, and let the\n // browser handle the Tab key as usual from there.\n e.stopPropagation();\n lastFocused.current = getActiveElement() as HTMLElement;\n if (e.shiftKey) {\n focusManager.focusFirst();\n } else {\n focusManager.focusLast();\n }\n return;\n } else {\n // if we didn't handle anything, return early so we don't preventDefault\n return;\n }\n\n // Prevent arrow keys from being handled by nested action groups.\n e.stopPropagation();\n e.preventDefault();\n };\n\n // Record the last focused child when focus moves out of the toolbar.\n const lastFocused = useRef<HTMLElement | null>(null);\n const onBlur: FocusEventHandler<HTMLElement> = e => {\n if (!nodeContains(e.currentTarget, e.relatedTarget) && !lastFocused.current) {\n lastFocused.current = getEventTarget(e);\n }\n };\n\n // Restore focus to the last focused child when focus returns into the toolbar.\n // If the element was removed, do nothing, either the first item in the first group,\n // or the last item in the last group will be focused, depending on direction.\n const onFocus: FocusEventHandler<HTMLElement> = e => {\n if (\n lastFocused.current &&\n !nodeContains(e.currentTarget, e.relatedTarget) &&\n nodeContains(ref.current, getEventTarget(e))\n ) {\n lastFocused.current?.focus();\n lastFocused.current = null;\n }\n };\n\n return {\n toolbarProps: {\n ...filterDOMProps(props, {labelable: true}),\n role: !isInToolbar ? 'toolbar' : 'group',\n 'aria-orientation': orientation,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabel == null ? ariaLabelledBy : undefined,\n onKeyDownCapture: !isInToolbar ? onKeyDown : undefined,\n onFocusCapture: !isInToolbar ? onFocus : undefined,\n onBlurCapture: !isInToolbar ? onBlur : undefined\n }\n };\n}\n"],"names":[],"version":3,"file":"useToolbar.mjs.map"}