@yamada-ui/react
Version:
React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion
164 lines (160 loc) • 5.67 kB
JavaScript
"use client";
import { useValidChildren } from "../../utils/children.js";
import { createContext as createContext$1 } from "../../utils/context.js";
import { useUpdateEffect } from "../../utils/effect.js";
import { mergeRefs } from "../../utils/ref.js";
import { utils_exports } from "../../utils/index.js";
import { cloneElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useDragControls, useMotionValue } from "motion/react";
//#region src/components/reorder/use-reorder.ts
const getAlternativeValue = ({ children, label } = {}) => serializeValue(children ?? label);
const serializeValue = (value) => (0, utils_exports.isObject)(value) || (0, utils_exports.isArray)(value) ? JSON.stringify(value) : value;
const [ReorderContext, useReorderContext] = createContext$1({ name: "ReorderContext" });
const [ReorderItemContext, useReorderItemContext] = createContext$1({ name: "ReorderItemContext" });
const useReorder = ({ ref, children, item, items = [], orientation = "vertical", onChange, onCompleteChange,...rest } = {}) => {
const axis = orientation === "vertical" ? "y" : "x";
const validChildren = useValidChildren(children);
const hasChildren = !!validChildren.length;
const defaultValues = useMemo(() => {
const values$1 = hasChildren ? validChildren.map(({ props }) => props.value ?? getAlternativeValue(props)) : items.map((props) => props.value ?? getAlternativeValue(props));
const duplicatedValues = values$1.filter((value, index, self) => self.indexOf(value) === index && index !== self.lastIndexOf(value));
if (duplicatedValues.length) console.warn(`Reorder: 'value' of 'ReorderItem' must not be duplicated. duplicate 'value' is '${duplicatedValues.join(`', '`)}' `);
return Array.from(new Set(values$1));
}, [
hasChildren,
validChildren,
items
]);
const childMap = useMemo(() => {
return Object.fromEntries(validChildren.map((child) => [serializeValue(child.props.value) ?? serializeValue(getAlternativeValue(child.props)), child]));
}, [validChildren]);
const itemMap = useMemo(() => {
return Object.fromEntries(items.map((props) => [serializeValue(props.value) ?? serializeValue(getAlternativeValue(props)), props]));
}, [items]);
const prevDefaultValues = useRef(defaultValues);
const [values, setValues] = useState(defaultValues);
const prevValues = useRef(defaultValues);
const cloneChildren = useMemo(() => values.map((value) => {
if (hasChildren) return childMap[serializeValue(value)];
else {
const props = itemMap[serializeValue(value)];
return props && item ? cloneElement(item, {
key: serializeValue(props.value),
...props
}) : null;
}
}), [
values,
hasChildren,
childMap,
itemMap,
item
]);
const onReorder = useCallback((newValues) => {
setValues(newValues);
onChange?.(newValues);
}, [onChange]);
const onCompleteReorder = useCallback(() => {
if (JSON.stringify(prevValues.current) === JSON.stringify(values)) return;
prevValues.current = values;
onCompleteChange?.(values);
}, [onCompleteChange, values]);
useUpdateEffect(() => {
if (JSON.stringify(defaultValues) === JSON.stringify(prevDefaultValues.current)) return;
prevValues.current = defaultValues;
prevDefaultValues.current = defaultValues;
setValues(defaultValues);
}, [defaultValues]);
return {
children: cloneChildren,
orientation,
values,
getRootProps: useCallback((props = {}) => ({
axis,
values,
...rest,
...props,
ref: mergeRefs(props.ref, ref),
onMouseUp: (0, utils_exports.handlerAll)(props.onMouseUp, rest.onMouseUp, onCompleteReorder),
onReorder: (0, utils_exports.handlerAll)(props.onReorder, rest.onReorder, onReorder),
onTouchEnd: (0, utils_exports.handlerAll)(props.onTouchEnd, rest.onTouchEnd, onCompleteReorder)
}), [
rest,
ref,
onCompleteReorder,
onReorder,
axis,
values
])
};
};
const useReorderItem = ({ ref, label, value,...rest }) => {
const { orientation } = useReorderContext();
const dragControls = useDragControls();
const [hasTrigger, setHasTrigger] = useState(false);
const [drag, setDrag] = useState(false);
const x = useMotionValue(0);
const y = useMotionValue(0);
const register = useCallback((node) => setHasTrigger(!!node), []);
useEffect(() => {
const unsubscribeX = x.on("change", (x$1) => {
if (orientation === "horizontal") setDrag(x$1 !== 0);
});
const unsubscribeY = y.on("change", (y$1) => {
if (orientation === "vertical") setDrag(y$1 !== 0);
});
return () => {
unsubscribeX();
unsubscribeY();
};
}, [
orientation,
x,
y
]);
return {
getItemProps: useCallback((props = {}) => {
const children = props.children ?? rest.children ?? label;
return {
"data-has-trigger": (0, utils_exports.dataAttr)(hasTrigger),
"data-selected": (0, utils_exports.dataAttr)(drag),
dragControls,
dragListener: !hasTrigger,
value: value ?? getAlternativeValue({ children }),
...props,
...rest,
ref: mergeRefs(props.ref, ref),
style: {
x,
y,
...props.style,
...rest.style
},
children
};
}, [
ref,
rest,
dragControls,
hasTrigger,
value,
x,
y,
drag,
label
]),
getTriggerProps: useCallback((props = {}) => ({
...props,
ref: mergeRefs(register, props.ref),
"data-selected": (0, utils_exports.dataAttr)(drag),
onPointerDown: (0, utils_exports.handlerAll)(props.onPointerDown, (ev) => dragControls.start(ev))
}), [
drag,
dragControls,
register
])
};
};
//#endregion
export { ReorderContext, ReorderItemContext, useReorder, useReorderContext, useReorderItem, useReorderItemContext };
//# sourceMappingURL=use-reorder.js.map