UNPKG

3.88 kBJavaScriptView Raw
1'use client';
2
3import * as React from 'react';
4import PropTypes from 'prop-types';
5import getDisplayName from '@mui/utils/getDisplayName';
6import { getThemeProps } from '@mui/system/useThemeProps';
7import useTheme from "../styles/useTheme.js";
8import useEnhancedEffect from "../utils/useEnhancedEffect.js";
9import useMediaQuery from "../useMediaQuery/index.js";
10import { jsx as _jsx } from "react/jsx-runtime";
11const breakpointKeys = ['xs', 'sm', 'md', 'lg', 'xl'];
12
13// By default, returns true if screen width is the same or greater than the given breakpoint.
14export const isWidthUp = (breakpoint, width, inclusive = true) => {
15 if (inclusive) {
16 return breakpointKeys.indexOf(breakpoint) <= breakpointKeys.indexOf(width);
17 }
18 return breakpointKeys.indexOf(breakpoint) < breakpointKeys.indexOf(width);
19};
20
21// By default, returns true if screen width is less than the given breakpoint.
22export const isWidthDown = (breakpoint, width, inclusive = false) => {
23 if (inclusive) {
24 return breakpointKeys.indexOf(width) <= breakpointKeys.indexOf(breakpoint);
25 }
26 return breakpointKeys.indexOf(width) < breakpointKeys.indexOf(breakpoint);
27};
28const withWidth = (options = {}) => Component => {
29 const {
30 withTheme: withThemeOption = false,
31 noSSR = false,
32 initialWidth: initialWidthOption
33 } = options;
34 function WithWidth(props) {
35 const contextTheme = useTheme();
36 const theme = props.theme || contextTheme;
37 const {
38 initialWidth,
39 width,
40 ...other
41 } = getThemeProps({
42 theme,
43 name: 'MuiWithWidth',
44 props
45 });
46 const [mountedState, setMountedState] = React.useState(false);
47 useEnhancedEffect(() => {
48 setMountedState(true);
49 }, []);
50
51 /**
52 * innerWidth |xs sm md lg xl
53 * |-------|-------|-------|-------|------>
54 * width | xs | sm | md | lg | xl
55 */
56 const keys = theme.breakpoints.keys.slice().reverse();
57 const widthComputed = keys.reduce((output, key) => {
58 // TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler
59 // eslint-disable-next-line react-hooks/rules-of-hooks
60 const matches = useMediaQuery(theme.breakpoints.up(key));
61 return !output && matches ? key : output;
62 }, null);
63 const more = {
64 width: width || (mountedState || noSSR ? widthComputed : undefined) || initialWidth || initialWidthOption,
65 ...(withThemeOption ? {
66 theme
67 } : {}),
68 ...other
69 };
70
71 // When rendering the component on the server,
72 // we have no idea about the client browser screen width.
73 // In order to prevent blinks and help the reconciliation of the React tree
74 // we are not rendering the child component.
75 //
76 // An alternative is to use the `initialWidth` property.
77 if (more.width === undefined) {
78 return null;
79 }
80 return /*#__PURE__*/_jsx(Component, {
81 ...more
82 });
83 }
84 process.env.NODE_ENV !== "production" ? WithWidth.propTypes = {
85 /**
86 * As `window.innerWidth` is unavailable on the server,
87 * we default to rendering an empty component during the first mount.
88 * You might want to use a heuristic to approximate
89 * the screen width of the client browser screen width.
90 *
91 * For instance, you could be using the user-agent or the client-hints.
92 * https://caniuse.com/#search=client%20hint
93 */
94 initialWidth: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
95 /**
96 * @ignore
97 */
98 theme: PropTypes.object,
99 /**
100 * Bypass the width calculation logic.
101 */
102 width: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl'])
103 } : void 0;
104 if (process.env.NODE_ENV !== 'production') {
105 WithWidth.displayName = `WithWidth(${getDisplayName(Component)})`;
106 }
107 return WithWidth;
108};
109export default withWidth;
\No newline at end of file