UNPKG

2.98 kBJavaScriptView Raw
1import * as React from 'react';
2export var CompoundComponentContext = /*#__PURE__*/React.createContext(null);
3CompoundComponentContext.displayName = 'CompoundComponentContext';
4/**
5 * Sorts the subitems by their position in the DOM.
6 */
7function sortSubitems(subitems) {
8 var subitemsArray = Array.from(subitems.keys()).map(function (key) {
9 var subitem = subitems.get(key);
10 return {
11 key: key,
12 subitem: subitem
13 };
14 });
15 subitemsArray.sort(function (a, b) {
16 var aNode = a.subitem.ref.current;
17 var bNode = b.subitem.ref.current;
18 if (aNode === null || bNode === null || aNode === bNode) {
19 return 0;
20 }
21
22 // eslint-disable-next-line no-bitwise
23 return aNode.compareDocumentPosition(bNode) & Node.DOCUMENT_POSITION_PRECEDING ? 1 : -1;
24 });
25 return new Map(subitemsArray.map(function (item) {
26 return [item.key, item.subitem];
27 }));
28}
29
30/**
31 * Provides a way for a component to know about its children.
32 *
33 * Child components register themselves with the `useCompoundItem` hook, passing in arbitrary metadata to the parent.
34 *
35 * This is a more powerful altervantive to `children` traversal, as child components don't have to be placed
36 * directly inside the parent component. They can be anywhere in the tree (and even rendered by other components).
37 *
38 * The downside is that this doesn't work with SSR as it relies on the useEffect hook.
39 *
40 * @ignore - internal hook.
41 */
42export function useCompoundParent() {
43 var _React$useState = React.useState(new Map()),
44 subitems = _React$useState[0],
45 setSubitems = _React$useState[1];
46 var subitemKeys = React.useRef(new Set());
47 var deregisterItem = React.useCallback(function deregisterItem(id) {
48 subitemKeys.current.delete(id);
49 setSubitems(function (previousState) {
50 var newState = new Map(previousState);
51 newState.delete(id);
52 return newState;
53 });
54 }, []);
55 var registerItem = React.useCallback(function registerItem(id, item) {
56 var providedOrGeneratedId;
57 if (typeof id === 'function') {
58 providedOrGeneratedId = id(subitemKeys.current);
59 } else {
60 providedOrGeneratedId = id;
61 }
62 subitemKeys.current.add(providedOrGeneratedId);
63 setSubitems(function (previousState) {
64 var newState = new Map(previousState);
65 newState.set(providedOrGeneratedId, item);
66 return newState;
67 });
68 return {
69 id: providedOrGeneratedId,
70 deregister: function deregister() {
71 return deregisterItem(providedOrGeneratedId);
72 }
73 };
74 }, [deregisterItem]);
75 var sortedSubitems = React.useMemo(function () {
76 return sortSubitems(subitems);
77 }, [subitems]);
78 var getItemIndex = React.useCallback(function getItemIndex(id) {
79 return Array.from(sortedSubitems.keys()).indexOf(id);
80 }, [sortedSubitems]);
81 return {
82 contextValue: {
83 getItemIndex: getItemIndex,
84 registerItem: registerItem,
85 totalSubitemCount: subitems.size
86 },
87 subitems: sortedSubitems
88 };
89}
\No newline at end of file