@mui/utils 7.0.0 → 7.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +100 -0
- package/esm/index.js +1 -1
- package/esm/useForkRef/useForkRef.d.ts +1 -2
- package/esm/useForkRef/useForkRef.js +32 -12
- package/index.js +1 -1
- package/modern/useForkRef/useForkRef.d.ts +1 -2
- package/package.json +4 -12
- package/useForkRef/useForkRef.d.ts +1 -2
- package/useForkRef/useForkRef.js +32 -13
- package/modern/ClassNameGenerator/ClassNameGenerator.js +0 -17
- package/modern/ClassNameGenerator/index.js +0 -1
- package/modern/HTMLElementType/HTMLElementType.js +0 -14
- package/modern/HTMLElementType/index.js +0 -1
- package/modern/appendOwnerState/appendOwnerState.js +0 -28
- package/modern/appendOwnerState/index.js +0 -1
- package/modern/capitalize/capitalize.js +0 -11
- package/modern/capitalize/index.js +0 -1
- package/modern/chainPropTypes/chainPropTypes.js +0 -8
- package/modern/chainPropTypes/index.js +0 -1
- package/modern/clamp/clamp.js +0 -4
- package/modern/clamp/index.js +0 -1
- package/modern/composeClasses/composeClasses.js +0 -53
- package/modern/composeClasses/index.js +0 -1
- package/modern/createChainedFunction/createChainedFunction.js +0 -17
- package/modern/createChainedFunction/index.js +0 -1
- package/modern/debounce/debounce.js +0 -17
- package/modern/debounce/index.js +0 -2
- package/modern/deepmerge/deepmerge.js +0 -64
- package/modern/deepmerge/index.js +0 -2
- package/modern/deprecatedPropType/deprecatedPropType.js +0 -13
- package/modern/deprecatedPropType/index.js +0 -1
- package/modern/elementAcceptingRef/elementAcceptingRef.js +0 -42
- package/modern/elementAcceptingRef/index.js +0 -1
- package/modern/elementTypeAcceptingRef/elementTypeAcceptingRef.js +0 -40
- package/modern/elementTypeAcceptingRef/index.js +0 -1
- package/modern/exactProp/exactProp.js +0 -20
- package/modern/exactProp/index.js +0 -1
- package/modern/extractEventHandlers/extractEventHandlers.js +0 -18
- package/modern/extractEventHandlers/index.js +0 -1
- package/modern/formatMuiErrorMessage/formatMuiErrorMessage.js +0 -15
- package/modern/formatMuiErrorMessage/index.js +0 -1
- package/modern/generateUtilityClass/generateUtilityClass.js +0 -22
- package/modern/generateUtilityClass/index.js +0 -2
- package/modern/generateUtilityClasses/generateUtilityClasses.js +0 -8
- package/modern/generateUtilityClasses/index.js +0 -1
- package/modern/getDisplayName/getDisplayName.js +0 -38
- package/modern/getDisplayName/index.js +0 -1
- package/modern/getReactElementRef/getReactElementRef.js +0 -18
- package/modern/getReactElementRef/index.js +0 -1
- package/modern/getReactNodeRef/getReactNodeRef.js +0 -23
- package/modern/getReactNodeRef/index.js +0 -1
- package/modern/getScrollbarSize/getScrollbarSize.js +0 -7
- package/modern/getScrollbarSize/index.js +0 -1
- package/modern/getValidReactChildren/getValidReactChildren.js +0 -11
- package/modern/getValidReactChildren/index.js +0 -1
- package/modern/index.js +0 -57
- package/modern/integerPropType/index.js +0 -2
- package/modern/integerPropType/integerPropType.js +0 -44
- package/modern/isFocusVisible/index.js +0 -1
- package/modern/isFocusVisible/isFocusVisible.js +0 -15
- package/modern/isHostComponent/index.js +0 -1
- package/modern/isHostComponent/isHostComponent.js +0 -7
- package/modern/isMuiElement/index.js +0 -1
- package/modern/isMuiElement/isMuiElement.js +0 -8
- package/modern/mergeSlotProps/index.js +0 -1
- package/modern/mergeSlotProps/mergeSlotProps.js +0 -90
- package/modern/omitEventHandlers/index.js +0 -1
- package/modern/omitEventHandlers/omitEventHandlers.js +0 -18
- package/modern/ownerDocument/index.js +0 -1
- package/modern/ownerDocument/ownerDocument.js +0 -3
- package/modern/ownerWindow/index.js +0 -1
- package/modern/ownerWindow/ownerWindow.js +0 -5
- package/modern/package.json +0 -1
- package/modern/ponyfillGlobal/index.js +0 -1
- package/modern/ponyfillGlobal/ponyfillGlobal.js +0 -6
- package/modern/refType/index.js +0 -1
- package/modern/refType/refType.js +0 -3
- package/modern/requirePropFactory/index.js +0 -1
- package/modern/requirePropFactory/requirePropFactory.js +0 -25
- package/modern/resolveComponentProps/index.js +0 -1
- package/modern/resolveComponentProps/resolveComponentProps.js +0 -11
- package/modern/resolveProps/index.js +0 -1
- package/modern/resolveProps/resolveProps.js +0 -43
- package/modern/setRef/index.js +0 -1
- package/modern/setRef/setRef.js +0 -20
- package/modern/types/index.js +0 -1
- package/modern/unsupportedProp/index.js +0 -1
- package/modern/unsupportedProp/unsupportedProp.js +0 -10
- package/modern/useControlled/index.js +0 -1
- package/modern/useControlled/useControlled.js +0 -41
- package/modern/useEnhancedEffect/index.js +0 -1
- package/modern/useEnhancedEffect/useEnhancedEffect.js +0 -13
- package/modern/useEventCallback/index.js +0 -1
- package/modern/useEventCallback/useEventCallback.js +0 -20
- package/modern/useForkRef/index.js +0 -1
- package/modern/useForkRef/useForkRef.js +0 -40
- package/modern/useId/index.js +0 -1
- package/modern/useId/useId.js +0 -45
- package/modern/useIsFocusVisible/index.js +0 -2
- package/modern/useIsFocusVisible/useIsFocusVisible.js +0 -163
- package/modern/useLazyRef/index.js +0 -1
- package/modern/useLazyRef/useLazyRef.js +0 -19
- package/modern/useLocalStorageState/index.js +0 -1
- package/modern/useLocalStorageState/useLocalStorageState.js +0 -108
- package/modern/useOnMount/index.js +0 -1
- package/modern/useOnMount/useOnMount.js +0 -14
- package/modern/usePreviousProps/index.js +0 -1
- package/modern/usePreviousProps/usePreviousProps.js +0 -11
- package/modern/useSlotProps/index.js +0 -1
- package/modern/useSlotProps/useSlotProps.js +0 -38
- package/modern/useTimeout/index.js +0 -2
- package/modern/useTimeout/useTimeout.js +0 -35
- package/modern/visuallyHidden/index.js +0 -1
- package/modern/visuallyHidden/visuallyHidden.js +0 -12
- package/tsconfig.build.tsbuildinfo +0 -1
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export default function requirePropFactory(componentNameInError, Component) {
|
|
2
|
-
if (process.env.NODE_ENV === 'production') {
|
|
3
|
-
return () => null;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
// eslint-disable-next-line react/forbid-foreign-prop-types
|
|
7
|
-
const prevPropTypes = Component ? {
|
|
8
|
-
...Component.propTypes
|
|
9
|
-
} : null;
|
|
10
|
-
const requireProp = requiredProp => (props, propName, componentName, location, propFullName, ...args) => {
|
|
11
|
-
const propFullNameSafe = propFullName || propName;
|
|
12
|
-
const defaultTypeChecker = prevPropTypes?.[propFullNameSafe];
|
|
13
|
-
if (defaultTypeChecker) {
|
|
14
|
-
const typeCheckerResult = defaultTypeChecker(props, propName, componentName, location, propFullName, ...args);
|
|
15
|
-
if (typeCheckerResult) {
|
|
16
|
-
return typeCheckerResult;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
if (typeof props[propName] !== 'undefined' && !props[requiredProp]) {
|
|
20
|
-
return new Error(`The prop \`${propFullNameSafe}\` of ` + `\`${componentNameInError}\` can only be used together with the \`${requiredProp}\` prop.`);
|
|
21
|
-
}
|
|
22
|
-
return null;
|
|
23
|
-
};
|
|
24
|
-
return requireProp;
|
|
25
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./resolveComponentProps.js";
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* If `componentProps` is a function, calls it with the provided `ownerState`.
|
|
3
|
-
* Otherwise, just returns `componentProps`.
|
|
4
|
-
*/
|
|
5
|
-
function resolveComponentProps(componentProps, ownerState, slotState) {
|
|
6
|
-
if (typeof componentProps === 'function') {
|
|
7
|
-
return componentProps(ownerState, slotState);
|
|
8
|
-
}
|
|
9
|
-
return componentProps;
|
|
10
|
-
}
|
|
11
|
-
export default resolveComponentProps;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./resolveProps.js";
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Add keys, values of `defaultProps` that does not exist in `props`
|
|
3
|
-
* @param defaultProps
|
|
4
|
-
* @param props
|
|
5
|
-
* @returns resolved props
|
|
6
|
-
*/
|
|
7
|
-
export default function resolveProps(defaultProps, props) {
|
|
8
|
-
const output = {
|
|
9
|
-
...props
|
|
10
|
-
};
|
|
11
|
-
for (const key in defaultProps) {
|
|
12
|
-
if (Object.prototype.hasOwnProperty.call(defaultProps, key)) {
|
|
13
|
-
const propName = key;
|
|
14
|
-
if (propName === 'components' || propName === 'slots') {
|
|
15
|
-
output[propName] = {
|
|
16
|
-
...defaultProps[propName],
|
|
17
|
-
...output[propName]
|
|
18
|
-
};
|
|
19
|
-
} else if (propName === 'componentsProps' || propName === 'slotProps') {
|
|
20
|
-
const defaultSlotProps = defaultProps[propName];
|
|
21
|
-
const slotProps = props[propName];
|
|
22
|
-
if (!slotProps) {
|
|
23
|
-
output[propName] = defaultSlotProps || {};
|
|
24
|
-
} else if (!defaultSlotProps) {
|
|
25
|
-
output[propName] = slotProps;
|
|
26
|
-
} else {
|
|
27
|
-
output[propName] = {
|
|
28
|
-
...slotProps
|
|
29
|
-
};
|
|
30
|
-
for (const slotKey in defaultSlotProps) {
|
|
31
|
-
if (Object.prototype.hasOwnProperty.call(defaultSlotProps, slotKey)) {
|
|
32
|
-
const slotPropName = slotKey;
|
|
33
|
-
output[propName][slotPropName] = resolveProps(defaultSlotProps[slotPropName], slotProps[slotPropName]);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
} else if (output[propName] === undefined) {
|
|
38
|
-
output[propName] = defaultProps[propName];
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return output;
|
|
43
|
-
}
|
package/modern/setRef/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./setRef.js";
|
package/modern/setRef/setRef.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TODO v5: consider making it private
|
|
3
|
-
*
|
|
4
|
-
* passes {value} to {ref}
|
|
5
|
-
*
|
|
6
|
-
* WARNING: Be sure to only call this inside a callback that is passed as a ref.
|
|
7
|
-
* Otherwise, make sure to cleanup the previous {ref} if it changes. See
|
|
8
|
-
* https://github.com/mui/material-ui/issues/13539
|
|
9
|
-
*
|
|
10
|
-
* Useful if you want to expose the ref of an inner component to the public API
|
|
11
|
-
* while still using it inside the component.
|
|
12
|
-
* @param ref A ref callback or ref object. If anything falsy, this is a no-op.
|
|
13
|
-
*/
|
|
14
|
-
export default function setRef(ref, value) {
|
|
15
|
-
if (typeof ref === 'function') {
|
|
16
|
-
ref(value);
|
|
17
|
-
} else if (ref) {
|
|
18
|
-
ref.current = value;
|
|
19
|
-
}
|
|
20
|
-
}
|
package/modern/types/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./unsupportedProp.js";
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export default function unsupportedProp(props, propName, componentName, location, propFullName) {
|
|
2
|
-
if (process.env.NODE_ENV === 'production') {
|
|
3
|
-
return null;
|
|
4
|
-
}
|
|
5
|
-
const propFullNameSafe = propFullName || propName;
|
|
6
|
-
if (typeof props[propName] !== 'undefined') {
|
|
7
|
-
return new Error(`The prop \`${propFullNameSafe}\` is not supported. Please remove it.`);
|
|
8
|
-
}
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./useControlled.js";
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
// TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler -- process.env never changes, dependency arrays are intentionally ignored
|
|
4
|
-
/* eslint-disable react-hooks/rules-of-hooks, react-hooks/exhaustive-deps */
|
|
5
|
-
import * as React from 'react';
|
|
6
|
-
export default function useControlled({
|
|
7
|
-
controlled,
|
|
8
|
-
default: defaultProp,
|
|
9
|
-
name,
|
|
10
|
-
state = 'value'
|
|
11
|
-
}) {
|
|
12
|
-
// isControlled is ignored in the hook dependency lists as it should never change.
|
|
13
|
-
const {
|
|
14
|
-
current: isControlled
|
|
15
|
-
} = React.useRef(controlled !== undefined);
|
|
16
|
-
const [valueState, setValue] = React.useState(defaultProp);
|
|
17
|
-
const value = isControlled ? controlled : valueState;
|
|
18
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
19
|
-
React.useEffect(() => {
|
|
20
|
-
if (isControlled !== (controlled !== undefined)) {
|
|
21
|
-
console.error([`MUI: A component is changing the ${isControlled ? '' : 'un'}controlled ${state} state of ${name} to be ${isControlled ? 'un' : ''}controlled.`, 'Elements should not switch from uncontrolled to controlled (or vice versa).', `Decide between using a controlled or uncontrolled ${name} ` + 'element for the lifetime of the component.', "The nature of the state is determined during the first render. It's considered controlled if the value is not `undefined`.", 'More info: https://fb.me/react-controlled-components'].join('\n'));
|
|
22
|
-
}
|
|
23
|
-
}, [state, name, controlled]);
|
|
24
|
-
const {
|
|
25
|
-
current: defaultValue
|
|
26
|
-
} = React.useRef(defaultProp);
|
|
27
|
-
React.useEffect(() => {
|
|
28
|
-
// Object.is() is not equivalent to the === operator.
|
|
29
|
-
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is for more details.
|
|
30
|
-
if (!isControlled && !Object.is(defaultValue, defaultProp)) {
|
|
31
|
-
console.error([`MUI: A component is changing the default ${state} state of an uncontrolled ${name} after being initialized. ` + `To suppress this warning opt to use a controlled ${name}.`].join('\n'));
|
|
32
|
-
}
|
|
33
|
-
}, [JSON.stringify(defaultProp)]);
|
|
34
|
-
}
|
|
35
|
-
const setValueIfUncontrolled = React.useCallback(newValue => {
|
|
36
|
-
if (!isControlled) {
|
|
37
|
-
setValue(newValue);
|
|
38
|
-
}
|
|
39
|
-
}, []);
|
|
40
|
-
return [value, setValueIfUncontrolled];
|
|
41
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./useEnhancedEffect.js";
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* A version of `React.useLayoutEffect` that does not show a warning when server-side rendering.
|
|
7
|
-
* This is useful for effects that are only needed for client-side rendering but not for SSR.
|
|
8
|
-
*
|
|
9
|
-
* Before you use this hook, make sure to read https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85
|
|
10
|
-
* and confirm it doesn't apply to your use-case.
|
|
11
|
-
*/
|
|
12
|
-
const useEnhancedEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
|
|
13
|
-
export default useEnhancedEffect;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./useEventCallback.js";
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
import useEnhancedEffect from "../useEnhancedEffect/index.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Inspired by https://github.com/facebook/react/issues/14099#issuecomment-440013892
|
|
8
|
-
* See RFC in https://github.com/reactjs/rfcs/pull/220
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
function useEventCallback(fn) {
|
|
12
|
-
const ref = React.useRef(fn);
|
|
13
|
-
useEnhancedEffect(() => {
|
|
14
|
-
ref.current = fn;
|
|
15
|
-
});
|
|
16
|
-
return React.useRef((...args) =>
|
|
17
|
-
// @ts-expect-error hide `this`
|
|
18
|
-
(0, ref.current)(...args)).current;
|
|
19
|
-
}
|
|
20
|
-
export default useEventCallback;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./useForkRef.js";
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
import setRef from "../setRef/index.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Takes an array of refs and returns a new ref which will apply any modification to all of the refs.
|
|
8
|
-
* This is useful when you want to have the ref used in multiple places.
|
|
9
|
-
*
|
|
10
|
-
* ```tsx
|
|
11
|
-
* const rootRef = React.useRef<Instance>(null);
|
|
12
|
-
* const refFork = useForkRef(rootRef, props.ref);
|
|
13
|
-
*
|
|
14
|
-
* return (
|
|
15
|
-
* <Root {...props} ref={refFork} />
|
|
16
|
-
* );
|
|
17
|
-
* ```
|
|
18
|
-
*
|
|
19
|
-
* @param {Array<React.Ref<Instance> | undefined>} refs The ref array.
|
|
20
|
-
* @returns {React.RefCallback<Instance> | null} The new ref callback.
|
|
21
|
-
*/
|
|
22
|
-
export default function useForkRef(...refs) {
|
|
23
|
-
/**
|
|
24
|
-
* This will create a new function if the refs passed to this hook change and are all defined.
|
|
25
|
-
* This means react will call the old forkRef with `null` and the new forkRef
|
|
26
|
-
* with the ref. Cleanup naturally emerges from this behavior.
|
|
27
|
-
*/
|
|
28
|
-
return React.useMemo(() => {
|
|
29
|
-
if (refs.every(ref => ref == null)) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
return instance => {
|
|
33
|
-
refs.forEach(ref => {
|
|
34
|
-
setRef(ref, instance);
|
|
35
|
-
});
|
|
36
|
-
};
|
|
37
|
-
// TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler -- intentionally ignoring that the dependency array must be an array literal
|
|
38
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
39
|
-
}, refs);
|
|
40
|
-
}
|
package/modern/useId/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./useId.js";
|
package/modern/useId/useId.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
let globalId = 0;
|
|
5
|
-
|
|
6
|
-
// TODO React 17: Remove `useGlobalId` once React 17 support is removed
|
|
7
|
-
function useGlobalId(idOverride) {
|
|
8
|
-
const [defaultId, setDefaultId] = React.useState(idOverride);
|
|
9
|
-
const id = idOverride || defaultId;
|
|
10
|
-
React.useEffect(() => {
|
|
11
|
-
if (defaultId == null) {
|
|
12
|
-
// Fallback to this default id when possible.
|
|
13
|
-
// Use the incrementing value for client-side rendering only.
|
|
14
|
-
// We can't use it server-side.
|
|
15
|
-
// If you want to use random values please consider the Birthday Problem: https://en.wikipedia.org/wiki/Birthday_problem
|
|
16
|
-
globalId += 1;
|
|
17
|
-
setDefaultId(`mui-${globalId}`);
|
|
18
|
-
}
|
|
19
|
-
}, [defaultId]);
|
|
20
|
-
return id;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// See https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379 for why
|
|
24
|
-
const safeReact = {
|
|
25
|
-
...React
|
|
26
|
-
};
|
|
27
|
-
const maybeReactUseId = safeReact.useId;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
*
|
|
31
|
-
* @example <div id={useId()} />
|
|
32
|
-
* @param idOverride
|
|
33
|
-
* @returns {string}
|
|
34
|
-
*/
|
|
35
|
-
export default function useId(idOverride) {
|
|
36
|
-
// React.useId() is only available from React 17.0.0.
|
|
37
|
-
if (maybeReactUseId !== undefined) {
|
|
38
|
-
const reactId = maybeReactUseId();
|
|
39
|
-
return idOverride ?? reactId;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler
|
|
43
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks -- `React.useId` is invariant at runtime.
|
|
44
|
-
return useGlobalId(idOverride);
|
|
45
|
-
}
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
// based on https://github.com/WICG/focus-visible/blob/v4.1.5/src/focus-visible.js
|
|
4
|
-
import * as React from 'react';
|
|
5
|
-
import { Timeout } from "../useTimeout/useTimeout.js";
|
|
6
|
-
let hadKeyboardEvent = true;
|
|
7
|
-
let hadFocusVisibleRecently = false;
|
|
8
|
-
const hadFocusVisibleRecentlyTimeout = new Timeout();
|
|
9
|
-
const inputTypesWhitelist = {
|
|
10
|
-
text: true,
|
|
11
|
-
search: true,
|
|
12
|
-
url: true,
|
|
13
|
-
tel: true,
|
|
14
|
-
email: true,
|
|
15
|
-
password: true,
|
|
16
|
-
number: true,
|
|
17
|
-
date: true,
|
|
18
|
-
month: true,
|
|
19
|
-
week: true,
|
|
20
|
-
time: true,
|
|
21
|
-
datetime: true,
|
|
22
|
-
'datetime-local': true
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Computes whether the given element should automatically trigger the
|
|
27
|
-
* `focus-visible` class being added, i.e. whether it should always match
|
|
28
|
-
* `:focus-visible` when focused.
|
|
29
|
-
* @param {Element} node
|
|
30
|
-
* @returns {boolean}
|
|
31
|
-
*/
|
|
32
|
-
function focusTriggersKeyboardModality(node) {
|
|
33
|
-
const {
|
|
34
|
-
type,
|
|
35
|
-
tagName
|
|
36
|
-
} = node;
|
|
37
|
-
if (tagName === 'INPUT' && inputTypesWhitelist[type] && !node.readOnly) {
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
if (tagName === 'TEXTAREA' && !node.readOnly) {
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
if (node.isContentEditable) {
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Keep track of our keyboard modality state with `hadKeyboardEvent`.
|
|
51
|
-
* If the most recent user interaction was via the keyboard;
|
|
52
|
-
* and the key press did not include a meta, alt/option, or control key;
|
|
53
|
-
* then the modality is keyboard. Otherwise, the modality is not keyboard.
|
|
54
|
-
* @param {KeyboardEvent} event
|
|
55
|
-
*/
|
|
56
|
-
function handleKeyDown(event) {
|
|
57
|
-
if (event.metaKey || event.altKey || event.ctrlKey) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
hadKeyboardEvent = true;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* If at any point a user clicks with a pointing device, ensure that we change
|
|
65
|
-
* the modality away from keyboard.
|
|
66
|
-
* This avoids the situation where a user presses a key on an already focused
|
|
67
|
-
* element, and then clicks on a different element, focusing it with a
|
|
68
|
-
* pointing device, while we still think we're in keyboard modality.
|
|
69
|
-
*/
|
|
70
|
-
function handlePointerDown() {
|
|
71
|
-
hadKeyboardEvent = false;
|
|
72
|
-
}
|
|
73
|
-
function handleVisibilityChange() {
|
|
74
|
-
if (this.visibilityState === 'hidden') {
|
|
75
|
-
// If the tab becomes active again, the browser will handle calling focus
|
|
76
|
-
// on the element (Safari actually calls it twice).
|
|
77
|
-
// If this tab change caused a blur on an element with focus-visible,
|
|
78
|
-
// re-apply the class when the user switches back to the tab.
|
|
79
|
-
if (hadFocusVisibleRecently) {
|
|
80
|
-
hadKeyboardEvent = true;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
function prepare(doc) {
|
|
85
|
-
doc.addEventListener('keydown', handleKeyDown, true);
|
|
86
|
-
doc.addEventListener('mousedown', handlePointerDown, true);
|
|
87
|
-
doc.addEventListener('pointerdown', handlePointerDown, true);
|
|
88
|
-
doc.addEventListener('touchstart', handlePointerDown, true);
|
|
89
|
-
doc.addEventListener('visibilitychange', handleVisibilityChange, true);
|
|
90
|
-
}
|
|
91
|
-
export function teardown(doc) {
|
|
92
|
-
doc.removeEventListener('keydown', handleKeyDown, true);
|
|
93
|
-
doc.removeEventListener('mousedown', handlePointerDown, true);
|
|
94
|
-
doc.removeEventListener('pointerdown', handlePointerDown, true);
|
|
95
|
-
doc.removeEventListener('touchstart', handlePointerDown, true);
|
|
96
|
-
doc.removeEventListener('visibilitychange', handleVisibilityChange, true);
|
|
97
|
-
}
|
|
98
|
-
function isFocusVisible(event) {
|
|
99
|
-
const {
|
|
100
|
-
target
|
|
101
|
-
} = event;
|
|
102
|
-
try {
|
|
103
|
-
return target.matches(':focus-visible');
|
|
104
|
-
} catch (error) {
|
|
105
|
-
// Browsers not implementing :focus-visible will throw a SyntaxError.
|
|
106
|
-
// We use our own heuristic for those browsers.
|
|
107
|
-
// Rethrow might be better if it's not the expected error but do we really
|
|
108
|
-
// want to crash if focus-visible malfunctioned?
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// No need for validFocusTarget check. The user does that by attaching it to
|
|
112
|
-
// focusable events only.
|
|
113
|
-
return hadKeyboardEvent || focusTriggersKeyboardModality(target);
|
|
114
|
-
}
|
|
115
|
-
export default function useIsFocusVisible() {
|
|
116
|
-
const ref = React.useCallback(node => {
|
|
117
|
-
if (node != null) {
|
|
118
|
-
prepare(node.ownerDocument);
|
|
119
|
-
}
|
|
120
|
-
}, []);
|
|
121
|
-
const isFocusVisibleRef = React.useRef(false);
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Should be called if a blur event is fired
|
|
125
|
-
*/
|
|
126
|
-
function handleBlurVisible() {
|
|
127
|
-
// checking against potential state variable does not suffice if we focus and blur synchronously.
|
|
128
|
-
// React wouldn't have time to trigger a re-render so `focusVisible` would be stale.
|
|
129
|
-
// Ideally we would adjust `isFocusVisible(event)` to look at `relatedTarget` for blur events.
|
|
130
|
-
// This doesn't work in IE11 due to https://github.com/facebook/react/issues/3751
|
|
131
|
-
// TODO: check again if React releases their internal changes to focus event handling (https://github.com/facebook/react/pull/19186).
|
|
132
|
-
if (isFocusVisibleRef.current) {
|
|
133
|
-
// To detect a tab/window switch, we look for a blur event followed
|
|
134
|
-
// rapidly by a visibility change.
|
|
135
|
-
// If we don't see a visibility change within 100ms, it's probably a
|
|
136
|
-
// regular focus change.
|
|
137
|
-
hadFocusVisibleRecently = true;
|
|
138
|
-
hadFocusVisibleRecentlyTimeout.start(100, () => {
|
|
139
|
-
hadFocusVisibleRecently = false;
|
|
140
|
-
});
|
|
141
|
-
isFocusVisibleRef.current = false;
|
|
142
|
-
return true;
|
|
143
|
-
}
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Should be called if a blur event is fired
|
|
149
|
-
*/
|
|
150
|
-
function handleFocusVisible(event) {
|
|
151
|
-
if (isFocusVisible(event)) {
|
|
152
|
-
isFocusVisibleRef.current = true;
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
|
-
return {
|
|
158
|
-
isFocusVisibleRef,
|
|
159
|
-
onFocus: handleFocusVisible,
|
|
160
|
-
onBlur: handleBlurVisible,
|
|
161
|
-
ref
|
|
162
|
-
};
|
|
163
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./useLazyRef.js";
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
const UNINITIALIZED = {};
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* A React.useRef() that is initialized lazily with a function. Note that it accepts an optional
|
|
8
|
-
* initialization argument, so the initialization function doesn't need to be an inline closure.
|
|
9
|
-
*
|
|
10
|
-
* @usage
|
|
11
|
-
* const ref = useLazyRef(sortColumns, columns)
|
|
12
|
-
*/
|
|
13
|
-
export default function useLazyRef(init, initArg) {
|
|
14
|
-
const ref = React.useRef(UNINITIALIZED);
|
|
15
|
-
if (ref.current === UNINITIALIZED) {
|
|
16
|
-
ref.current = init(initArg);
|
|
17
|
-
}
|
|
18
|
-
return ref;
|
|
19
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./useLocalStorageState.js";
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
|
|
5
|
-
// storage events only work across tabs, we'll use an event emitter to announce within the current tab
|
|
6
|
-
const currentTabChangeListeners = new Map();
|
|
7
|
-
function onCurrentTabStorageChange(key, handler) {
|
|
8
|
-
let listeners = currentTabChangeListeners.get(key);
|
|
9
|
-
if (!listeners) {
|
|
10
|
-
listeners = new Set();
|
|
11
|
-
currentTabChangeListeners.set(key, listeners);
|
|
12
|
-
}
|
|
13
|
-
listeners.add(handler);
|
|
14
|
-
}
|
|
15
|
-
function offCurrentTabStorageChange(key, handler) {
|
|
16
|
-
const listeners = currentTabChangeListeners.get(key);
|
|
17
|
-
if (!listeners) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
listeners.delete(handler);
|
|
21
|
-
if (listeners.size === 0) {
|
|
22
|
-
currentTabChangeListeners.delete(key);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
function emitCurrentTabStorageChange(key) {
|
|
26
|
-
const listeners = currentTabChangeListeners.get(key);
|
|
27
|
-
if (listeners) {
|
|
28
|
-
listeners.forEach(listener => listener());
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
function subscribe(area, key, callback) {
|
|
32
|
-
if (!key) {
|
|
33
|
-
return () => {};
|
|
34
|
-
}
|
|
35
|
-
const storageHandler = event => {
|
|
36
|
-
if (event.storageArea === area && event.key === key) {
|
|
37
|
-
callback();
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
window.addEventListener('storage', storageHandler);
|
|
41
|
-
onCurrentTabStorageChange(key, callback);
|
|
42
|
-
return () => {
|
|
43
|
-
window.removeEventListener('storage', storageHandler);
|
|
44
|
-
offCurrentTabStorageChange(key, callback);
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
function getSnapshot(area, key) {
|
|
48
|
-
if (!key) {
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
try {
|
|
52
|
-
return area.getItem(key);
|
|
53
|
-
} catch {
|
|
54
|
-
// ignore
|
|
55
|
-
// See https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API#feature-detecting_localstorage
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
function setValue(area, key, value) {
|
|
60
|
-
if (!key) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
try {
|
|
64
|
-
if (value === null) {
|
|
65
|
-
area.removeItem(key);
|
|
66
|
-
} else {
|
|
67
|
-
area.setItem(key, String(value));
|
|
68
|
-
}
|
|
69
|
-
} catch {
|
|
70
|
-
// ignore
|
|
71
|
-
// See https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API#feature-detecting_localstorage
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
emitCurrentTabStorageChange(key);
|
|
75
|
-
}
|
|
76
|
-
const serverValue = [null, () => {}];
|
|
77
|
-
function useLocalStorageStateServer() {
|
|
78
|
-
return serverValue;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Sync state to local storage so that it persists through a page refresh. Usage is
|
|
83
|
-
* similar to useState except we pass in a storage key so that we can default
|
|
84
|
-
* to that value on page load instead of the specified initial value.
|
|
85
|
-
*
|
|
86
|
-
* Since the storage API isn't available in server-rendering environments, we
|
|
87
|
-
* return null during SSR and hydration.
|
|
88
|
-
*/
|
|
89
|
-
function useLocalStorageStateBrowser(key, initializer = null) {
|
|
90
|
-
const [initialValue] = React.useState(initializer);
|
|
91
|
-
const area = window.localStorage;
|
|
92
|
-
const subscribeKey = React.useCallback(callback => subscribe(area, key, callback), [area, key]);
|
|
93
|
-
const getKeySnapshot = React.useCallback(() => getSnapshot(area, key) ?? initialValue, [area, initialValue, key]);
|
|
94
|
-
|
|
95
|
-
// Start with null for the hydration, and then switch to the actual value.
|
|
96
|
-
const getKeyServerSnapshot = () => null;
|
|
97
|
-
const storedValue = React.useSyncExternalStore(subscribeKey, getKeySnapshot, getKeyServerSnapshot);
|
|
98
|
-
const setStoredValue = React.useCallback(value => {
|
|
99
|
-
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
100
|
-
setValue(area, key, valueToStore);
|
|
101
|
-
}, [area, key, storedValue]);
|
|
102
|
-
const [nonStoredValue, setNonStoredValue] = React.useState(initialValue);
|
|
103
|
-
if (!key) {
|
|
104
|
-
return [nonStoredValue, setNonStoredValue];
|
|
105
|
-
}
|
|
106
|
-
return [storedValue, setStoredValue];
|
|
107
|
-
}
|
|
108
|
-
export default typeof window === 'undefined' ? useLocalStorageStateServer : useLocalStorageStateBrowser;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./useOnMount.js";
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
const EMPTY = [];
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* A React.useEffect equivalent that runs once, when the component is mounted.
|
|
8
|
-
*/
|
|
9
|
-
export default function useOnMount(fn) {
|
|
10
|
-
// TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler -- no need to put `fn` in the dependency array
|
|
11
|
-
/* eslint-disable react-hooks/exhaustive-deps */
|
|
12
|
-
React.useEffect(fn, EMPTY);
|
|
13
|
-
/* eslint-enable react-hooks/exhaustive-deps */
|
|
14
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./usePreviousProps.js";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "./useSlotProps.js";
|