UNPKG

@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
"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