index.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. var $9QJ9Y$babelruntimehelpersextends = require("@babel/runtime/helpers/extends");
  2. var $9QJ9Y$react = require("react");
  3. var $9QJ9Y$radixuiprimitive = require("@radix-ui/primitive");
  4. var $9QJ9Y$radixuireactcollection = require("@radix-ui/react-collection");
  5. var $9QJ9Y$radixuireactcomposerefs = require("@radix-ui/react-compose-refs");
  6. var $9QJ9Y$radixuireactcontext = require("@radix-ui/react-context");
  7. var $9QJ9Y$radixuireactid = require("@radix-ui/react-id");
  8. var $9QJ9Y$radixuireactprimitive = require("@radix-ui/react-primitive");
  9. var $9QJ9Y$radixuireactusecallbackref = require("@radix-ui/react-use-callback-ref");
  10. var $9QJ9Y$radixuireactusecontrollablestate = require("@radix-ui/react-use-controllable-state");
  11. var $9QJ9Y$radixuireactdirection = require("@radix-ui/react-direction");
  12. function $parcel$export(e, n, v, s) {
  13. Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
  14. }
  15. function $parcel$interopDefault(a) {
  16. return a && a.__esModule ? a.default : a;
  17. }
  18. $parcel$export(module.exports, "createRovingFocusGroupScope", () => $0063afae63b3fa70$export$c7109489551a4f4);
  19. $parcel$export(module.exports, "RovingFocusGroup", () => $0063afae63b3fa70$export$8699f7c8af148338);
  20. $parcel$export(module.exports, "RovingFocusGroupItem", () => $0063afae63b3fa70$export$ab9df7c53fe8454);
  21. $parcel$export(module.exports, "Root", () => $0063afae63b3fa70$export$be92b6f5f03c0fe9);
  22. $parcel$export(module.exports, "Item", () => $0063afae63b3fa70$export$6d08773d2e66f8f2);
  23. const $0063afae63b3fa70$var$ENTRY_FOCUS = 'rovingFocusGroup.onEntryFocus';
  24. const $0063afae63b3fa70$var$EVENT_OPTIONS = {
  25. bubbles: false,
  26. cancelable: true
  27. };
  28. /* -------------------------------------------------------------------------------------------------
  29. * RovingFocusGroup
  30. * -----------------------------------------------------------------------------------------------*/ const $0063afae63b3fa70$var$GROUP_NAME = 'RovingFocusGroup';
  31. const [$0063afae63b3fa70$var$Collection, $0063afae63b3fa70$var$useCollection, $0063afae63b3fa70$var$createCollectionScope] = $9QJ9Y$radixuireactcollection.createCollection($0063afae63b3fa70$var$GROUP_NAME);
  32. const [$0063afae63b3fa70$var$createRovingFocusGroupContext, $0063afae63b3fa70$export$c7109489551a4f4] = $9QJ9Y$radixuireactcontext.createContextScope($0063afae63b3fa70$var$GROUP_NAME, [
  33. $0063afae63b3fa70$var$createCollectionScope
  34. ]);
  35. const [$0063afae63b3fa70$var$RovingFocusProvider, $0063afae63b3fa70$var$useRovingFocusContext] = $0063afae63b3fa70$var$createRovingFocusGroupContext($0063afae63b3fa70$var$GROUP_NAME);
  36. const $0063afae63b3fa70$export$8699f7c8af148338 = /*#__PURE__*/ $9QJ9Y$react.forwardRef((props, forwardedRef)=>{
  37. return /*#__PURE__*/ $9QJ9Y$react.createElement($0063afae63b3fa70$var$Collection.Provider, {
  38. scope: props.__scopeRovingFocusGroup
  39. }, /*#__PURE__*/ $9QJ9Y$react.createElement($0063afae63b3fa70$var$Collection.Slot, {
  40. scope: props.__scopeRovingFocusGroup
  41. }, /*#__PURE__*/ $9QJ9Y$react.createElement($0063afae63b3fa70$var$RovingFocusGroupImpl, ($parcel$interopDefault($9QJ9Y$babelruntimehelpersextends))({}, props, {
  42. ref: forwardedRef
  43. }))));
  44. });
  45. /*#__PURE__*/ Object.assign($0063afae63b3fa70$export$8699f7c8af148338, {
  46. displayName: $0063afae63b3fa70$var$GROUP_NAME
  47. });
  48. /* -----------------------------------------------------------------------------------------------*/ const $0063afae63b3fa70$var$RovingFocusGroupImpl = /*#__PURE__*/ $9QJ9Y$react.forwardRef((props, forwardedRef)=>{
  49. const { __scopeRovingFocusGroup: __scopeRovingFocusGroup , orientation: orientation , loop: loop = false , dir: dir , currentTabStopId: currentTabStopIdProp , defaultCurrentTabStopId: defaultCurrentTabStopId , onCurrentTabStopIdChange: onCurrentTabStopIdChange , onEntryFocus: onEntryFocus , ...groupProps } = props;
  50. const ref = $9QJ9Y$react.useRef(null);
  51. const composedRefs = $9QJ9Y$radixuireactcomposerefs.useComposedRefs(forwardedRef, ref);
  52. const direction = $9QJ9Y$radixuireactdirection.useDirection(dir);
  53. const [currentTabStopId = null, setCurrentTabStopId] = $9QJ9Y$radixuireactusecontrollablestate.useControllableState({
  54. prop: currentTabStopIdProp,
  55. defaultProp: defaultCurrentTabStopId,
  56. onChange: onCurrentTabStopIdChange
  57. });
  58. const [isTabbingBackOut, setIsTabbingBackOut] = $9QJ9Y$react.useState(false);
  59. const handleEntryFocus = $9QJ9Y$radixuireactusecallbackref.useCallbackRef(onEntryFocus);
  60. const getItems = $0063afae63b3fa70$var$useCollection(__scopeRovingFocusGroup);
  61. const isClickFocusRef = $9QJ9Y$react.useRef(false);
  62. const [focusableItemsCount, setFocusableItemsCount] = $9QJ9Y$react.useState(0);
  63. $9QJ9Y$react.useEffect(()=>{
  64. const node = ref.current;
  65. if (node) {
  66. node.addEventListener($0063afae63b3fa70$var$ENTRY_FOCUS, handleEntryFocus);
  67. return ()=>node.removeEventListener($0063afae63b3fa70$var$ENTRY_FOCUS, handleEntryFocus)
  68. ;
  69. }
  70. }, [
  71. handleEntryFocus
  72. ]);
  73. return /*#__PURE__*/ $9QJ9Y$react.createElement($0063afae63b3fa70$var$RovingFocusProvider, {
  74. scope: __scopeRovingFocusGroup,
  75. orientation: orientation,
  76. dir: direction,
  77. loop: loop,
  78. currentTabStopId: currentTabStopId,
  79. onItemFocus: $9QJ9Y$react.useCallback((tabStopId)=>setCurrentTabStopId(tabStopId)
  80. , [
  81. setCurrentTabStopId
  82. ]),
  83. onItemShiftTab: $9QJ9Y$react.useCallback(()=>setIsTabbingBackOut(true)
  84. , []),
  85. onFocusableItemAdd: $9QJ9Y$react.useCallback(()=>setFocusableItemsCount((prevCount)=>prevCount + 1
  86. )
  87. , []),
  88. onFocusableItemRemove: $9QJ9Y$react.useCallback(()=>setFocusableItemsCount((prevCount)=>prevCount - 1
  89. )
  90. , [])
  91. }, /*#__PURE__*/ $9QJ9Y$react.createElement($9QJ9Y$radixuireactprimitive.Primitive.div, ($parcel$interopDefault($9QJ9Y$babelruntimehelpersextends))({
  92. tabIndex: isTabbingBackOut || focusableItemsCount === 0 ? -1 : 0,
  93. "data-orientation": orientation
  94. }, groupProps, {
  95. ref: composedRefs,
  96. style: {
  97. outline: 'none',
  98. ...props.style
  99. },
  100. onMouseDown: $9QJ9Y$radixuiprimitive.composeEventHandlers(props.onMouseDown, ()=>{
  101. isClickFocusRef.current = true;
  102. }),
  103. onFocus: $9QJ9Y$radixuiprimitive.composeEventHandlers(props.onFocus, (event)=>{
  104. // We normally wouldn't need this check, because we already check
  105. // that the focus is on the current target and not bubbling to it.
  106. // We do this because Safari doesn't focus buttons when clicked, and
  107. // instead, the wrapper will get focused and not through a bubbling event.
  108. const isKeyboardFocus = !isClickFocusRef.current;
  109. if (event.target === event.currentTarget && isKeyboardFocus && !isTabbingBackOut) {
  110. const entryFocusEvent = new CustomEvent($0063afae63b3fa70$var$ENTRY_FOCUS, $0063afae63b3fa70$var$EVENT_OPTIONS);
  111. event.currentTarget.dispatchEvent(entryFocusEvent);
  112. if (!entryFocusEvent.defaultPrevented) {
  113. const items = getItems().filter((item)=>item.focusable
  114. );
  115. const activeItem = items.find((item)=>item.active
  116. );
  117. const currentItem = items.find((item)=>item.id === currentTabStopId
  118. );
  119. const candidateItems = [
  120. activeItem,
  121. currentItem,
  122. ...items
  123. ].filter(Boolean);
  124. const candidateNodes = candidateItems.map((item)=>item.ref.current
  125. );
  126. $0063afae63b3fa70$var$focusFirst(candidateNodes);
  127. }
  128. }
  129. isClickFocusRef.current = false;
  130. }),
  131. onBlur: $9QJ9Y$radixuiprimitive.composeEventHandlers(props.onBlur, ()=>setIsTabbingBackOut(false)
  132. )
  133. })));
  134. });
  135. /* -------------------------------------------------------------------------------------------------
  136. * RovingFocusGroupItem
  137. * -----------------------------------------------------------------------------------------------*/ const $0063afae63b3fa70$var$ITEM_NAME = 'RovingFocusGroupItem';
  138. const $0063afae63b3fa70$export$ab9df7c53fe8454 = /*#__PURE__*/ $9QJ9Y$react.forwardRef((props, forwardedRef)=>{
  139. const { __scopeRovingFocusGroup: __scopeRovingFocusGroup , focusable: focusable = true , active: active = false , tabStopId: tabStopId , ...itemProps } = props;
  140. const autoId = $9QJ9Y$radixuireactid.useId();
  141. const id = tabStopId || autoId;
  142. const context = $0063afae63b3fa70$var$useRovingFocusContext($0063afae63b3fa70$var$ITEM_NAME, __scopeRovingFocusGroup);
  143. const isCurrentTabStop = context.currentTabStopId === id;
  144. const getItems = $0063afae63b3fa70$var$useCollection(__scopeRovingFocusGroup);
  145. const { onFocusableItemAdd: onFocusableItemAdd , onFocusableItemRemove: onFocusableItemRemove } = context;
  146. $9QJ9Y$react.useEffect(()=>{
  147. if (focusable) {
  148. onFocusableItemAdd();
  149. return ()=>onFocusableItemRemove()
  150. ;
  151. }
  152. }, [
  153. focusable,
  154. onFocusableItemAdd,
  155. onFocusableItemRemove
  156. ]);
  157. return /*#__PURE__*/ $9QJ9Y$react.createElement($0063afae63b3fa70$var$Collection.ItemSlot, {
  158. scope: __scopeRovingFocusGroup,
  159. id: id,
  160. focusable: focusable,
  161. active: active
  162. }, /*#__PURE__*/ $9QJ9Y$react.createElement($9QJ9Y$radixuireactprimitive.Primitive.span, ($parcel$interopDefault($9QJ9Y$babelruntimehelpersextends))({
  163. tabIndex: isCurrentTabStop ? 0 : -1,
  164. "data-orientation": context.orientation
  165. }, itemProps, {
  166. ref: forwardedRef,
  167. onMouseDown: $9QJ9Y$radixuiprimitive.composeEventHandlers(props.onMouseDown, (event)=>{
  168. // We prevent focusing non-focusable items on `mousedown`.
  169. // Even though the item has tabIndex={-1}, that only means take it out of the tab order.
  170. if (!focusable) event.preventDefault(); // Safari doesn't focus a button when clicked so we run our logic on mousedown also
  171. else context.onItemFocus(id);
  172. }),
  173. onFocus: $9QJ9Y$radixuiprimitive.composeEventHandlers(props.onFocus, ()=>context.onItemFocus(id)
  174. ),
  175. onKeyDown: $9QJ9Y$radixuiprimitive.composeEventHandlers(props.onKeyDown, (event)=>{
  176. if (event.key === 'Tab' && event.shiftKey) {
  177. context.onItemShiftTab();
  178. return;
  179. }
  180. if (event.target !== event.currentTarget) return;
  181. const focusIntent = $0063afae63b3fa70$var$getFocusIntent(event, context.orientation, context.dir);
  182. if (focusIntent !== undefined) {
  183. event.preventDefault();
  184. const items = getItems().filter((item)=>item.focusable
  185. );
  186. let candidateNodes = items.map((item)=>item.ref.current
  187. );
  188. if (focusIntent === 'last') candidateNodes.reverse();
  189. else if (focusIntent === 'prev' || focusIntent === 'next') {
  190. if (focusIntent === 'prev') candidateNodes.reverse();
  191. const currentIndex = candidateNodes.indexOf(event.currentTarget);
  192. candidateNodes = context.loop ? $0063afae63b3fa70$var$wrapArray(candidateNodes, currentIndex + 1) : candidateNodes.slice(currentIndex + 1);
  193. }
  194. /**
  195. * Imperative focus during keydown is risky so we prevent React's batching updates
  196. * to avoid potential bugs. See: https://github.com/facebook/react/issues/20332
  197. */ setTimeout(()=>$0063afae63b3fa70$var$focusFirst(candidateNodes)
  198. );
  199. }
  200. })
  201. })));
  202. });
  203. /*#__PURE__*/ Object.assign($0063afae63b3fa70$export$ab9df7c53fe8454, {
  204. displayName: $0063afae63b3fa70$var$ITEM_NAME
  205. });
  206. /* -----------------------------------------------------------------------------------------------*/ // prettier-ignore
  207. const $0063afae63b3fa70$var$MAP_KEY_TO_FOCUS_INTENT = {
  208. ArrowLeft: 'prev',
  209. ArrowUp: 'prev',
  210. ArrowRight: 'next',
  211. ArrowDown: 'next',
  212. PageUp: 'first',
  213. Home: 'first',
  214. PageDown: 'last',
  215. End: 'last'
  216. };
  217. function $0063afae63b3fa70$var$getDirectionAwareKey(key, dir) {
  218. if (dir !== 'rtl') return key;
  219. return key === 'ArrowLeft' ? 'ArrowRight' : key === 'ArrowRight' ? 'ArrowLeft' : key;
  220. }
  221. function $0063afae63b3fa70$var$getFocusIntent(event, orientation, dir) {
  222. const key = $0063afae63b3fa70$var$getDirectionAwareKey(event.key, dir);
  223. if (orientation === 'vertical' && [
  224. 'ArrowLeft',
  225. 'ArrowRight'
  226. ].includes(key)) return undefined;
  227. if (orientation === 'horizontal' && [
  228. 'ArrowUp',
  229. 'ArrowDown'
  230. ].includes(key)) return undefined;
  231. return $0063afae63b3fa70$var$MAP_KEY_TO_FOCUS_INTENT[key];
  232. }
  233. function $0063afae63b3fa70$var$focusFirst(candidates) {
  234. const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
  235. for (const candidate of candidates){
  236. // if focus is already where we want to go, we don't want to keep going through the candidates
  237. if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;
  238. candidate.focus();
  239. if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;
  240. }
  241. }
  242. /**
  243. * Wraps an array around itself at a given start index
  244. * Example: `wrapArray(['a', 'b', 'c', 'd'], 2) === ['c', 'd', 'a', 'b']`
  245. */ function $0063afae63b3fa70$var$wrapArray(array, startIndex) {
  246. return array.map((_, index)=>array[(startIndex + index) % array.length]
  247. );
  248. }
  249. const $0063afae63b3fa70$export$be92b6f5f03c0fe9 = $0063afae63b3fa70$export$8699f7c8af148338;
  250. const $0063afae63b3fa70$export$6d08773d2e66f8f2 = $0063afae63b3fa70$export$ab9df7c53fe8454;
  251. //# sourceMappingURL=index.js.map