87 lines
3.5 KiB
JavaScript
87 lines
3.5 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
Object.defineProperty(exports, "useControllableState", {
|
|
enumerable: true,
|
|
get: function() {
|
|
return useControllableState;
|
|
}
|
|
});
|
|
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
|
|
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
|
|
function isFactoryDispatch(newState) {
|
|
return typeof newState === 'function';
|
|
}
|
|
const useControllableState = (options)=>{
|
|
'use no memo';
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
if (options.state !== undefined && options.defaultState !== undefined) {
|
|
// eslint-disable-next-line no-console
|
|
console.error(`@fluentui/react-utilities [useControllableState]:
|
|
A component must be either controlled or uncontrolled (specify either the state or the defaultState, but not both).
|
|
Decide between using a controlled or uncontrolled component and remove one of this props.
|
|
More info: https://reactjs.org/link/controlled-components
|
|
${new Error().stack}`);
|
|
}
|
|
}
|
|
const [internalState, setInternalState] = _react.useState(()=>{
|
|
if (options.defaultState === undefined) {
|
|
return options.initialState;
|
|
}
|
|
return isInitializer(options.defaultState) ? options.defaultState() : options.defaultState;
|
|
});
|
|
// Heads up!
|
|
// This part is specific for controlled mode and mocks behavior of React dispatcher function.
|
|
const stateValueRef = _react.useRef(options.state);
|
|
_react.useEffect(()=>{
|
|
stateValueRef.current = options.state;
|
|
}, [
|
|
options.state
|
|
]);
|
|
const setControlledState = _react.useCallback((newState)=>{
|
|
if (isFactoryDispatch(newState)) {
|
|
newState(stateValueRef.current);
|
|
}
|
|
}, []);
|
|
return useIsControlled(options.state) ? [
|
|
options.state,
|
|
setControlledState
|
|
] : [
|
|
internalState,
|
|
setInternalState
|
|
];
|
|
};
|
|
function isInitializer(value) {
|
|
return typeof value === 'function';
|
|
}
|
|
/**
|
|
* Helper hook to handle previous comparison of controlled/uncontrolled
|
|
* Prints an error when isControlled value switches between subsequent renders
|
|
* @returns - whether the value is controlled
|
|
*/ const useIsControlled = (controlledValue)=>{
|
|
'use no memo';
|
|
const [isControlled] = _react.useState(()=>controlledValue !== undefined);
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
// We don't want these warnings in production even though it is against native behaviour
|
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
_react.useEffect(()=>{
|
|
if (isControlled !== (controlledValue !== undefined)) {
|
|
const error = new Error();
|
|
const controlWarning = isControlled ? 'a controlled value to be uncontrolled' : 'an uncontrolled value to be controlled';
|
|
const undefinedWarning = isControlled ? 'defined to an undefined' : 'undefined to a defined';
|
|
// eslint-disable-next-line no-console
|
|
console.error(`@fluentui/react-utilities [useControllableState]:
|
|
A component is changing ${controlWarning}. This is likely caused by the value changing from ${undefinedWarning} value, which should not happen.
|
|
Decide between using a controlled or uncontrolled input element for the lifetime of the component.
|
|
More info: https://reactjs.org/link/controlled-components
|
|
${error.stack}`);
|
|
}
|
|
}, [
|
|
isControlled,
|
|
controlledValue
|
|
]);
|
|
}
|
|
return isControlled;
|
|
};
|