@yamada-ui/react
Version:
React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion
423 lines (419 loc) • 14.5 kB
JavaScript
"use client";
const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
const require_children = require('../../utils/children.cjs');
const require_context = require('../../utils/context.cjs');
const require_dom = require('../../utils/dom.cjs');
const require_effect = require('../../utils/effect.cjs');
const require_ref = require('../../utils/ref.cjs');
const require_utils_index = require('../../utils/index.cjs');
const require_environment_provider = require('../../core/system/environment-provider.cjs');
const require_hooks_use_descendants_index = require('../use-descendants/index.cjs');
const require_use_disclosure = require('../use-disclosure/use-disclosure.cjs');
const require_use_popover = require('../../components/popover/use-popover.cjs');
let react = require("react");
react = require_rolldown_runtime.__toESM(react);
let react_jsx_runtime = require("react/jsx-runtime");
react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
let scroll_into_view_if_needed = require("scroll-into-view-if-needed");
scroll_into_view_if_needed = require_rolldown_runtime.__toESM(scroll_into_view_if_needed);
//#region src/hooks/use-combobox/index.tsx
const createComboboxItem = (children, { Group, Label, Option }) => {
return require_children.getValidChildren(children).filter(({ type }) => require_children.isSomeElement(type, Option) || require_children.isSomeElement(type, Group)).map(({ type, props }) => {
if (require_children.isSomeElement(type, Option)) return {
...props,
label: props.children
};
else {
const validChildren = require_children.getValidChildren(props.children);
const label = require_children.findChild(validChildren, Label);
return {
...props,
items: validChildren.filter(({ type: type$1 }) => require_children.isSomeElement(type$1, Option)).map(({ props: props$1 }) => ({
...props$1,
label: props$1.children
})),
label: label?.props.children ?? props.label
};
}
});
};
const createComboboxChildren = (items, { Empty, Group, Option }) => {
return items.map((item, index) => {
if ("data-empty" in item && Empty) {
const { label,...rest } = item;
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Empty, {
...rest,
children: label
}, index);
} else if ("items" in item) {
const { items: items$1 = [], label,...rest } = item;
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Group, {
label,
...rest,
children: items$1.map(({ label: label$1,...rest$1 }, index$1) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Option, {
...rest$1,
children: label$1
}, index$1))
}, index);
} else {
const { label,...rest } = item;
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Option, {
...rest,
children: label
}, index);
}
});
};
const { DescendantsContext: ComboboxDescendantsContext, useDescendant: useComboboxDescendant, useDescendantRegister: useComboboxDescendantRegister, useDescendants: useComboboxDescendants } = require_hooks_use_descendants_index.createDescendants();
const [ComboboxContext, useComboboxContext] = require_context.createContext({ name: "ComboboxContext" });
const [ComboboxGroupContext, useComboboxGroupContext] = require_context.createContext({ name: "ComboboxGroupContext" });
const useCombobox = (props = {}) => {
const [popoverProps, { "aria-label": ariaLabelProp, "aria-labelledby": ariaLabelledbyProp, closeOnSelect: closeOnSelectProp = true, defaultOpen, disabled, initialFocusValue, open: openProp, openOnClick = true, openOnEnter = true, openOnSpace = true, readOnly, selectFocusRef, selectOnSpace = true, onChange: onChangeProp, onClose: onCloseProp, onOpen: onOpenProp,...rest }] = require_use_popover.usePopoverProps(props, [
"disabled",
"open",
"defaultOpen",
"onOpen",
"onClose",
"openOnClick"
]);
const { getWindow } = require_environment_provider.useEnvironment();
const interactive = !(readOnly || disabled);
const triggerRef = (0, react.useRef)(null);
const contentRef = (0, react.useRef)(null);
const contentId = (0, react.useId)();
const descendants = useComboboxDescendants();
const { open, onClose, onOpen } = require_use_disclosure.useDisclosure({
defaultOpen,
open: openProp,
onClose: onCloseProp,
onOpen: onOpenProp
});
const activeDescendant = (0, react.useRef)(null);
const mergedPopoverProps = (0, react.useMemo)(() => ({
autoFocus: false,
matchWidth: true,
openOnClick: false,
...popoverProps,
disabled: !interactive,
open,
onClose,
onOpen
}), [
interactive,
onClose,
onOpen,
open,
popoverProps
]);
const onSelect = (0, react.useCallback)((value, closeOnSelect = closeOnSelectProp) => {
(selectFocusRef ?? triggerRef).current?.focus();
if (!interactive || (0, require_utils_index.utils_exports.isUndefined)(value)) return;
onChangeProp?.(value);
if (!closeOnSelect) return;
onClose();
}, [
closeOnSelectProp,
interactive,
onChangeProp,
onClose,
selectFocusRef
]);
const onScrollIntoView = (0, react.useCallback)((descendant, block = "start") => {
if (!contentRef.current || !descendant) return;
const style = getWindow()?.getComputedStyle(contentRef.current);
const padding = block === "start" ? style?.paddingBlockStart : style?.paddingBlockEnd;
const value = parseInt(padding ?? "0px");
(0, scroll_into_view_if_needed.default)(descendant.node, {
behavior: (actions) => actions.forEach(({ el, top }) => {
el.scrollTop = block === "start" ? top - value : top + value;
}),
block,
boundary: contentRef.current,
inline: "nearest",
scrollMode: "if-needed"
});
}, [getWindow]);
const onActiveDescendant = (0, react.useCallback)((descendant) => {
if (!triggerRef.current || !descendant || disabled) return;
triggerRef.current.setAttribute("aria-activedescendant", descendant.id);
activeDescendant.current = descendant;
descendants.active(descendant);
}, [descendants, disabled]);
const onOpenWithActiveDescendant = (0, react.useCallback)((getFallbackDescendant, block = "start") => {
onOpen();
setTimeout(() => {
if (!initialFocusValue) {
const descendant = getFallbackDescendant();
onActiveDescendant(descendant);
onScrollIntoView(descendant, block);
} else {
const descendant = descendants.values().find(({ value }) => initialFocusValue === value) ?? getFallbackDescendant();
onActiveDescendant(descendant);
onScrollIntoView(descendant, block);
}
});
}, [
descendants,
initialFocusValue,
onActiveDescendant,
onOpen,
onScrollIntoView
]);
const onClick = (0, react.useCallback)((ev) => {
if (disabled) return;
ev.preventDefault();
if (!open) {
if (openOnClick) onOpenWithActiveDescendant(descendants.enabledFirstValue);
} else onClose();
}, [
descendants,
disabled,
onClose,
onOpenWithActiveDescendant,
open,
openOnClick
]);
const onKeyDown = (0, react.useCallback)((ev) => {
if (disabled || require_dom.isComposing(ev)) return;
require_dom.runKeyAction(ev, {
ArrowDown: (ev$1) => {
ev$1.preventDefault();
if (!open) onOpenWithActiveDescendant(descendants.enabledFirstValue);
else if (activeDescendant.current) {
const descendant = descendants.enabledNextValue(activeDescendant.current);
onActiveDescendant(descendant);
onScrollIntoView(descendant, descendant?.recurred ? "start" : "end");
} else {
const descendant = descendants.enabledFirstValue();
onActiveDescendant(descendant);
onScrollIntoView(descendant);
}
},
ArrowUp: (ev$1) => {
ev$1.preventDefault();
if (!open) onOpenWithActiveDescendant(descendants.enabledLastValue, "end");
else if (activeDescendant.current) {
const descendant = descendants.enabledPrevValue(activeDescendant.current);
onActiveDescendant(descendant);
onScrollIntoView(descendant, descendant?.recurred ? "end" : "start");
} else {
const descendant = descendants.enabledLastValue();
onActiveDescendant(descendant);
onScrollIntoView(descendant, "end");
}
},
End: (ev$1) => {
ev$1.preventDefault();
if (!open) return;
const descendant = descendants.enabledLastValue();
onActiveDescendant(descendant);
onScrollIntoView(descendant, "end");
},
Enter: (ev$1) => {
if (!open) {
if (!openOnEnter) return;
ev$1.preventDefault();
onOpenWithActiveDescendant(descendants.enabledFirstValue);
} else {
if (!activeDescendant.current) return;
ev$1.preventDefault();
const { closeOnSelect, value } = activeDescendant.current;
onSelect(value, closeOnSelect);
}
},
Home: (ev$1) => {
if (!open) return;
ev$1.preventDefault();
const descendant = descendants.enabledFirstValue();
onActiveDescendant(descendant);
onScrollIntoView(descendant);
},
Space: (ev$1) => {
if (!open) {
if (!openOnSpace) return;
ev$1.preventDefault();
onOpenWithActiveDescendant(descendants.enabledFirstValue);
} else {
if (!activeDescendant.current || !selectOnSpace) return;
ev$1.preventDefault();
const { closeOnSelect, value } = activeDescendant.current;
onSelect(value, closeOnSelect);
}
}
}, { preventDefault: false });
}, [
disabled,
open,
onOpenWithActiveDescendant,
descendants,
onActiveDescendant,
onScrollIntoView,
openOnEnter,
onSelect,
openOnSpace,
selectOnSpace
]);
require_effect.useUpdateEffect(() => {
if (open) return;
activeDescendant.current = null;
}, [open]);
const getTriggerProps = (0, react.useCallback)(({ ref, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby,...props$1 } = {}) => ({
"aria-controls": open ? contentId : void 0,
"aria-disabled": (0, require_utils_index.utils_exports.ariaAttr)(!interactive),
"aria-expanded": open,
"aria-haspopup": "listbox",
"aria-label": ariaLabel || ariaLabelProp,
"aria-labelledby": (0, require_utils_index.utils_exports.cx)(ariaLabelledby, ariaLabelledbyProp),
"data-disabled": (0, require_utils_index.utils_exports.dataAttr)(disabled),
"data-readonly": (0, require_utils_index.utils_exports.dataAttr)(readOnly),
role: "combobox",
tabIndex: interactive ? 0 : -1,
...rest,
...props$1,
ref: require_ref.mergeRefs(ref, rest.ref, triggerRef),
onClick: (0, require_utils_index.utils_exports.handlerAll)(props$1.onClick, rest.onClick, onClick),
onKeyDown: (0, require_utils_index.utils_exports.handlerAll)(props$1.onKeyDown, rest.onKeyDown, onKeyDown)
}), [
open,
contentId,
interactive,
ariaLabelledbyProp,
disabled,
readOnly,
ariaLabelProp,
rest,
onClick,
onKeyDown
]);
return {
activeDescendant,
descendants,
interactive,
open,
getContentProps: (0, react.useCallback)(({ ref,...props$1 } = {}) => ({
id: contentId,
role: "listbox",
...props$1,
ref: require_ref.mergeRefs(ref, contentRef),
onKeyDown: (0, require_utils_index.utils_exports.handlerAll)(props$1.onKeyDown)
}), [contentId]),
getSeparatorProps: (0, react.useCallback)((props$1) => ({
role: "separator",
...props$1
}), []),
getTriggerProps,
popoverProps: mergedPopoverProps,
onActiveDescendant,
onClose,
onOpen,
onOpenWithActiveDescendant,
onScrollIntoView,
onSelect
};
};
const useComboboxGroup = ({ "aria-labelledby": ariaLabelledbyProp,...rest } = {}) => {
const labelId = (0, react.useId)();
return {
getGroupProps: (0, react.useCallback)(({ "aria-labelledby": ariaLabelledby,...props } = {}) => ({
"aria-labelledby": (0, require_utils_index.utils_exports.cx)(ariaLabelledbyProp, ariaLabelledby, labelId),
role: "group",
...rest,
...props
}), [
ariaLabelledbyProp,
labelId,
rest
]),
getLabelProps: (0, react.useCallback)((props) => ({
id: labelId,
role: "presentation",
...props
}), [labelId])
};
};
const useComboboxItem = ({ id, "aria-disabled": ariaDisabled, "data-disabled": dataDisabled, closeOnSelect, disabled = false, selected = false, value,...rest } = {}) => {
const uuid = (0, react.useId)();
const itemRef = (0, react.useRef)(null);
const { onActiveDescendant, onClose, onSelect } = useComboboxContext();
id ??= uuid;
const { descendants, register } = useComboboxDescendant({
id,
closeOnSelect,
disabled,
value
});
const onActive = (0, react.useCallback)(() => {
if (disabled) return;
onActiveDescendant(descendants.value(itemRef.current));
}, [
descendants,
disabled,
onActiveDescendant
]);
const onClick = (0, react.useCallback)((ev) => {
ev.preventDefault();
if (disabled) return;
onSelect(value, closeOnSelect);
}, [
closeOnSelect,
disabled,
onSelect,
value
]);
const getItemProps = (0, react.useCallback)(({ ref,...props } = {}) => ({
id,
"aria-disabled": ariaDisabled ?? (0, require_utils_index.utils_exports.ariaAttr)(disabled),
"aria-selected": selected,
"data-disabled": dataDisabled ?? (0, require_utils_index.utils_exports.dataAttr)(disabled),
"data-selected": (0, require_utils_index.utils_exports.dataAttr)(selected),
"data-value": value,
role: "option",
tabIndex: -1,
...rest,
...props,
ref: require_ref.mergeRefs(ref, rest.ref, itemRef, register),
onClick: (0, require_utils_index.utils_exports.handlerAll)(props.onClick, rest.onClick, onClick),
onMouseMove: (0, require_utils_index.utils_exports.handlerAll)(props.onMouseMove, rest.onMouseMove, onActive)
}), [
id,
ariaDisabled,
disabled,
selected,
dataDisabled,
value,
rest,
register,
onClick,
onActive
]);
return {
descendants,
disabled,
selected,
getIndicatorProps: (0, react.useCallback)(({ style,...props } = {}) => ({
style: {
opacity: selected ? 1 : 0,
...style
},
...props
}), [selected]),
getItemProps,
onActiveDescendant,
onClose
};
};
//#endregion
exports.ComboboxContext = ComboboxContext;
exports.ComboboxDescendantsContext = ComboboxDescendantsContext;
exports.ComboboxGroupContext = ComboboxGroupContext;
exports.createComboboxChildren = createComboboxChildren;
exports.createComboboxItem = createComboboxItem;
exports.useCombobox = useCombobox;
exports.useComboboxContext = useComboboxContext;
exports.useComboboxDescendant = useComboboxDescendant;
exports.useComboboxDescendantRegister = useComboboxDescendantRegister;
exports.useComboboxDescendants = useComboboxDescendants;
exports.useComboboxGroup = useComboboxGroup;
exports.useComboboxGroupContext = useComboboxGroupContext;
exports.useComboboxItem = useComboboxItem;
//# sourceMappingURL=index.cjs.map