@hitachivantara/uikit-react-core
Version:
Core React components for the NEXT Design System.
130 lines (129 loc) • 3.4 kB
JavaScript
import { jsx } from "react/jsx-runtime";
import * as React from "react";
import { unstable_useEnhancedEffect } from "@mui/material/utils";
function binaryFindElement(array, element) {
let start = 0;
let end = array.length - 1;
while (start <= end) {
const middle = Math.floor((start + end) / 2);
if (array[middle].element === element) {
return middle;
}
if (
// eslint-disable-next-line no-bitwise
array[middle].element.compareDocumentPosition(element) & Node.DOCUMENT_POSITION_PRECEDING
) {
end = middle - 1;
} else {
start = middle + 1;
}
}
return start;
}
const DescendantContext = React.createContext({
level: 0
});
function usePrevious(value) {
const ref = React.useRef(null);
React.useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
const noop = () => {
};
function useDescendant(descendant) {
const [, forceUpdate] = React.useState();
const {
registerDescendant = noop,
unregisterDescendant = noop,
descendants = [],
parentId = null,
level = 0
} = React.useContext(DescendantContext);
const index = descendants.findIndex(
(item) => item.element === descendant.element
);
const previousDescendants = usePrevious(descendants);
const someDescendantsHaveChanged = descendants.some(
(newDescendant, position) => {
return previousDescendants?.[position] && previousDescendants[position].element !== newDescendant.element;
}
);
unstable_useEnhancedEffect(() => {
if (descendant.element) {
registerDescendant({
...descendant,
index
});
return () => {
unregisterDescendant(descendant.element);
};
}
forceUpdate({});
return void 0;
}, [
registerDescendant,
unregisterDescendant,
index,
someDescendantsHaveChanged,
descendant
]);
return { parentId, index, level };
}
const DescendantProvider = (props) => {
const { children, id, level } = props;
const [items, set] = React.useState([]);
const registerDescendant = React.useCallback(
({ element, ...other }) => {
set((oldItems) => {
if (oldItems.length === 0) {
return [
{
...other,
element,
index: 0
}
];
}
const index = binaryFindElement(oldItems, element);
let newItems;
if (oldItems[index] && oldItems[index].element === element) {
newItems = oldItems;
} else {
const newItem = {
...other,
element,
index
};
newItems = oldItems.slice();
newItems.splice(index, 0, newItem);
}
newItems.forEach((item, position) => {
item.index = position;
});
return newItems;
});
},
[]
);
const unregisterDescendant = React.useCallback((element) => {
set((oldItems) => oldItems.filter((item) => element !== item.element));
}, []);
const value = React.useMemo(
() => ({
descendants: items,
registerDescendant,
unregisterDescendant,
parentId: id,
level
}),
[items, registerDescendant, unregisterDescendant, id, level]
);
return /* @__PURE__ */ jsx(DescendantContext.Provider, { value, children });
};
export {
DescendantContext,
DescendantProvider,
useDescendant
};