1 | 'use client';
|
2 |
|
3 | import _extends from "@babel/runtime/helpers/esm/extends";
|
4 | import * as React from 'react';
|
5 | function areEqual(a, b) {
|
6 | return a === b;
|
7 | }
|
8 | const EMPTY_OBJECT = {};
|
9 | const NOOP = () => {};
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | function getControlledState(internalState, controlledProps) {
|
16 | const augmentedState = _extends({}, internalState);
|
17 | Object.keys(controlledProps).forEach(key => {
|
18 | if (controlledProps[key] !== undefined) {
|
19 | augmentedState[key] = controlledProps[key];
|
20 | }
|
21 | });
|
22 | return augmentedState;
|
23 | }
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 | function useStateChangeDetection(parameters) {
|
30 | const {
|
31 | nextState,
|
32 | initialState,
|
33 | stateComparers,
|
34 | onStateChange,
|
35 | controlledProps,
|
36 | lastActionRef
|
37 | } = parameters;
|
38 | const internalPreviousStateRef = React.useRef(initialState);
|
39 | React.useEffect(() => {
|
40 | if (lastActionRef.current === null) {
|
41 |
|
42 | return;
|
43 | }
|
44 | const previousState = getControlledState(internalPreviousStateRef.current, controlledProps);
|
45 | Object.keys(nextState).forEach(key => {
|
46 | var _stateComparers$key;
|
47 |
|
48 | const stateComparer = (_stateComparers$key = stateComparers[key]) != null ? _stateComparers$key : areEqual;
|
49 | const nextStateItem = nextState[key];
|
50 | const previousStateItem = previousState[key];
|
51 | if (previousStateItem == null && nextStateItem != null || previousStateItem != null && nextStateItem == null || previousStateItem != null && nextStateItem != null && !stateComparer(nextStateItem, previousStateItem)) {
|
52 | var _event, _type;
|
53 | onStateChange == null || onStateChange((_event = lastActionRef.current.event) != null ? _event : null, key, nextStateItem, (_type = lastActionRef.current.type) != null ? _type : '', nextState);
|
54 | }
|
55 | });
|
56 | internalPreviousStateRef.current = nextState;
|
57 | lastActionRef.current = null;
|
58 | }, [internalPreviousStateRef, nextState, lastActionRef, onStateChange, stateComparers, controlledProps]);
|
59 | }
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 | export function useControllableReducer(parameters) {
|
86 | const lastActionRef = React.useRef(null);
|
87 | const {
|
88 | reducer,
|
89 | initialState,
|
90 | controlledProps = EMPTY_OBJECT,
|
91 | stateComparers = EMPTY_OBJECT,
|
92 | onStateChange = NOOP,
|
93 | actionContext,
|
94 | componentName = ''
|
95 | } = parameters;
|
96 | const controlledPropsRef = React.useRef(controlledProps);
|
97 | if (process.env.NODE_ENV !== 'production') {
|
98 |
|
99 | React.useEffect(() => {
|
100 | Object.keys(controlledProps).forEach(key => {
|
101 | if (controlledPropsRef.current[key] !== undefined && controlledProps[key] === undefined) {
|
102 | console.error(`useControllableReducer: ${componentName ? `The ${componentName} component` : 'A component'} is changing a controlled prop to be uncontrolled: ${key}`);
|
103 | }
|
104 | if (controlledPropsRef.current[key] === undefined && controlledProps[key] !== undefined) {
|
105 | console.error(`useControllableReducer: ${componentName ? `The ${componentName} component` : 'A component'} is changing an uncontrolled prop to be controlled: ${key}`);
|
106 | }
|
107 | });
|
108 | }, [controlledProps, componentName]);
|
109 | }
|
110 |
|
111 |
|
112 | const reducerWithControlledState = React.useCallback((state, action) => {
|
113 | lastActionRef.current = action;
|
114 | const controlledState = getControlledState(state, controlledProps);
|
115 | const newState = reducer(controlledState, action);
|
116 | return newState;
|
117 | }, [controlledProps, reducer]);
|
118 | const [nextState, dispatch] = React.useReducer(reducerWithControlledState, initialState);
|
119 |
|
120 |
|
121 | const dispatchWithContext = React.useCallback(action => {
|
122 | dispatch(_extends({}, action, {
|
123 | context: actionContext
|
124 | }));
|
125 | }, [actionContext]);
|
126 | useStateChangeDetection({
|
127 | nextState,
|
128 | initialState,
|
129 | stateComparers: stateComparers != null ? stateComparers : EMPTY_OBJECT,
|
130 | onStateChange: onStateChange != null ? onStateChange : NOOP,
|
131 | controlledProps,
|
132 | lastActionRef
|
133 | });
|
134 | return [getControlledState(nextState, controlledProps), dispatchWithContext];
|
135 | } |
\ | No newline at end of file |