@ultraviolet/plus
Version:
Ultraviolet Plus
130 lines (129 loc) • 4.04 kB
JavaScript
"use client";
import { jsx } from "@emotion/react/jsx-runtime";
import { useContext, useState, useReducer, useRef, useCallback, useMemo, createContext } from "react";
import { NAVIGATION_WIDTH, ANIMATION_DURATION } from "./constants.js";
import NavigationLocales from "./locales/en.js";
const NavigationContext = createContext({
expanded: true,
/**
* This function will trigger the expand/collapse of the navigation and
* will also trigger the animation
*/
toggleExpand: () => {
},
animation: false,
locales: NavigationLocales,
pinItem: () => [],
unpinItem: () => [],
pinnedItems: [],
pinLimit: 7,
navigationRef: {
current: null
},
width: NAVIGATION_WIDTH,
setWidth: () => {
},
reorderItems: () => [],
items: {},
registerItem: () => {
},
setPinnedItems: () => {
},
allowNavigationResize: true,
setAllowNavigationResize: () => {
},
shouldAnimate: true,
animationType: "simple"
});
const useNavigation = () => useContext(NavigationContext);
const NavigationProvider = ({
children,
pinnedFeature = false,
initialPinned,
initialExpanded = true,
locales = NavigationLocales,
pinLimit = 7,
onExpandChange,
initialWidth = NAVIGATION_WIDTH,
initialAllowNavigationResize = true,
animation: shouldAnimate = true,
animationType
}) => {
const [expanded, setExpanded] = useState(initialExpanded);
const [pinnedItems, setPinnedItems] = useState(initialPinned ?? []);
const [animation, setAnimation] = useState(false);
const [width, setWidth] = useState(initialWidth);
const [allowNavigationResize, setAllowNavigationResize] = useState(initialAllowNavigationResize);
const [items, registerItem] = useReducer((oldState, newState) => ({
...oldState,
...newState
}), {});
const navigationRef = useRef(null);
const toggleExpand = useCallback((toggle) => {
if (typeof toggle !== "boolean" && toggle !== void 0) {
throw new Error("toggleExpand only accepts boolean or undefined as parameter. You most likely did <button onClick={toggleExpand}> instead of <button onClick={() => toggleExpand()}>");
}
if (toggle !== void 0 && toggle === expanded) {
return;
}
onExpandChange?.(!expanded);
if (navigationRef.current) {
navigationRef.current.style.width = "";
}
if (shouldAnimate) {
setAnimation(expanded ? "collapse" : "expand");
setTimeout(() => {
setExpanded(toggle !== void 0 ? toggle : !expanded);
setAnimation(false);
}, ANIMATION_DURATION);
} else {
setExpanded(toggle !== void 0 ? toggle : !expanded);
}
}, [expanded, onExpandChange, shouldAnimate]);
const pinItem = useCallback((item) => {
const newValue = [...pinnedItems, item];
setPinnedItems(newValue);
return newValue;
}, [pinnedItems]);
const unpinItem = useCallback((item) => {
const newValue = pinnedItems.filter((localItem) => localItem !== item);
setPinnedItems(newValue);
return newValue;
}, [pinnedItems]);
const reorderItems = useCallback((initialIndex, endIndex) => {
const newPinnedItems = [...pinnedItems];
const [removed] = newPinnedItems.splice(initialIndex, 1);
newPinnedItems.splice(endIndex, 0, removed);
setPinnedItems(newPinnedItems);
return newPinnedItems;
}, [pinnedItems]);
const value = useMemo(() => ({
expanded,
toggleExpand,
pinnedItems,
pinItem,
unpinItem,
pinnedFeature,
locales,
pinLimit,
animation,
setAnimation,
navigationRef,
width,
setWidth,
reorderItems,
registerItem,
items,
setPinnedItems,
allowNavigationResize,
setAllowNavigationResize,
shouldAnimate,
animationType
}), [expanded, toggleExpand, pinnedItems, pinItem, unpinItem, pinnedFeature, locales, pinLimit, animation, width, reorderItems, items, allowNavigationResize, shouldAnimate, animationType]);
return /* @__PURE__ */ jsx(NavigationContext.Provider, { value, children });
};
export {
NavigationContext,
NavigationProvider,
useNavigation
};