@ariakit/react-core
Version:
Ariakit React core
177 lines (174 loc) • 5.45 kB
JavaScript
"use client";
import {
selectTextField
} from "./5VQZOHHZ.js";
import {
useCompositeContext
} from "./APTFW6PT.js";
import {
useStoreState
} from "./RTNCFSKZ.js";
import {
createElement,
createHook,
forwardRef
} from "./VOQWLFSQ.js";
import {
useEvent,
useMergeRefs
} from "./5GGHRIN3.js";
import {
__objRest,
__spreadProps,
__spreadValues
} from "./3YLGPPWQ.js";
// src/composite/composite-container.tsx
import { isButton, isTextField } from "@ariakit/core/utils/dom";
import { isFocusEventOutside, isSelfTarget } from "@ariakit/core/utils/events";
import {
disableFocusIn,
getFirstTabbableIn,
restoreFocusIn
} from "@ariakit/core/utils/focus";
import { removeUndefinedValues } from "@ariakit/core/utils/misc";
import { useEffect, useRef } from "react";
var TagName = "div";
function getFirstTabbable(container) {
restoreFocusIn(container);
const tabbable = getFirstTabbableIn(container);
disableFocusIn(container);
return tabbable;
}
var useCompositeContainer = createHook(function useCompositeContainer2(_a) {
var _b = _a, { store } = _b, props = __objRest(_b, ["store"]);
const context = useCompositeContext();
store = store || context;
const ref = useRef(null);
const isOpenRef = useRef(false);
const open = (collapseToEnd = false) => {
const container = ref.current;
if (!container) return;
restoreFocusIn(container);
const tabbable = getFirstTabbableIn(container);
if (!tabbable) {
disableFocusIn(container);
return;
}
isOpenRef.current = true;
queueMicrotask(() => {
tabbable.focus();
if (isTextField(tabbable) || tabbable.isContentEditable) {
selectTextField(tabbable, collapseToEnd);
}
});
};
const close = () => {
const container = ref.current;
if (!container) return;
isOpenRef.current = false;
disableFocusIn(container);
};
const renderedItems = useStoreState(store, "renderedItems");
useEffect(() => {
const container = ref.current;
if (!container) return;
const isOpen = isOpenRef.current;
if (!isOpen && (renderedItems == null ? void 0 : renderedItems.length)) {
disableFocusIn(container);
}
}, [renderedItems]);
const onFocusProp = props.onFocus;
const onFocus = useEvent((event) => {
onFocusProp == null ? void 0 : onFocusProp(event);
if (event.defaultPrevented) return;
if (!store) return;
const isOpen = isOpenRef.current;
if (isSelfTarget(event)) {
isOpenRef.current = false;
const { baseElement } = store.getState();
const composite = baseElement;
const selector = "[data-composite-container]";
const containers = composite == null ? void 0 : composite.querySelectorAll(selector);
if (containers) {
for (const container of containers) {
disableFocusIn(container);
}
}
} else if (!isOpen) {
isOpenRef.current = true;
restoreFocusIn(event.currentTarget);
store == null ? void 0 : store.setState("moves", 0);
}
});
const onBlurProp = props.onBlur;
const onBlur = useEvent((event) => {
onBlurProp == null ? void 0 : onBlurProp(event);
if (event.defaultPrevented) return;
if (isFocusEventOutside(event)) {
close();
}
});
const onKeyDownProp = props.onKeyDown;
const onKeyDown = useEvent((event) => {
onKeyDownProp == null ? void 0 : onKeyDownProp(event);
if (event.defaultPrevented) return;
if (event.altKey) return;
if (event.ctrlKey) return;
if (event.metaKey) return;
if (event.shiftKey) return;
const container = event.currentTarget;
if (isSelfTarget(event)) {
if (event.key.length === 1 && event.key !== " ") {
const tabbable = getFirstTabbable(container);
if (!tabbable) return;
if (isTextField(tabbable) || tabbable.isContentEditable) {
event.stopPropagation();
open();
}
} else if (event.key === "Delete" || event.key === "Backspace") {
const tabbable = getFirstTabbable(container);
if (!tabbable) return;
if (isTextField(tabbable) || tabbable.isContentEditable) {
open();
const onInput = () => queueMicrotask(() => container.focus());
container.addEventListener("input", onInput, { once: true });
}
}
} else if (event.key === "Escape") {
queueMicrotask(() => container.focus());
} else if (event.key === "Enter") {
const target = event.target;
const isInput = target.tagName === "INPUT" && !isButton(target) || target.tagName === "TEXTAREA";
if (isInput || target.isContentEditable) {
event.preventDefault();
queueMicrotask(() => container.focus());
}
}
});
const onClickProp = props.onClick;
const onClick = useEvent((event) => {
onClickProp == null ? void 0 : onClickProp(event);
if (event.defaultPrevented) return;
if (isSelfTarget(event) && !event.detail) {
open(true);
}
});
props = __spreadProps(__spreadValues({
"data-composite-container": ""
}, props), {
ref: useMergeRefs(ref, props.ref),
onFocus,
onBlur,
onKeyDown,
onClick
});
return removeUndefinedValues(props);
});
var CompositeContainer = forwardRef(function CompositeContainer2(props) {
const htmlProps = useCompositeContainer(props);
return createElement(TagName, htmlProps);
});
export {
useCompositeContainer,
CompositeContainer
};