Initial commit
This commit is contained in:
228
node_modules/@radix-ui/react-roving-focus/dist/index.mjs
generated
vendored
Normal file
228
node_modules/@radix-ui/react-roving-focus/dist/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
"use client";
|
||||
|
||||
// packages/react/roving-focus/src/roving-focus-group.tsx
|
||||
import * as React from "react";
|
||||
import { composeEventHandlers } from "@radix-ui/primitive";
|
||||
import { createCollection } from "@radix-ui/react-collection";
|
||||
import { useComposedRefs } from "@radix-ui/react-compose-refs";
|
||||
import { createContextScope } from "@radix-ui/react-context";
|
||||
import { useId } from "@radix-ui/react-id";
|
||||
import { Primitive } from "@radix-ui/react-primitive";
|
||||
import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
|
||||
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
||||
import { useDirection } from "@radix-ui/react-direction";
|
||||
import { jsx } from "react/jsx-runtime";
|
||||
var ENTRY_FOCUS = "rovingFocusGroup.onEntryFocus";
|
||||
var EVENT_OPTIONS = { bubbles: false, cancelable: true };
|
||||
var GROUP_NAME = "RovingFocusGroup";
|
||||
var [Collection, useCollection, createCollectionScope] = createCollection(GROUP_NAME);
|
||||
var [createRovingFocusGroupContext, createRovingFocusGroupScope] = createContextScope(
|
||||
GROUP_NAME,
|
||||
[createCollectionScope]
|
||||
);
|
||||
var [RovingFocusProvider, useRovingFocusContext] = createRovingFocusGroupContext(GROUP_NAME);
|
||||
var RovingFocusGroup = React.forwardRef(
|
||||
(props, forwardedRef) => {
|
||||
return /* @__PURE__ */ jsx(Collection.Provider, { scope: props.__scopeRovingFocusGroup, children: /* @__PURE__ */ jsx(Collection.Slot, { scope: props.__scopeRovingFocusGroup, children: /* @__PURE__ */ jsx(RovingFocusGroupImpl, { ...props, ref: forwardedRef }) }) });
|
||||
}
|
||||
);
|
||||
RovingFocusGroup.displayName = GROUP_NAME;
|
||||
var RovingFocusGroupImpl = React.forwardRef((props, forwardedRef) => {
|
||||
const {
|
||||
__scopeRovingFocusGroup,
|
||||
orientation,
|
||||
loop = false,
|
||||
dir,
|
||||
currentTabStopId: currentTabStopIdProp,
|
||||
defaultCurrentTabStopId,
|
||||
onCurrentTabStopIdChange,
|
||||
onEntryFocus,
|
||||
preventScrollOnEntryFocus = false,
|
||||
...groupProps
|
||||
} = props;
|
||||
const ref = React.useRef(null);
|
||||
const composedRefs = useComposedRefs(forwardedRef, ref);
|
||||
const direction = useDirection(dir);
|
||||
const [currentTabStopId = null, setCurrentTabStopId] = useControllableState({
|
||||
prop: currentTabStopIdProp,
|
||||
defaultProp: defaultCurrentTabStopId,
|
||||
onChange: onCurrentTabStopIdChange
|
||||
});
|
||||
const [isTabbingBackOut, setIsTabbingBackOut] = React.useState(false);
|
||||
const handleEntryFocus = useCallbackRef(onEntryFocus);
|
||||
const getItems = useCollection(__scopeRovingFocusGroup);
|
||||
const isClickFocusRef = React.useRef(false);
|
||||
const [focusableItemsCount, setFocusableItemsCount] = React.useState(0);
|
||||
React.useEffect(() => {
|
||||
const node = ref.current;
|
||||
if (node) {
|
||||
node.addEventListener(ENTRY_FOCUS, handleEntryFocus);
|
||||
return () => node.removeEventListener(ENTRY_FOCUS, handleEntryFocus);
|
||||
}
|
||||
}, [handleEntryFocus]);
|
||||
return /* @__PURE__ */ jsx(
|
||||
RovingFocusProvider,
|
||||
{
|
||||
scope: __scopeRovingFocusGroup,
|
||||
orientation,
|
||||
dir: direction,
|
||||
loop,
|
||||
currentTabStopId,
|
||||
onItemFocus: React.useCallback(
|
||||
(tabStopId) => setCurrentTabStopId(tabStopId),
|
||||
[setCurrentTabStopId]
|
||||
),
|
||||
onItemShiftTab: React.useCallback(() => setIsTabbingBackOut(true), []),
|
||||
onFocusableItemAdd: React.useCallback(
|
||||
() => setFocusableItemsCount((prevCount) => prevCount + 1),
|
||||
[]
|
||||
),
|
||||
onFocusableItemRemove: React.useCallback(
|
||||
() => setFocusableItemsCount((prevCount) => prevCount - 1),
|
||||
[]
|
||||
),
|
||||
children: /* @__PURE__ */ jsx(
|
||||
Primitive.div,
|
||||
{
|
||||
tabIndex: isTabbingBackOut || focusableItemsCount === 0 ? -1 : 0,
|
||||
"data-orientation": orientation,
|
||||
...groupProps,
|
||||
ref: composedRefs,
|
||||
style: { outline: "none", ...props.style },
|
||||
onMouseDown: composeEventHandlers(props.onMouseDown, () => {
|
||||
isClickFocusRef.current = true;
|
||||
}),
|
||||
onFocus: composeEventHandlers(props.onFocus, (event) => {
|
||||
const isKeyboardFocus = !isClickFocusRef.current;
|
||||
if (event.target === event.currentTarget && isKeyboardFocus && !isTabbingBackOut) {
|
||||
const entryFocusEvent = new CustomEvent(ENTRY_FOCUS, 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);
|
||||
focusFirst(candidateNodes, preventScrollOnEntryFocus);
|
||||
}
|
||||
}
|
||||
isClickFocusRef.current = false;
|
||||
}),
|
||||
onBlur: composeEventHandlers(props.onBlur, () => setIsTabbingBackOut(false))
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
});
|
||||
var ITEM_NAME = "RovingFocusGroupItem";
|
||||
var RovingFocusGroupItem = React.forwardRef(
|
||||
(props, forwardedRef) => {
|
||||
const {
|
||||
__scopeRovingFocusGroup,
|
||||
focusable = true,
|
||||
active = false,
|
||||
tabStopId,
|
||||
...itemProps
|
||||
} = props;
|
||||
const autoId = useId();
|
||||
const id = tabStopId || autoId;
|
||||
const context = useRovingFocusContext(ITEM_NAME, __scopeRovingFocusGroup);
|
||||
const isCurrentTabStop = context.currentTabStopId === id;
|
||||
const getItems = useCollection(__scopeRovingFocusGroup);
|
||||
const { onFocusableItemAdd, onFocusableItemRemove } = context;
|
||||
React.useEffect(() => {
|
||||
if (focusable) {
|
||||
onFocusableItemAdd();
|
||||
return () => onFocusableItemRemove();
|
||||
}
|
||||
}, [focusable, onFocusableItemAdd, onFocusableItemRemove]);
|
||||
return /* @__PURE__ */ jsx(
|
||||
Collection.ItemSlot,
|
||||
{
|
||||
scope: __scopeRovingFocusGroup,
|
||||
id,
|
||||
focusable,
|
||||
active,
|
||||
children: /* @__PURE__ */ jsx(
|
||||
Primitive.span,
|
||||
{
|
||||
tabIndex: isCurrentTabStop ? 0 : -1,
|
||||
"data-orientation": context.orientation,
|
||||
...itemProps,
|
||||
ref: forwardedRef,
|
||||
onMouseDown: composeEventHandlers(props.onMouseDown, (event) => {
|
||||
if (!focusable) event.preventDefault();
|
||||
else context.onItemFocus(id);
|
||||
}),
|
||||
onFocus: composeEventHandlers(props.onFocus, () => context.onItemFocus(id)),
|
||||
onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
|
||||
if (event.key === "Tab" && event.shiftKey) {
|
||||
context.onItemShiftTab();
|
||||
return;
|
||||
}
|
||||
if (event.target !== event.currentTarget) return;
|
||||
const focusIntent = getFocusIntent(event, context.orientation, context.dir);
|
||||
if (focusIntent !== void 0) {
|
||||
if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;
|
||||
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 ? wrapArray(candidateNodes, currentIndex + 1) : candidateNodes.slice(currentIndex + 1);
|
||||
}
|
||||
setTimeout(() => focusFirst(candidateNodes));
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
RovingFocusGroupItem.displayName = ITEM_NAME;
|
||||
var MAP_KEY_TO_FOCUS_INTENT = {
|
||||
ArrowLeft: "prev",
|
||||
ArrowUp: "prev",
|
||||
ArrowRight: "next",
|
||||
ArrowDown: "next",
|
||||
PageUp: "first",
|
||||
Home: "first",
|
||||
PageDown: "last",
|
||||
End: "last"
|
||||
};
|
||||
function getDirectionAwareKey(key, dir) {
|
||||
if (dir !== "rtl") return key;
|
||||
return key === "ArrowLeft" ? "ArrowRight" : key === "ArrowRight" ? "ArrowLeft" : key;
|
||||
}
|
||||
function getFocusIntent(event, orientation, dir) {
|
||||
const key = getDirectionAwareKey(event.key, dir);
|
||||
if (orientation === "vertical" && ["ArrowLeft", "ArrowRight"].includes(key)) return void 0;
|
||||
if (orientation === "horizontal" && ["ArrowUp", "ArrowDown"].includes(key)) return void 0;
|
||||
return MAP_KEY_TO_FOCUS_INTENT[key];
|
||||
}
|
||||
function focusFirst(candidates, preventScroll = false) {
|
||||
const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
|
||||
for (const candidate of candidates) {
|
||||
if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;
|
||||
candidate.focus({ preventScroll });
|
||||
if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;
|
||||
}
|
||||
}
|
||||
function wrapArray(array, startIndex) {
|
||||
return array.map((_, index) => array[(startIndex + index) % array.length]);
|
||||
}
|
||||
var Root = RovingFocusGroup;
|
||||
var Item = RovingFocusGroupItem;
|
||||
export {
|
||||
Item,
|
||||
Root,
|
||||
RovingFocusGroup,
|
||||
RovingFocusGroupItem,
|
||||
createRovingFocusGroupScope
|
||||
};
|
||||
//# sourceMappingURL=index.mjs.map
|
||||
Reference in New Issue
Block a user