@radix-ui/react-roving-focus
Advanced tools
Comparing version 0.1.6-rc.5 to 0.1.6-rc.6
@@ -1,2 +0,266 @@ | ||
var e,r,o,t=require("@radix-ui/react-direction").useDirection,n=require("@radix-ui/react-use-controllable-state").useControllableState,u=require("@radix-ui/react-use-callback-ref").useCallbackRef,i=require("@radix-ui/react-primitive").Primitive,c=require("@radix-ui/react-id").useId,a=require("@radix-ui/react-context").createContextScope,s=require("@radix-ui/react-compose-refs").useComposedRefs,l=require("@radix-ui/react-collection").createCollection,f=require("@radix-ui/primitive").composeEventHandlers,p=(e={},r=require("react"),Object.keys(r).forEach((function(o){"default"!==o&&"__esModule"!==o&&Object.defineProperty(e,o,{enumerable:!0,get:function(){return r[o]}})})),e),d=(o=require("@babel/runtime/helpers/extends"))&&o.__esModule?o.default:o;const v={bubbles:!1,cancelable:!0},[m,g,b]=l("RovingFocusGroup"),[w,F]=a("RovingFocusGroup",[b]);exports.createRovingFocusGroupScope=F;const[x,R]=w("RovingFocusGroup"),E=/*#__PURE__*/p.forwardRef(((e,r)=>/*#__PURE__*/p.createElement(m.Provider,{scope:e.__scopeRovingFocusGroup},/*#__PURE__*/p.createElement(m.Slot,{scope:e.__scopeRovingFocusGroup},/*#__PURE__*/p.createElement(I,d({},e,{ref:r}))))));exports.RovingFocusGroup=E;const I=/*#__PURE__*/p.forwardRef(((e,r)=>{const{__scopeRovingFocusGroup:o,orientation:c,loop:a=!1,dir:l,currentTabStopId:m,defaultCurrentTabStopId:b,onCurrentTabStopIdChange:w,onEntryFocus:F,...R}=e,E=p.useRef(null),I=s(r,E),h=t(l),[G=null,S]=n({prop:m,defaultProp:b,onChange:w}),[T,A]=p.useState(!1),D=u(F),_=g(o),q=p.useRef(!1);return p.useEffect((()=>{const e=E.current;if(e)return e.addEventListener("rovingFocusGroup.onEntryFocus",D),()=>e.removeEventListener("rovingFocusGroup.onEntryFocus",D)}),[D]),/*#__PURE__*/p.createElement(x,{scope:o,orientation:c,dir:h,loop:a,currentTabStopId:G,onItemFocus:p.useCallback((e=>S(e)),[S]),onItemShiftTab:p.useCallback((()=>A(!0)),[])},/*#__PURE__*/p.createElement(i.div,d({tabIndex:T?-1:0,"data-orientation":c},R,{ref:I,style:{outline:"none",...e.style},onMouseDown:f(e.onMouseDown,(()=>{q.current=!0})),onFocus:f(e.onFocus,(e=>{const r=!q.current;if(e.target===e.currentTarget&&r&&!T){const r=new Event("rovingFocusGroup.onEntryFocus",v);if(e.currentTarget.dispatchEvent(r),!r.defaultPrevented){const e=_().filter((e=>e.focusable));y([e.find((e=>e.active)),e.find((e=>e.id===G)),...e].filter(Boolean).map((e=>e.ref.current)))}}q.current=!1})),onBlur:f(e.onBlur,(()=>A(!1)))})))})),h=/*#__PURE__*/p.forwardRef(((e,r)=>{const{__scopeRovingFocusGroup:o,focusable:t=!0,active:n=!1,...u}=e,a=c(),s=R("RovingFocusGroupItem",o),l=s.currentTabStopId===a,v=g(o);/*#__PURE__*/return p.createElement(m.ItemSlot,{scope:o,id:a,focusable:t,active:n},/*#__PURE__*/p.createElement(i.span,d({tabIndex:l?0:-1,"data-orientation":s.orientation},u,{ref:r,onMouseDown:f(e.onMouseDown,(e=>{t?s.onItemFocus(a):e.preventDefault()})),onFocus:f(e.onFocus,(()=>s.onItemFocus(a))),onKeyDown:f(e.onKeyDown,(e=>{if("Tab"===e.key&&e.shiftKey)return void s.onItemShiftTab();if(e.target!==e.currentTarget)return;const r=function(e,r,o){const t=function(e,r){return"rtl"!==r?e:"ArrowLeft"===e?"ArrowRight":"ArrowRight"===e?"ArrowLeft":e}(e.key,o);return"vertical"===r&&["ArrowLeft","ArrowRight"].includes(t)||"horizontal"===r&&["ArrowUp","ArrowDown"].includes(t)?void 0:G[t]}(e,s.orientation,s.dir);if(void 0!==r){e.preventDefault();let n=v().filter((e=>e.focusable)).map((e=>e.ref.current));if("last"===r)n.reverse();else if("prev"===r||"next"===r){"prev"===r&&n.reverse();const u=n.indexOf(e.currentTarget);n=s.loop?(t=u+1,(o=n).map(((e,r)=>o[(t+r)%o.length]))):n.slice(u+1)}setTimeout((()=>y(n)))}var o,t}))})))}));exports.RovingFocusGroupItem=h;const G={ArrowLeft:"prev",ArrowUp:"prev",ArrowRight:"next",ArrowDown:"next",PageUp:"first",Home:"first",PageDown:"last",End:"last"};function y(e){const r=document.activeElement;for(const o of e){if(o===r)return;if(o.focus(),document.activeElement!==r)return}}const S=E;exports.Root=S;const T=h;exports.Item=T; | ||
var $9QJ9Y$babelruntimehelpersextends = require("@babel/runtime/helpers/extends"); | ||
var $9QJ9Y$react = require("react"); | ||
var $9QJ9Y$radixuiprimitive = require("@radix-ui/primitive"); | ||
var $9QJ9Y$radixuireactcollection = require("@radix-ui/react-collection"); | ||
var $9QJ9Y$radixuireactcomposerefs = require("@radix-ui/react-compose-refs"); | ||
var $9QJ9Y$radixuireactcontext = require("@radix-ui/react-context"); | ||
var $9QJ9Y$radixuireactid = require("@radix-ui/react-id"); | ||
var $9QJ9Y$radixuireactprimitive = require("@radix-ui/react-primitive"); | ||
var $9QJ9Y$radixuireactusecallbackref = require("@radix-ui/react-use-callback-ref"); | ||
var $9QJ9Y$radixuireactusecontrollablestate = require("@radix-ui/react-use-controllable-state"); | ||
var $9QJ9Y$radixuireactdirection = require("@radix-ui/react-direction"); | ||
function $parcel$exportWildcard(dest, source) { | ||
Object.keys(source).forEach(function(key) { | ||
if (key === 'default' || key === '__esModule' || dest.hasOwnProperty(key)) { | ||
return; | ||
} | ||
Object.defineProperty(dest, key, { | ||
enumerable: true, | ||
get: function get() { | ||
return source[key]; | ||
} | ||
}); | ||
}); | ||
return dest; | ||
} | ||
function $parcel$interopDefault(a) { | ||
return a && a.__esModule ? a.default : a; | ||
} | ||
function $parcel$export(e, n, v, s) { | ||
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true}); | ||
} | ||
var $0063afae63b3fa70$exports = {}; | ||
$parcel$export($0063afae63b3fa70$exports, "createRovingFocusGroupScope", () => $0063afae63b3fa70$export$c7109489551a4f4); | ||
$parcel$export($0063afae63b3fa70$exports, "RovingFocusGroup", () => $0063afae63b3fa70$export$8699f7c8af148338); | ||
$parcel$export($0063afae63b3fa70$exports, "RovingFocusGroupItem", () => $0063afae63b3fa70$export$ab9df7c53fe8454); | ||
$parcel$export($0063afae63b3fa70$exports, "Root", () => $0063afae63b3fa70$export$be92b6f5f03c0fe9); | ||
$parcel$export($0063afae63b3fa70$exports, "Item", () => $0063afae63b3fa70$export$6d08773d2e66f8f2); | ||
const $0063afae63b3fa70$var$ENTRY_FOCUS = 'rovingFocusGroup.onEntryFocus'; | ||
const $0063afae63b3fa70$var$EVENT_OPTIONS = { | ||
bubbles: false, | ||
cancelable: true | ||
}; | ||
/* ------------------------------------------------------------------------------------------------- | ||
* RovingFocusGroup | ||
* -----------------------------------------------------------------------------------------------*/ const $0063afae63b3fa70$var$GROUP_NAME = 'RovingFocusGroup'; | ||
const [$0063afae63b3fa70$var$Collection, $0063afae63b3fa70$var$useCollection, $0063afae63b3fa70$var$createCollectionScope] = $9QJ9Y$radixuireactcollection.createCollection($0063afae63b3fa70$var$GROUP_NAME); | ||
const [$0063afae63b3fa70$var$createRovingFocusGroupContext, $0063afae63b3fa70$export$c7109489551a4f4] = $9QJ9Y$radixuireactcontext.createContextScope($0063afae63b3fa70$var$GROUP_NAME, [ | ||
$0063afae63b3fa70$var$createCollectionScope | ||
]); | ||
const [$0063afae63b3fa70$var$RovingFocusProvider, $0063afae63b3fa70$var$useRovingFocusContext] = $0063afae63b3fa70$var$createRovingFocusGroupContext($0063afae63b3fa70$var$GROUP_NAME); | ||
const $0063afae63b3fa70$export$8699f7c8af148338 = /*#__PURE__*/ $9QJ9Y$react.forwardRef((props, forwardedRef)=>{ | ||
return /*#__PURE__*/ $9QJ9Y$react.createElement($0063afae63b3fa70$var$Collection.Provider, { | ||
scope: props.__scopeRovingFocusGroup | ||
}, /*#__PURE__*/ $9QJ9Y$react.createElement($0063afae63b3fa70$var$Collection.Slot, { | ||
scope: props.__scopeRovingFocusGroup | ||
}, /*#__PURE__*/ $9QJ9Y$react.createElement($0063afae63b3fa70$var$RovingFocusGroupImpl, ($parcel$interopDefault($9QJ9Y$babelruntimehelpersextends))({}, props, { | ||
ref: forwardedRef | ||
})))); | ||
}); | ||
/*#__PURE__*/ Object.assign($0063afae63b3fa70$export$8699f7c8af148338, { | ||
displayName: $0063afae63b3fa70$var$GROUP_NAME | ||
}); | ||
/* -----------------------------------------------------------------------------------------------*/ const $0063afae63b3fa70$var$RovingFocusGroupImpl = /*#__PURE__*/ $9QJ9Y$react.forwardRef((props, forwardedRef)=>{ | ||
const { __scopeRovingFocusGroup: __scopeRovingFocusGroup , orientation: orientation , loop: loop = false , dir: dir , currentTabStopId: currentTabStopIdProp , defaultCurrentTabStopId: defaultCurrentTabStopId , onCurrentTabStopIdChange: onCurrentTabStopIdChange , onEntryFocus: onEntryFocus , ...groupProps } = props; | ||
const ref = $9QJ9Y$react.useRef(null); | ||
const composedRefs = $9QJ9Y$radixuireactcomposerefs.useComposedRefs(forwardedRef, ref); | ||
const direction = $9QJ9Y$radixuireactdirection.useDirection(dir); | ||
const [currentTabStopId = null, setCurrentTabStopId] = $9QJ9Y$radixuireactusecontrollablestate.useControllableState({ | ||
prop: currentTabStopIdProp, | ||
defaultProp: defaultCurrentTabStopId, | ||
onChange: onCurrentTabStopIdChange | ||
}); | ||
const [isTabbingBackOut, setIsTabbingBackOut] = $9QJ9Y$react.useState(false); | ||
const handleEntryFocus = $9QJ9Y$radixuireactusecallbackref.useCallbackRef(onEntryFocus); | ||
const getItems = $0063afae63b3fa70$var$useCollection(__scopeRovingFocusGroup); | ||
const isClickFocusRef = $9QJ9Y$react.useRef(false); | ||
$9QJ9Y$react.useEffect(()=>{ | ||
const node = ref.current; | ||
if (node) { | ||
node.addEventListener($0063afae63b3fa70$var$ENTRY_FOCUS, handleEntryFocus); | ||
return ()=>node.removeEventListener($0063afae63b3fa70$var$ENTRY_FOCUS, handleEntryFocus) | ||
; | ||
} | ||
}, [ | ||
handleEntryFocus | ||
]); | ||
return /*#__PURE__*/ $9QJ9Y$react.createElement($0063afae63b3fa70$var$RovingFocusProvider, { | ||
scope: __scopeRovingFocusGroup, | ||
orientation: orientation, | ||
dir: direction, | ||
loop: loop, | ||
currentTabStopId: currentTabStopId, | ||
onItemFocus: $9QJ9Y$react.useCallback((tabStopId)=>setCurrentTabStopId(tabStopId) | ||
, [ | ||
setCurrentTabStopId | ||
]), | ||
onItemShiftTab: $9QJ9Y$react.useCallback(()=>setIsTabbingBackOut(true) | ||
, []) | ||
}, /*#__PURE__*/ $9QJ9Y$react.createElement($9QJ9Y$radixuireactprimitive.Primitive.div, ($parcel$interopDefault($9QJ9Y$babelruntimehelpersextends))({ | ||
tabIndex: isTabbingBackOut ? -1 : 0, | ||
"data-orientation": orientation | ||
}, groupProps, { | ||
ref: composedRefs, | ||
style: { | ||
outline: 'none', | ||
...props.style | ||
}, | ||
onMouseDown: $9QJ9Y$radixuiprimitive.composeEventHandlers(props.onMouseDown, ()=>{ | ||
isClickFocusRef.current = true; | ||
}), | ||
onFocus: $9QJ9Y$radixuiprimitive.composeEventHandlers(props.onFocus, (event)=>{ | ||
// We normally wouldn't need this check, because we already check | ||
// that the focus is on the current target and not bubbling to it. | ||
// We do this because Safari doesn't focus buttons when clicked, and | ||
// instead, the wrapper will get focused and not through a bubbling event. | ||
const isKeyboardFocus = !isClickFocusRef.current; | ||
if (event.target === event.currentTarget && isKeyboardFocus && !isTabbingBackOut) { | ||
const entryFocusEvent = new Event($0063afae63b3fa70$var$ENTRY_FOCUS, $0063afae63b3fa70$var$EVENT_OPTIONS); | ||
event.currentTarget.dispatchEvent(entryFocusEvent); | ||
if (!entryFocusEvent.defaultPrevented) { | ||
const items = getItems().filter((item)=>item.focusable | ||
); | ||
const activeItem = items.find((item)=>item.active | ||
); | ||
const currentItem = items.find((item)=>item.id === currentTabStopId | ||
); | ||
const candidateItems = [ | ||
activeItem, | ||
currentItem, | ||
...items | ||
].filter(Boolean); | ||
const candidateNodes = candidateItems.map((item)=>item.ref.current | ||
); | ||
$0063afae63b3fa70$var$focusFirst(candidateNodes); | ||
} | ||
} | ||
isClickFocusRef.current = false; | ||
}), | ||
onBlur: $9QJ9Y$radixuiprimitive.composeEventHandlers(props.onBlur, ()=>setIsTabbingBackOut(false) | ||
) | ||
}))); | ||
}); | ||
/* ------------------------------------------------------------------------------------------------- | ||
* RovingFocusGroupItem | ||
* -----------------------------------------------------------------------------------------------*/ const $0063afae63b3fa70$var$ITEM_NAME = 'RovingFocusGroupItem'; | ||
const $0063afae63b3fa70$export$ab9df7c53fe8454 = /*#__PURE__*/ $9QJ9Y$react.forwardRef((props, forwardedRef)=>{ | ||
const { __scopeRovingFocusGroup: __scopeRovingFocusGroup , focusable: focusable = true , active: active = false , ...itemProps } = props; | ||
const id = $9QJ9Y$radixuireactid.useId(); | ||
const context = $0063afae63b3fa70$var$useRovingFocusContext($0063afae63b3fa70$var$ITEM_NAME, __scopeRovingFocusGroup); | ||
const isCurrentTabStop = context.currentTabStopId === id; | ||
const getItems = $0063afae63b3fa70$var$useCollection(__scopeRovingFocusGroup); | ||
return /*#__PURE__*/ $9QJ9Y$react.createElement($0063afae63b3fa70$var$Collection.ItemSlot, { | ||
scope: __scopeRovingFocusGroup, | ||
id: id, | ||
focusable: focusable, | ||
active: active | ||
}, /*#__PURE__*/ $9QJ9Y$react.createElement($9QJ9Y$radixuireactprimitive.Primitive.span, ($parcel$interopDefault($9QJ9Y$babelruntimehelpersextends))({ | ||
tabIndex: isCurrentTabStop ? 0 : -1, | ||
"data-orientation": context.orientation | ||
}, itemProps, { | ||
ref: forwardedRef, | ||
onMouseDown: $9QJ9Y$radixuiprimitive.composeEventHandlers(props.onMouseDown, (event)=>{ | ||
// We prevent focusing non-focusable items on `mousedown`. | ||
// Even though the item has tabIndex={-1}, that only means take it out of the tab order. | ||
if (!focusable) event.preventDefault(); // Safari doesn't focus a button when clicked so we run our logic on mousedown also | ||
else context.onItemFocus(id); | ||
}), | ||
onFocus: $9QJ9Y$radixuiprimitive.composeEventHandlers(props.onFocus, ()=>context.onItemFocus(id) | ||
), | ||
onKeyDown: $9QJ9Y$radixuiprimitive.composeEventHandlers(props.onKeyDown, (event)=>{ | ||
if (event.key === 'Tab' && event.shiftKey) { | ||
context.onItemShiftTab(); | ||
return; | ||
} | ||
if (event.target !== event.currentTarget) return; | ||
const focusIntent = $0063afae63b3fa70$var$getFocusIntent(event, context.orientation, context.dir); | ||
if (focusIntent !== undefined) { | ||
event.preventDefault(); | ||
const items = getItems().filter((item)=>item.focusable | ||
); | ||
let candidateNodes = items.map((item)=>item.ref.current | ||
); | ||
if (focusIntent === 'last') candidateNodes.reverse(); | ||
else if (focusIntent === 'prev' || focusIntent === 'next') { | ||
if (focusIntent === 'prev') candidateNodes.reverse(); | ||
const currentIndex = candidateNodes.indexOf(event.currentTarget); | ||
candidateNodes = context.loop ? $0063afae63b3fa70$var$wrapArray(candidateNodes, currentIndex + 1) : candidateNodes.slice(currentIndex + 1); | ||
} | ||
/** | ||
* Imperative focus during keydown is risky so we prevent React's batching updates | ||
* to avoid potential bugs. See: https://github.com/facebook/react/issues/20332 | ||
*/ setTimeout(()=>$0063afae63b3fa70$var$focusFirst(candidateNodes) | ||
); | ||
} | ||
}) | ||
}))); | ||
}); | ||
/*#__PURE__*/ Object.assign($0063afae63b3fa70$export$ab9df7c53fe8454, { | ||
displayName: $0063afae63b3fa70$var$ITEM_NAME | ||
}); | ||
/* -----------------------------------------------------------------------------------------------*/ // prettier-ignore | ||
const $0063afae63b3fa70$var$MAP_KEY_TO_FOCUS_INTENT = { | ||
ArrowLeft: 'prev', | ||
ArrowUp: 'prev', | ||
ArrowRight: 'next', | ||
ArrowDown: 'next', | ||
PageUp: 'first', | ||
Home: 'first', | ||
PageDown: 'last', | ||
End: 'last' | ||
}; | ||
function $0063afae63b3fa70$var$getDirectionAwareKey(key, dir) { | ||
if (dir !== 'rtl') return key; | ||
return key === 'ArrowLeft' ? 'ArrowRight' : key === 'ArrowRight' ? 'ArrowLeft' : key; | ||
} | ||
function $0063afae63b3fa70$var$getFocusIntent(event, orientation, dir) { | ||
const key = $0063afae63b3fa70$var$getDirectionAwareKey(event.key, dir); | ||
if (orientation === 'vertical' && [ | ||
'ArrowLeft', | ||
'ArrowRight' | ||
].includes(key)) return undefined; | ||
if (orientation === 'horizontal' && [ | ||
'ArrowUp', | ||
'ArrowDown' | ||
].includes(key)) return undefined; | ||
return $0063afae63b3fa70$var$MAP_KEY_TO_FOCUS_INTENT[key]; | ||
} | ||
function $0063afae63b3fa70$var$focusFirst(candidates) { | ||
const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement; | ||
for (const candidate of candidates){ | ||
// if focus is already where we want to go, we don't want to keep going through the candidates | ||
if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return; | ||
candidate.focus(); | ||
if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return; | ||
} | ||
} | ||
/** | ||
* Wraps an array around itself at a given start index | ||
* Example: `wrapArray(['a', 'b', 'c', 'd'], 2) === ['c', 'd', 'a', 'b']` | ||
*/ function $0063afae63b3fa70$var$wrapArray(array, startIndex) { | ||
return array.map((_, index)=>array[(startIndex + index) % array.length] | ||
); | ||
} | ||
const $0063afae63b3fa70$export$be92b6f5f03c0fe9 = $0063afae63b3fa70$export$8699f7c8af148338; | ||
const $0063afae63b3fa70$export$6d08773d2e66f8f2 = $0063afae63b3fa70$export$ab9df7c53fe8454; | ||
$parcel$exportWildcard(module.exports, $0063afae63b3fa70$exports); | ||
//# sourceMappingURL=index.js.map |
@@ -1,2 +0,247 @@ | ||
import{useDirection as e}from"@radix-ui/react-direction";import{useControllableState as o}from"@radix-ui/react-use-controllable-state";import{useCallbackRef as r}from"@radix-ui/react-use-callback-ref";import{Primitive as t}from"@radix-ui/react-primitive";import{useId as n}from"@radix-ui/react-id";import{createContextScope as i}from"@radix-ui/react-context";import{useComposedRefs as c}from"@radix-ui/react-compose-refs";import{createCollection as u}from"@radix-ui/react-collection";import{composeEventHandlers as a}from"@radix-ui/primitive";import*as s from"react";import f from"@babel/runtime/helpers/esm/extends";const p={bubbles:!1,cancelable:!0},[l,m,d]=u("RovingFocusGroup"),[v,g]=i("RovingFocusGroup",[d]);export{g as createRovingFocusGroupScope};const[F,w]=v("RovingFocusGroup");export const RovingFocusGroup=/*#__PURE__*/s.forwardRef(((e,o)=>/*#__PURE__*/s.createElement(l.Provider,{scope:e.__scopeRovingFocusGroup},/*#__PURE__*/s.createElement(l.Slot,{scope:e.__scopeRovingFocusGroup},/*#__PURE__*/s.createElement(b,f({},e,{ref:o}))))));/*#__PURE__*/const b=/*#__PURE__*/s.forwardRef(((n,i)=>{const{__scopeRovingFocusGroup:u,orientation:l,loop:d=!1,dir:v,currentTabStopId:g,defaultCurrentTabStopId:w,onCurrentTabStopIdChange:b,onEntryFocus:x,...E}=n,I=s.useRef(null),G=c(i,I),h=e(v),[T=null,A]=o({prop:g,defaultProp:w,onChange:b}),[y,D]=s.useState(!1),S=r(x),_=m(u),C=s.useRef(!1);return s.useEffect((()=>{const e=I.current;if(e)return e.addEventListener("rovingFocusGroup.onEntryFocus",S),()=>e.removeEventListener("rovingFocusGroup.onEntryFocus",S)}),[S]),/*#__PURE__*/s.createElement(F,{scope:u,orientation:l,dir:h,loop:d,currentTabStopId:T,onItemFocus:s.useCallback((e=>A(e)),[A]),onItemShiftTab:s.useCallback((()=>D(!0)),[])},/*#__PURE__*/s.createElement(t.div,f({tabIndex:y?-1:0,"data-orientation":l},E,{ref:G,style:{outline:"none",...n.style},onMouseDown:a(n.onMouseDown,(()=>{C.current=!0})),onFocus:a(n.onFocus,(e=>{const o=!C.current;if(e.target===e.currentTarget&&o&&!y){const o=new Event("rovingFocusGroup.onEntryFocus",p);if(e.currentTarget.dispatchEvent(o),!o.defaultPrevented){const e=_().filter((e=>e.focusable));R([e.find((e=>e.active)),e.find((e=>e.id===T)),...e].filter(Boolean).map((e=>e.ref.current)))}}C.current=!1})),onBlur:a(n.onBlur,(()=>D(!1)))})))}));export const RovingFocusGroupItem=/*#__PURE__*/s.forwardRef(((e,o)=>{const{__scopeRovingFocusGroup:r,focusable:i=!0,active:c=!1,...u}=e,p=n(),d=w("RovingFocusGroupItem",r),v=d.currentTabStopId===p,g=m(r);/*#__PURE__*/return s.createElement(l.ItemSlot,{scope:r,id:p,focusable:i,active:c},/*#__PURE__*/s.createElement(t.span,f({tabIndex:v?0:-1,"data-orientation":d.orientation},u,{ref:o,onMouseDown:a(e.onMouseDown,(e=>{i?d.onItemFocus(p):e.preventDefault()})),onFocus:a(e.onFocus,(()=>d.onItemFocus(p))),onKeyDown:a(e.onKeyDown,(e=>{if("Tab"===e.key&&e.shiftKey)return void d.onItemShiftTab();if(e.target!==e.currentTarget)return;const o=function(e,o,r){const t=function(e,o){return"rtl"!==o?e:"ArrowLeft"===e?"ArrowRight":"ArrowRight"===e?"ArrowLeft":e}(e.key,r);return"vertical"===o&&["ArrowLeft","ArrowRight"].includes(t)||"horizontal"===o&&["ArrowUp","ArrowDown"].includes(t)?void 0:x[t]}(e,d.orientation,d.dir);if(void 0!==o){e.preventDefault();let n=g().filter((e=>e.focusable)).map((e=>e.ref.current));if("last"===o)n.reverse();else if("prev"===o||"next"===o){"prev"===o&&n.reverse();const i=n.indexOf(e.currentTarget);n=d.loop?(t=i+1,(r=n).map(((e,o)=>r[(t+o)%r.length]))):n.slice(i+1)}setTimeout((()=>R(n)))}var r,t}))})))}));/*#__PURE__*/const x={ArrowLeft:"prev",ArrowUp:"prev",ArrowRight:"next",ArrowDown:"next",PageUp:"first",Home:"first",PageDown:"last",End:"last"};function R(e){const o=document.activeElement;for(const r of e){if(r===o)return;if(r.focus(),document.activeElement!==o)return}}export const Root=RovingFocusGroup;export const Item=RovingFocusGroupItem; | ||
import $98Iye$babelruntimehelpersesmextends from "@babel/runtime/helpers/esm/extends"; | ||
import {forwardRef as $98Iye$forwardRef, createElement as $98Iye$createElement, useRef as $98Iye$useRef, useState as $98Iye$useState, useEffect as $98Iye$useEffect, useCallback as $98Iye$useCallback} from "react"; | ||
import {composeEventHandlers as $98Iye$composeEventHandlers} from "@radix-ui/primitive"; | ||
import {createCollection as $98Iye$createCollection} from "@radix-ui/react-collection"; | ||
import {useComposedRefs as $98Iye$useComposedRefs} from "@radix-ui/react-compose-refs"; | ||
import {createContextScope as $98Iye$createContextScope} from "@radix-ui/react-context"; | ||
import {useId as $98Iye$useId} from "@radix-ui/react-id"; | ||
import {Primitive as $98Iye$Primitive} from "@radix-ui/react-primitive"; | ||
import {useCallbackRef as $98Iye$useCallbackRef} from "@radix-ui/react-use-callback-ref"; | ||
import {useControllableState as $98Iye$useControllableState} from "@radix-ui/react-use-controllable-state"; | ||
import {useDirection as $98Iye$useDirection} from "@radix-ui/react-direction"; | ||
function $parcel$export(e, n, v, s) { | ||
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true}); | ||
} | ||
var $d7bdfb9eb0fdf311$exports = {}; | ||
$parcel$export($d7bdfb9eb0fdf311$exports, "createRovingFocusGroupScope", () => $d7bdfb9eb0fdf311$export$c7109489551a4f4); | ||
$parcel$export($d7bdfb9eb0fdf311$exports, "RovingFocusGroup", () => $d7bdfb9eb0fdf311$export$8699f7c8af148338); | ||
$parcel$export($d7bdfb9eb0fdf311$exports, "RovingFocusGroupItem", () => $d7bdfb9eb0fdf311$export$ab9df7c53fe8454); | ||
$parcel$export($d7bdfb9eb0fdf311$exports, "Root", () => $d7bdfb9eb0fdf311$export$be92b6f5f03c0fe9); | ||
$parcel$export($d7bdfb9eb0fdf311$exports, "Item", () => $d7bdfb9eb0fdf311$export$6d08773d2e66f8f2); | ||
const $d7bdfb9eb0fdf311$var$ENTRY_FOCUS = 'rovingFocusGroup.onEntryFocus'; | ||
const $d7bdfb9eb0fdf311$var$EVENT_OPTIONS = { | ||
bubbles: false, | ||
cancelable: true | ||
}; | ||
/* ------------------------------------------------------------------------------------------------- | ||
* RovingFocusGroup | ||
* -----------------------------------------------------------------------------------------------*/ const $d7bdfb9eb0fdf311$var$GROUP_NAME = 'RovingFocusGroup'; | ||
const [$d7bdfb9eb0fdf311$var$Collection, $d7bdfb9eb0fdf311$var$useCollection, $d7bdfb9eb0fdf311$var$createCollectionScope] = $98Iye$createCollection($d7bdfb9eb0fdf311$var$GROUP_NAME); | ||
const [$d7bdfb9eb0fdf311$var$createRovingFocusGroupContext, $d7bdfb9eb0fdf311$export$c7109489551a4f4] = $98Iye$createContextScope($d7bdfb9eb0fdf311$var$GROUP_NAME, [ | ||
$d7bdfb9eb0fdf311$var$createCollectionScope | ||
]); | ||
const [$d7bdfb9eb0fdf311$var$RovingFocusProvider, $d7bdfb9eb0fdf311$var$useRovingFocusContext] = $d7bdfb9eb0fdf311$var$createRovingFocusGroupContext($d7bdfb9eb0fdf311$var$GROUP_NAME); | ||
const $d7bdfb9eb0fdf311$export$8699f7c8af148338 = /*#__PURE__*/ $98Iye$forwardRef((props, forwardedRef)=>{ | ||
return /*#__PURE__*/ $98Iye$createElement($d7bdfb9eb0fdf311$var$Collection.Provider, { | ||
scope: props.__scopeRovingFocusGroup | ||
}, /*#__PURE__*/ $98Iye$createElement($d7bdfb9eb0fdf311$var$Collection.Slot, { | ||
scope: props.__scopeRovingFocusGroup | ||
}, /*#__PURE__*/ $98Iye$createElement($d7bdfb9eb0fdf311$var$RovingFocusGroupImpl, $98Iye$babelruntimehelpersesmextends({}, props, { | ||
ref: forwardedRef | ||
})))); | ||
}); | ||
/*#__PURE__*/ Object.assign($d7bdfb9eb0fdf311$export$8699f7c8af148338, { | ||
displayName: $d7bdfb9eb0fdf311$var$GROUP_NAME | ||
}); | ||
/* -----------------------------------------------------------------------------------------------*/ const $d7bdfb9eb0fdf311$var$RovingFocusGroupImpl = /*#__PURE__*/ $98Iye$forwardRef((props, forwardedRef)=>{ | ||
const { __scopeRovingFocusGroup: __scopeRovingFocusGroup , orientation: orientation , loop: loop = false , dir: dir , currentTabStopId: currentTabStopIdProp , defaultCurrentTabStopId: defaultCurrentTabStopId , onCurrentTabStopIdChange: onCurrentTabStopIdChange , onEntryFocus: onEntryFocus , ...groupProps } = props; | ||
const ref = $98Iye$useRef(null); | ||
const composedRefs = $98Iye$useComposedRefs(forwardedRef, ref); | ||
const direction = $98Iye$useDirection(dir); | ||
const [currentTabStopId = null, setCurrentTabStopId] = $98Iye$useControllableState({ | ||
prop: currentTabStopIdProp, | ||
defaultProp: defaultCurrentTabStopId, | ||
onChange: onCurrentTabStopIdChange | ||
}); | ||
const [isTabbingBackOut, setIsTabbingBackOut] = $98Iye$useState(false); | ||
const handleEntryFocus = $98Iye$useCallbackRef(onEntryFocus); | ||
const getItems = $d7bdfb9eb0fdf311$var$useCollection(__scopeRovingFocusGroup); | ||
const isClickFocusRef = $98Iye$useRef(false); | ||
$98Iye$useEffect(()=>{ | ||
const node = ref.current; | ||
if (node) { | ||
node.addEventListener($d7bdfb9eb0fdf311$var$ENTRY_FOCUS, handleEntryFocus); | ||
return ()=>node.removeEventListener($d7bdfb9eb0fdf311$var$ENTRY_FOCUS, handleEntryFocus) | ||
; | ||
} | ||
}, [ | ||
handleEntryFocus | ||
]); | ||
return /*#__PURE__*/ $98Iye$createElement($d7bdfb9eb0fdf311$var$RovingFocusProvider, { | ||
scope: __scopeRovingFocusGroup, | ||
orientation: orientation, | ||
dir: direction, | ||
loop: loop, | ||
currentTabStopId: currentTabStopId, | ||
onItemFocus: $98Iye$useCallback((tabStopId)=>setCurrentTabStopId(tabStopId) | ||
, [ | ||
setCurrentTabStopId | ||
]), | ||
onItemShiftTab: $98Iye$useCallback(()=>setIsTabbingBackOut(true) | ||
, []) | ||
}, /*#__PURE__*/ $98Iye$createElement($98Iye$Primitive.div, $98Iye$babelruntimehelpersesmextends({ | ||
tabIndex: isTabbingBackOut ? -1 : 0, | ||
"data-orientation": orientation | ||
}, groupProps, { | ||
ref: composedRefs, | ||
style: { | ||
outline: 'none', | ||
...props.style | ||
}, | ||
onMouseDown: $98Iye$composeEventHandlers(props.onMouseDown, ()=>{ | ||
isClickFocusRef.current = true; | ||
}), | ||
onFocus: $98Iye$composeEventHandlers(props.onFocus, (event)=>{ | ||
// We normally wouldn't need this check, because we already check | ||
// that the focus is on the current target and not bubbling to it. | ||
// We do this because Safari doesn't focus buttons when clicked, and | ||
// instead, the wrapper will get focused and not through a bubbling event. | ||
const isKeyboardFocus = !isClickFocusRef.current; | ||
if (event.target === event.currentTarget && isKeyboardFocus && !isTabbingBackOut) { | ||
const entryFocusEvent = new Event($d7bdfb9eb0fdf311$var$ENTRY_FOCUS, $d7bdfb9eb0fdf311$var$EVENT_OPTIONS); | ||
event.currentTarget.dispatchEvent(entryFocusEvent); | ||
if (!entryFocusEvent.defaultPrevented) { | ||
const items = getItems().filter((item)=>item.focusable | ||
); | ||
const activeItem = items.find((item)=>item.active | ||
); | ||
const currentItem = items.find((item)=>item.id === currentTabStopId | ||
); | ||
const candidateItems = [ | ||
activeItem, | ||
currentItem, | ||
...items | ||
].filter(Boolean); | ||
const candidateNodes = candidateItems.map((item)=>item.ref.current | ||
); | ||
$d7bdfb9eb0fdf311$var$focusFirst(candidateNodes); | ||
} | ||
} | ||
isClickFocusRef.current = false; | ||
}), | ||
onBlur: $98Iye$composeEventHandlers(props.onBlur, ()=>setIsTabbingBackOut(false) | ||
) | ||
}))); | ||
}); | ||
/* ------------------------------------------------------------------------------------------------- | ||
* RovingFocusGroupItem | ||
* -----------------------------------------------------------------------------------------------*/ const $d7bdfb9eb0fdf311$var$ITEM_NAME = 'RovingFocusGroupItem'; | ||
const $d7bdfb9eb0fdf311$export$ab9df7c53fe8454 = /*#__PURE__*/ $98Iye$forwardRef((props, forwardedRef)=>{ | ||
const { __scopeRovingFocusGroup: __scopeRovingFocusGroup , focusable: focusable = true , active: active = false , ...itemProps } = props; | ||
const id = $98Iye$useId(); | ||
const context = $d7bdfb9eb0fdf311$var$useRovingFocusContext($d7bdfb9eb0fdf311$var$ITEM_NAME, __scopeRovingFocusGroup); | ||
const isCurrentTabStop = context.currentTabStopId === id; | ||
const getItems = $d7bdfb9eb0fdf311$var$useCollection(__scopeRovingFocusGroup); | ||
return /*#__PURE__*/ $98Iye$createElement($d7bdfb9eb0fdf311$var$Collection.ItemSlot, { | ||
scope: __scopeRovingFocusGroup, | ||
id: id, | ||
focusable: focusable, | ||
active: active | ||
}, /*#__PURE__*/ $98Iye$createElement($98Iye$Primitive.span, $98Iye$babelruntimehelpersesmextends({ | ||
tabIndex: isCurrentTabStop ? 0 : -1, | ||
"data-orientation": context.orientation | ||
}, itemProps, { | ||
ref: forwardedRef, | ||
onMouseDown: $98Iye$composeEventHandlers(props.onMouseDown, (event)=>{ | ||
// We prevent focusing non-focusable items on `mousedown`. | ||
// Even though the item has tabIndex={-1}, that only means take it out of the tab order. | ||
if (!focusable) event.preventDefault(); // Safari doesn't focus a button when clicked so we run our logic on mousedown also | ||
else context.onItemFocus(id); | ||
}), | ||
onFocus: $98Iye$composeEventHandlers(props.onFocus, ()=>context.onItemFocus(id) | ||
), | ||
onKeyDown: $98Iye$composeEventHandlers(props.onKeyDown, (event)=>{ | ||
if (event.key === 'Tab' && event.shiftKey) { | ||
context.onItemShiftTab(); | ||
return; | ||
} | ||
if (event.target !== event.currentTarget) return; | ||
const focusIntent = $d7bdfb9eb0fdf311$var$getFocusIntent(event, context.orientation, context.dir); | ||
if (focusIntent !== undefined) { | ||
event.preventDefault(); | ||
const items = getItems().filter((item)=>item.focusable | ||
); | ||
let candidateNodes = items.map((item)=>item.ref.current | ||
); | ||
if (focusIntent === 'last') candidateNodes.reverse(); | ||
else if (focusIntent === 'prev' || focusIntent === 'next') { | ||
if (focusIntent === 'prev') candidateNodes.reverse(); | ||
const currentIndex = candidateNodes.indexOf(event.currentTarget); | ||
candidateNodes = context.loop ? $d7bdfb9eb0fdf311$var$wrapArray(candidateNodes, currentIndex + 1) : candidateNodes.slice(currentIndex + 1); | ||
} | ||
/** | ||
* Imperative focus during keydown is risky so we prevent React's batching updates | ||
* to avoid potential bugs. See: https://github.com/facebook/react/issues/20332 | ||
*/ setTimeout(()=>$d7bdfb9eb0fdf311$var$focusFirst(candidateNodes) | ||
); | ||
} | ||
}) | ||
}))); | ||
}); | ||
/*#__PURE__*/ Object.assign($d7bdfb9eb0fdf311$export$ab9df7c53fe8454, { | ||
displayName: $d7bdfb9eb0fdf311$var$ITEM_NAME | ||
}); | ||
/* -----------------------------------------------------------------------------------------------*/ // prettier-ignore | ||
const $d7bdfb9eb0fdf311$var$MAP_KEY_TO_FOCUS_INTENT = { | ||
ArrowLeft: 'prev', | ||
ArrowUp: 'prev', | ||
ArrowRight: 'next', | ||
ArrowDown: 'next', | ||
PageUp: 'first', | ||
Home: 'first', | ||
PageDown: 'last', | ||
End: 'last' | ||
}; | ||
function $d7bdfb9eb0fdf311$var$getDirectionAwareKey(key, dir) { | ||
if (dir !== 'rtl') return key; | ||
return key === 'ArrowLeft' ? 'ArrowRight' : key === 'ArrowRight' ? 'ArrowLeft' : key; | ||
} | ||
function $d7bdfb9eb0fdf311$var$getFocusIntent(event, orientation, dir) { | ||
const key = $d7bdfb9eb0fdf311$var$getDirectionAwareKey(event.key, dir); | ||
if (orientation === 'vertical' && [ | ||
'ArrowLeft', | ||
'ArrowRight' | ||
].includes(key)) return undefined; | ||
if (orientation === 'horizontal' && [ | ||
'ArrowUp', | ||
'ArrowDown' | ||
].includes(key)) return undefined; | ||
return $d7bdfb9eb0fdf311$var$MAP_KEY_TO_FOCUS_INTENT[key]; | ||
} | ||
function $d7bdfb9eb0fdf311$var$focusFirst(candidates) { | ||
const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement; | ||
for (const candidate of candidates){ | ||
// if focus is already where we want to go, we don't want to keep going through the candidates | ||
if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return; | ||
candidate.focus(); | ||
if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return; | ||
} | ||
} | ||
/** | ||
* Wraps an array around itself at a given start index | ||
* Example: `wrapArray(['a', 'b', 'c', 'd'], 2) === ['c', 'd', 'a', 'b']` | ||
*/ function $d7bdfb9eb0fdf311$var$wrapArray(array, startIndex) { | ||
return array.map((_, index)=>array[(startIndex + index) % array.length] | ||
); | ||
} | ||
const $d7bdfb9eb0fdf311$export$be92b6f5f03c0fe9 = $d7bdfb9eb0fdf311$export$8699f7c8af148338; | ||
const $d7bdfb9eb0fdf311$export$6d08773d2e66f8f2 = $d7bdfb9eb0fdf311$export$ab9df7c53fe8454; | ||
export {$d7bdfb9eb0fdf311$export$c7109489551a4f4 as createRovingFocusGroupScope, $d7bdfb9eb0fdf311$export$8699f7c8af148338 as RovingFocusGroup, $d7bdfb9eb0fdf311$export$ab9df7c53fe8454 as RovingFocusGroupItem, $d7bdfb9eb0fdf311$export$be92b6f5f03c0fe9 as Root, $d7bdfb9eb0fdf311$export$6d08773d2e66f8f2 as Item}; | ||
//# sourceMappingURL=index.module.js.map |
{ | ||
"name": "@radix-ui/react-roving-focus", | ||
"version": "0.1.6-rc.5", | ||
"version": "0.1.6-rc.6", | ||
"license": "MIT", | ||
@@ -21,10 +21,10 @@ "source": "src/index.ts", | ||
"@radix-ui/primitive": "0.1.0", | ||
"@radix-ui/react-collection": "0.1.5-rc.2", | ||
"@radix-ui/react-compose-refs": "0.1.1-rc.2", | ||
"@radix-ui/react-context": "0.1.2-rc.2", | ||
"@radix-ui/react-direction": "0.1.0-rc.5", | ||
"@radix-ui/react-id": "0.1.6-rc.2", | ||
"@radix-ui/react-primitive": "0.1.5-rc.2", | ||
"@radix-ui/react-use-callback-ref": "0.1.1-rc.2", | ||
"@radix-ui/react-use-controllable-state": "0.1.1-rc.2" | ||
"@radix-ui/react-collection": "0.1.5-rc.3", | ||
"@radix-ui/react-compose-refs": "0.1.1-rc.3", | ||
"@radix-ui/react-context": "0.1.2-rc.3", | ||
"@radix-ui/react-direction": "0.1.0-rc.6", | ||
"@radix-ui/react-id": "0.1.6-rc.3", | ||
"@radix-ui/react-primitive": "0.1.5-rc.3", | ||
"@radix-ui/react-use-callback-ref": "0.1.1-rc.3", | ||
"@radix-ui/react-use-controllable-state": "0.1.1-rc.3" | ||
}, | ||
@@ -31,0 +31,0 @@ "peerDependencies": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
75895
521
1
1
+ Added@radix-ui/react-collection@0.1.5-rc.3(transitive)
+ Added@radix-ui/react-compose-refs@0.1.1-rc.3(transitive)
+ Added@radix-ui/react-context@0.1.2-rc.3(transitive)
+ Added@radix-ui/react-direction@0.1.0-rc.6(transitive)
+ Added@radix-ui/react-id@0.1.6-rc.3(transitive)
+ Added@radix-ui/react-primitive@0.1.5-rc.3(transitive)
+ Added@radix-ui/react-slot@0.1.3-rc.3(transitive)
+ Added@radix-ui/react-use-callback-ref@0.1.1-rc.3(transitive)
+ Added@radix-ui/react-use-controllable-state@0.1.1-rc.3(transitive)
+ Added@radix-ui/react-use-layout-effect@0.1.1-rc.3(transitive)
- Removed@radix-ui/react-collection@0.1.5-rc.2(transitive)
- Removed@radix-ui/react-compose-refs@0.1.1-rc.2(transitive)
- Removed@radix-ui/react-context@0.1.2-rc.2(transitive)
- Removed@radix-ui/react-direction@0.1.0-rc.5(transitive)
- Removed@radix-ui/react-id@0.1.6-rc.2(transitive)
- Removed@radix-ui/react-primitive@0.1.5-rc.2(transitive)
- Removed@radix-ui/react-slot@0.1.3-rc.2(transitive)
- Removed@radix-ui/react-use-callback-ref@0.1.1-rc.2(transitive)
- Removed@radix-ui/react-use-controllable-state@0.1.1-rc.2(transitive)
- Removed@radix-ui/react-use-layout-effect@0.1.1-rc.2(transitive)