UNPKG

2.63 kBPlain TextView Raw
1import * as React from "react";
2import { createComponent } from "reakit-system/createComponent";
3import { createHook } from "reakit-system/createHook";
4import { useForkRef } from "reakit-utils/useForkRef";
5import { useIsomorphicEffect } from "reakit-utils/useIsomorphicEffect";
6import { GroupOptions, GroupHTMLProps, useGroup } from "../Group/Group";
7import {
8 unstable_useId,
9 unstable_IdOptions,
10 unstable_IdHTMLProps,
11} from "../Id/Id";
12import { CompositeStateReturn } from "./CompositeState";
13import { findEnabledItemById } from "./__utils/findEnabledItemById";
14import { COMPOSITE_GROUP_KEYS } from "./__keys";
15
16export type CompositeGroupOptions = GroupOptions &
17 unstable_IdOptions &
18 Pick<CompositeStateReturn, "registerGroup" | "unregisterGroup"> &
19 Pick<Partial<CompositeStateReturn>, "currentId" | "unstable_moves" | "items">;
20
21export type CompositeGroupHTMLProps = GroupHTMLProps & unstable_IdHTMLProps;
22
23export type CompositeGroupProps = CompositeGroupOptions &
24 CompositeGroupHTMLProps;
25
26export const useCompositeGroup = createHook<
27 CompositeGroupOptions,
28 CompositeGroupHTMLProps
29>({
30 name: "CompositeGroup",
31 compose: [useGroup, unstable_useId],
32 keys: COMPOSITE_GROUP_KEYS,
33
34 propsAreEqual(prev, next) {
35 if (!next.id || prev.id !== next.id) {
36 return useGroup.unstable_propsAreEqual(prev, next);
37 }
38 const {
39 currentId: prevCurrentId,
40 unstable_moves: prevMoves,
41 ...prevProps
42 } = prev;
43 const {
44 currentId: nextCurrentId,
45 unstable_moves: nextMoves,
46 ...nextProps
47 } = next;
48 if (prev.items && next.items) {
49 const prevCurrentItem = findEnabledItemById(prev.items, prevCurrentId);
50 const nextCurrentItem = findEnabledItemById(next.items, nextCurrentId);
51 const prevGroupId = prevCurrentItem?.groupId;
52 const nextGroupId = nextCurrentItem?.groupId;
53 if (next.id === nextGroupId || next.id === prevGroupId) {
54 return false;
55 }
56 }
57 return useGroup.unstable_propsAreEqual(prevProps, nextProps);
58 },
59
60 useProps(options, { ref: htmlRef, ...htmlProps }) {
61 const ref = React.useRef<HTMLElement>(null);
62 const { id } = options;
63
64 // We need this to be called before CompositeItems' register
65 useIsomorphicEffect(() => {
66 if (!id) return undefined;
67 options.registerGroup?.({ id, ref });
68 return () => {
69 options.unregisterGroup?.(id);
70 };
71 }, [id, options.registerGroup, options.unregisterGroup]);
72
73 return { ref: useForkRef(ref, htmlRef), ...htmlProps };
74 },
75});
76
77export const CompositeGroup = createComponent({
78 as: "div",
79 useHook: useCompositeGroup,
80});