257 lines
13 KiB
JavaScript
257 lines
13 KiB
JavaScript
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";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
const [focusableItemsCount, setFocusableItemsCount] = $98Iye$useState(0);
|
|
$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)
|
|
, []),
|
|
onFocusableItemAdd: $98Iye$useCallback(()=>setFocusableItemsCount((prevCount)=>prevCount + 1
|
|
)
|
|
, []),
|
|
onFocusableItemRemove: $98Iye$useCallback(()=>setFocusableItemsCount((prevCount)=>prevCount - 1
|
|
)
|
|
, [])
|
|
}, /*#__PURE__*/ $98Iye$createElement($98Iye$Primitive.div, $98Iye$babelruntimehelpersesmextends({
|
|
tabIndex: isTabbingBackOut || focusableItemsCount === 0 ? -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 CustomEvent($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 , tabStopId: tabStopId , ...itemProps } = props;
|
|
const autoId = $98Iye$useId();
|
|
const id = tabStopId || autoId;
|
|
const context = $d7bdfb9eb0fdf311$var$useRovingFocusContext($d7bdfb9eb0fdf311$var$ITEM_NAME, __scopeRovingFocusGroup);
|
|
const isCurrentTabStop = context.currentTabStopId === id;
|
|
const getItems = $d7bdfb9eb0fdf311$var$useCollection(__scopeRovingFocusGroup);
|
|
const { onFocusableItemAdd: onFocusableItemAdd , onFocusableItemRemove: onFocusableItemRemove } = context;
|
|
$98Iye$useEffect(()=>{
|
|
if (focusable) {
|
|
onFocusableItemAdd();
|
|
return ()=>onFocusableItemRemove()
|
|
;
|
|
}
|
|
}, [
|
|
focusable,
|
|
onFocusableItemAdd,
|
|
onFocusableItemRemove
|
|
]);
|
|
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
|