Spaces:
Running
Running
| // src/use-controllable-state.tsx | |
| import * as React from "react"; | |
| import { useLayoutEffect } from "@radix-ui/react-use-layout-effect"; | |
| var useInsertionEffect = React[" useInsertionEffect ".trim().toString()] || useLayoutEffect; | |
| function useControllableState({ | |
| prop, | |
| defaultProp, | |
| onChange = () => { | |
| }, | |
| caller | |
| }) { | |
| const [uncontrolledProp, setUncontrolledProp, onChangeRef] = useUncontrolledState({ | |
| defaultProp, | |
| onChange | |
| }); | |
| const isControlled = prop !== void 0; | |
| const value = isControlled ? prop : uncontrolledProp; | |
| if (true) { | |
| const isControlledRef = React.useRef(prop !== void 0); | |
| React.useEffect(() => { | |
| const wasControlled = isControlledRef.current; | |
| if (wasControlled !== isControlled) { | |
| const from = wasControlled ? "controlled" : "uncontrolled"; | |
| const to = isControlled ? "controlled" : "uncontrolled"; | |
| console.warn( | |
| `${caller} is changing from ${from} to ${to}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.` | |
| ); | |
| } | |
| isControlledRef.current = isControlled; | |
| }, [isControlled, caller]); | |
| } | |
| const setValue = React.useCallback( | |
| (nextValue) => { | |
| if (isControlled) { | |
| const value2 = isFunction(nextValue) ? nextValue(prop) : nextValue; | |
| if (value2 !== prop) { | |
| onChangeRef.current?.(value2); | |
| } | |
| } else { | |
| setUncontrolledProp(nextValue); | |
| } | |
| }, | |
| [isControlled, prop, setUncontrolledProp, onChangeRef] | |
| ); | |
| return [value, setValue]; | |
| } | |
| function useUncontrolledState({ | |
| defaultProp, | |
| onChange | |
| }) { | |
| const [value, setValue] = React.useState(defaultProp); | |
| const prevValueRef = React.useRef(value); | |
| const onChangeRef = React.useRef(onChange); | |
| useInsertionEffect(() => { | |
| onChangeRef.current = onChange; | |
| }, [onChange]); | |
| React.useEffect(() => { | |
| if (prevValueRef.current !== value) { | |
| onChangeRef.current?.(value); | |
| prevValueRef.current = value; | |
| } | |
| }, [value, prevValueRef]); | |
| return [value, setValue, onChangeRef]; | |
| } | |
| function isFunction(value) { | |
| return typeof value === "function"; | |
| } | |
| // src/use-controllable-state-reducer.tsx | |
| import * as React2 from "react"; | |
| import { useEffectEvent } from "@radix-ui/react-use-effect-event"; | |
| var SYNC_STATE = Symbol("RADIX:SYNC_STATE"); | |
| function useControllableStateReducer(reducer, userArgs, initialArg, init) { | |
| const { prop: controlledState, defaultProp, onChange: onChangeProp, caller } = userArgs; | |
| const isControlled = controlledState !== void 0; | |
| const onChange = useEffectEvent(onChangeProp); | |
| if (true) { | |
| const isControlledRef = React2.useRef(controlledState !== void 0); | |
| React2.useEffect(() => { | |
| const wasControlled = isControlledRef.current; | |
| if (wasControlled !== isControlled) { | |
| const from = wasControlled ? "controlled" : "uncontrolled"; | |
| const to = isControlled ? "controlled" : "uncontrolled"; | |
| console.warn( | |
| `${caller} is changing from ${from} to ${to}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.` | |
| ); | |
| } | |
| isControlledRef.current = isControlled; | |
| }, [isControlled, caller]); | |
| } | |
| const args = [{ ...initialArg, state: defaultProp }]; | |
| if (init) { | |
| args.push(init); | |
| } | |
| const [internalState, dispatch] = React2.useReducer( | |
| (state2, action) => { | |
| if (action.type === SYNC_STATE) { | |
| return { ...state2, state: action.state }; | |
| } | |
| const next = reducer(state2, action); | |
| if (isControlled && !Object.is(next.state, state2.state)) { | |
| onChange(next.state); | |
| } | |
| return next; | |
| }, | |
| ...args | |
| ); | |
| const uncontrolledState = internalState.state; | |
| const prevValueRef = React2.useRef(uncontrolledState); | |
| React2.useEffect(() => { | |
| if (prevValueRef.current !== uncontrolledState) { | |
| prevValueRef.current = uncontrolledState; | |
| if (!isControlled) { | |
| onChange(uncontrolledState); | |
| } | |
| } | |
| }, [onChange, uncontrolledState, prevValueRef, isControlled]); | |
| const state = React2.useMemo(() => { | |
| const isControlled2 = controlledState !== void 0; | |
| if (isControlled2) { | |
| return { ...internalState, state: controlledState }; | |
| } | |
| return internalState; | |
| }, [internalState, controlledState]); | |
| React2.useEffect(() => { | |
| if (isControlled && !Object.is(controlledState, internalState.state)) { | |
| dispatch({ type: SYNC_STATE, state: controlledState }); | |
| } | |
| }, [controlledState, internalState.state, isControlled]); | |
| return [state, dispatch]; | |
| } | |
| export { | |
| useControllableState, | |
| useControllableStateReducer | |
| }; | |
| //# sourceMappingURL=index.mjs.map | |