Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[material-ui][mui-system] Refactor types so they're compatible with upcoming React 19 #43276

Merged
merged 32 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
5a25eed
Bump React to 19
aarongarciah Jul 2, 2024
87e8897
Run useRef codemod
DiegoAndai Jul 3, 2024
a6c2910
Fix remaining types issues (on mui side)
DiegoAndai Jul 4, 2024
434dc0c
Remove resolutions for @types/react
Janpot Jul 19, 2024
5281e6e
patch deps
Janpot Jul 19, 2024
3e69aab
next 15
Janpot Jul 19, 2024
1165885
docs
Janpot Jul 19, 2024
11351f1
Update some React refs types and default values
aarongarciah Jul 22, 2024
387a417
Stop using deprecated React.MutableRefObject
aarongarciah Jul 22, 2024
e19b10e
More RefObject type changes
aarongarciah Jul 23, 2024
9cd55a8
Update to latest React rc
aarongarciah Jul 23, 2024
ed5c61e
Update pnpm-lock.yaml
Janpot Jul 24, 2024
107c35c
revert
Janpot Jul 24, 2024
c8208da
Fix next types
Janpot Jul 25, 2024
d98ec07
Apply changes to base hooks that were moved into material
DiegoAndai Jul 25, 2024
fdf18fa
pnpm docs:api
DiegoAndai Jul 25, 2024
efea014
Fix missing docs type issues
DiegoAndai Jul 25, 2024
7851311
Update to latest React rc
aarongarciah Jul 26, 2024
ec61d68
Fix type issue after merging next
DiegoAndai Jul 31, 2024
1ded074
pnpm dedupe
DiegoAndai Jul 31, 2024
f11c403
Fix remaining element.ref access issues
DiegoAndai Jul 31, 2024
a9c0ba3
Remove stale util
DiegoAndai Aug 1, 2024
4f80419
pnpm dedupe
DiegoAndai Aug 1, 2024
2cefda7
pnpm dedupe
aarongarciah Aug 5, 2024
e5d9697
Update to latest React rc
aarongarciah Aug 6, 2024
6e4d71c
Undo whitespace change
aarongarciah Aug 6, 2024
a92c9ea
pnpm dedupe
aarongarciah Aug 6, 2024
8fca03d
Fix Modal test
aarongarciah Aug 9, 2024
3078213
Update to latest React rc
aarongarciah Aug 12, 2024
c97d39b
Explicitly type useRef
DiegoAndai Aug 12, 2024
a2ce4ba
Revert changes that are not compatible with React 18
DiegoAndai Aug 12, 2024
0254d0a
Improve child prop type check
DiegoAndai Aug 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/data/joy/components/input/DebouncedInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Box from '@mui/joy/Box';
function DebounceInput(props) {
const { handleDebounce, debounceTimeout, ...other } = props;

const timerRef = React.useRef();
const timerRef = React.useRef(undefined);

const handleChange = (event) => {
clearTimeout(timerRef.current);
Expand Down
4 changes: 3 additions & 1 deletion docs/data/joy/components/input/DebouncedInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ type DebounceProps = {
function DebounceInput(props: InputProps & DebounceProps) {
const { handleDebounce, debounceTimeout, ...other } = props;

const timerRef = React.useRef<ReturnType<typeof setTimeout>>();
const timerRef = React.useRef<ReturnType<typeof setTimeout> | undefined>(
undefined,
);

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
clearTimeout(timerRef.current);
Expand Down
4 changes: 2 additions & 2 deletions docs/data/joy/components/snackbar/SnackbarHideDuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export default function SnackbarHideDuration() {
const [open, setOpen] = React.useState(false);
const [duration, setDuration] = React.useState();
const [left, setLeft] = React.useState();
const timer = React.useRef();
const timer = React.useRef(undefined);
const countdown = () => {
timer.current = window.setInterval(() => {
timer.current = setInterval(() => {
setLeft((prev) => (prev === undefined ? prev : Math.max(0, prev - 100)));
}, 100);
};
Expand Down
4 changes: 2 additions & 2 deletions docs/data/joy/components/snackbar/SnackbarHideDuration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export default function SnackbarHideDuration() {
const [open, setOpen] = React.useState(false);
const [duration, setDuration] = React.useState<undefined | number>();
const [left, setLeft] = React.useState<undefined | number>();
const timer = React.useRef<undefined | number>();
const timer = React.useRef<ReturnType<typeof setInterval> | undefined>(undefined);
const countdown = () => {
timer.current = window.setInterval(() => {
timer.current = setInterval(() => {
setLeft((prev) => (prev === undefined ? prev : Math.max(0, prev - 100)));
}, 100);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import SaveIcon from '@mui/icons-material/Save';
export default function CircularIntegration() {
const [loading, setLoading] = React.useState(false);
const [success, setSuccess] = React.useState(false);
const timer = React.useRef();
const timer = React.useRef(undefined);

const buttonSx = {
...(success && {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import SaveIcon from '@mui/icons-material/Save';
export default function CircularIntegration() {
const [loading, setLoading] = React.useState(false);
const [success, setSuccess] = React.useState(false);
const timer = React.useRef<ReturnType<typeof setTimeout>>();
const timer = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined);

const buttonSx = {
...(success && {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Typography from '@mui/material/Typography';
export default function DelayingAppearance() {
const [loading, setLoading] = React.useState(false);
const [query, setQuery] = React.useState('idle');
const timerRef = React.useRef();
const timerRef = React.useRef(undefined);

React.useEffect(
() => () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import Typography from '@mui/material/Typography';
export default function DelayingAppearance() {
const [loading, setLoading] = React.useState(false);
const [query, setQuery] = React.useState('idle');
const timerRef = React.useRef<ReturnType<typeof setTimeout>>();
const timerRef = React.useRef<ReturnType<typeof setTimeout> | undefined>(
undefined,
);

React.useEffect(
() => () => {
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/base-ui/api/use-autocomplete.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@
},
"unstable_isActiveElementInListbox": {
"type": {
"name": "(listbox: React.RefObject&lt;HTMLElement&gt;) =&gt; boolean",
"description": "(listbox: React.RefObject&lt;HTMLElement&gt;) =&gt; boolean"
"name": "(listbox: React.RefObject&lt;HTMLElement | null&gt;) =&gt; boolean",
"description": "(listbox: React.RefObject&lt;HTMLElement | null&gt;) =&gt; boolean"
}
},
"value": {
Expand Down
2 changes: 1 addition & 1 deletion docs/src/components/animation/FlashCode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const FlashCode = React.forwardRef(function FlashCode(
startLine?: number;
lineHeight?: number | string;
},
ref: React.Ref<HTMLDivElement>,
ref: React.ForwardedRef<HTMLDivElement>,
) {
const { children, startLine = 0, endLine = startLine, lineHeight = '0.75rem', ...other } = props;

Expand Down
21 changes: 13 additions & 8 deletions docs/src/modules/components/JoyThemeBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -978,7 +978,11 @@ function filterGlobalVariantTokens(palette: Partial<PaletteVariant>, variant: Va
return tokens;
}

type StateReducer<T> = (state: T, action: Partial<T>) => T;
type ReducerState = {
hover: boolean;
active: boolean;
disabled: boolean;
};

function GlobalVariantForm({
color,
Expand All @@ -996,13 +1000,14 @@ function GlobalVariantForm({
onRemove: (token: string) => void;
}) {
const [selectedVariant, setSelectedVariant] = React.useState<VariantProp>('solid');
const [states, setStates] = React.useReducer<
StateReducer<{ hover: boolean; active: boolean; disabled: boolean }>
>((prevState, action) => ({ ...prevState, ...action }), {
hover: false,
active: false,
disabled: false,
});
const [states, setStates] = React.useReducer(
(prevState: ReducerState, action: Partial<ReducerState>) => ({ ...prevState, ...action }),
{
hover: false,
active: false,
disabled: false,
},
);
const themeDefaultValue = filterGlobalVariantTokens(themeDefaultValueProp, selectedVariant);
const value = filterGlobalVariantTokens(valueProp, selectedVariant);
const mergedValue = { ...themeDefaultValue, ...value };
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-base/src/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const Button = React.forwardRef(function Button<RootComponentType extends React.
...other
} = props;

const buttonRef = React.useRef<HTMLButtonElement | HTMLAnchorElement | HTMLElement>();
const buttonRef = React.useRef<HTMLButtonElement | HTMLAnchorElement | HTMLElement | null>(null);

let rootElementName = rootElementNameProp;

Expand Down
2 changes: 1 addition & 1 deletion packages/mui-base/src/Tab/Tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const Tab = React.forwardRef(function Tab<RootComponentType extends React.Elemen
...other
} = props;

const tabRef = React.useRef<HTMLButtonElement | HTMLAnchorElement | HTMLElement>();
const tabRef = React.useRef<HTMLButtonElement | HTMLAnchorElement | HTMLElement | null>(null);
const handleRef = useForkRef(tabRef, forwardedRef);

const { active, highlighted, selected, getRootProps } = useTab({
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-base/src/useAutocomplete/useAutocomplete.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export interface UseAutocompleteProps<
* Temporary for Joy UI because the parent listbox is the document object
* TODO v6: Normalize the logic and remove this param.
*/
unstable_isActiveElementInListbox?: (listbox: React.RefObject<HTMLElement>) => boolean;
unstable_isActiveElementInListbox?: (listbox: React.RefObject<HTMLElement | null>) => boolean;
/**
* If `true`, the portion of the selected suggestion that the user hasn't typed,
* known as the completion string, appears inline after the input cursor in the textbox.
Expand Down
4 changes: 2 additions & 2 deletions packages/mui-base/src/useButton/useButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function useButton(parameters: UseButtonParameters = {}): UseButtonReturn
type,
rootElementName: rootElementNameProp,
} = parameters;
const buttonRef = React.useRef<HTMLButtonElement | HTMLAnchorElement | HTMLElement>();
const buttonRef = React.useRef<HTMLButtonElement | HTMLAnchorElement | HTMLElement | null>(null);

const [active, setActive] = React.useState<boolean>(false);

Expand Down Expand Up @@ -200,7 +200,7 @@ export function useButton(parameters: UseButtonParameters = {}): UseButtonReturn
}
if (disabled) {
buttonProps['aria-disabled'] = disabled as boolean;
buttonProps.tabIndex = focusableWhenDisabled ? tabIndex ?? 0 : -1;
buttonProps.tabIndex = focusableWhenDisabled ? (tabIndex ?? 0) : -1;
}
}

Expand Down
8 changes: 4 additions & 4 deletions packages/mui-base/src/useCompound/useCompound.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { render } from '@mui/internal-test-utils';
import { CompoundComponentContext, useCompoundParent } from './useCompoundParent';
import { useCompoundItem } from './useCompoundItem';

type ItemValue = { value: string; ref: React.RefObject<HTMLSpanElement> };
type ItemValue = { value: string; ref: React.RefObject<HTMLSpanElement | null> };

describe('compound components', () => {
describe('useCompoundParent', () => {
Expand Down Expand Up @@ -188,7 +188,7 @@ describe('compound components', () => {
const { children } = props;
const { contextValue } = useCompoundParent<
string,
{ ref: React.RefObject<HTMLSpanElement> }
{ ref: React.RefObject<HTMLSpanElement | null> }
>();

return (
Expand Down Expand Up @@ -240,7 +240,7 @@ describe('compound components', () => {
const { children } = props;
const { contextValue } = useCompoundParent<
number,
{ ref: React.RefObject<HTMLLIElement> }
{ ref: React.RefObject<HTMLLIElement | null> }
>();

return (
Expand All @@ -256,7 +256,7 @@ describe('compound components', () => {

function Child() {
const ref = React.useRef<HTMLLIElement>(null);
const { id } = useCompoundItem<string, { ref: React.RefObject<HTMLLIElement> }>(
const { id } = useCompoundItem<string, { ref: React.RefObject<HTMLLIElement | null> }>(
idGenerator,
React.useMemo(() => ({ ref }), []),
);
Expand Down
9 changes: 6 additions & 3 deletions packages/mui-base/src/useCompound/useCompoundParent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ if (process.env.NODE_ENV !== 'production') {
CompoundComponentContext.displayName = 'CompoundComponentContext';
}

export interface UseCompoundParentReturnValue<Key, Subitem extends { ref: React.RefObject<Node> }> {
export interface UseCompoundParentReturnValue<
Key,
Subitem extends { ref: React.RefObject<Node | null> },
> {
/**
* The value for the CompoundComponentContext provider.
*/
Expand All @@ -63,7 +66,7 @@ export interface UseCompoundParentReturnValue<Key, Subitem extends { ref: React.
/**
* Sorts the subitems by their position in the DOM.
*/
function sortSubitems<Key, Subitem extends { ref: React.RefObject<Node> }>(
function sortSubitems<Key, Subitem extends { ref: React.RefObject<Node | null> }>(
subitems: Map<Key, Subitem>,
) {
const subitemsArray = Array.from(subitems.keys()).map((key) => {
Expand Down Expand Up @@ -100,7 +103,7 @@ function sortSubitems<Key, Subitem extends { ref: React.RefObject<Node> }>(
*/
export function useCompoundParent<
Key,
Subitem extends { ref: React.RefObject<Node> },
Subitem extends { ref: React.RefObject<Node | null> },
>(): UseCompoundParentReturnValue<Key, Subitem> {
const [subitems, setSubitems] = React.useState(new Map<Key, Subitem>());
const subitemKeys = React.useRef(new Set<Key>());
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-base/src/useMenu/menuReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ActionWithContext } from '../utils/useControllableReducer.types';
import { MenuInternalState } from './useMenu.types';

export type MenuActionContext = ListActionContext<string> & {
listboxRef: React.RefObject<HTMLElement>;
listboxRef: React.RefObject<HTMLElement | null>;
};

export function menuReducer(
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-base/src/useMenuItem/useMenuItem.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface MenuItemMetadata {
id: string;
disabled: boolean;
label?: string;
ref: React.RefObject<HTMLElement>;
ref: React.RefObject<HTMLElement | null>;
}

export type UseMenuItemRootSlotProps<ExternalProps = {}> = ExternalProps &
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-base/src/useOption/useOption.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export interface SelectOption<Value> {
value: Value;
label: React.ReactNode;
disabled?: boolean;
ref: React.RefObject<HTMLElement>;
ref: React.RefObject<HTMLElement | null>;
id?: string;
}

Expand Down
8 changes: 4 additions & 4 deletions packages/mui-base/src/useSlider/useSlider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ export function useSlider(parameters: UseSliderParameters): UseSliderReturnValue
value: valueProp,
} = parameters;

const touchId = React.useRef<number>();
const touchId = React.useRef<number | undefined>(undefined);
// We can't use the :active browser pseudo-classes.
// - The active state isn't triggered when clicking on the rail.
// - The active state isn't transferred when inversing a range slider.
Expand Down Expand Up @@ -267,7 +267,7 @@ export function useSlider(parameters: UseSliderParameters): UseSliderReturnValue

const [focusedThumbIndex, setFocusedThumbIndex] = React.useState(-1);

const sliderRef = React.useRef<HTMLSpanElement>();
const sliderRef = React.useRef<HTMLSpanElement | null>(null);
const handleRef = useForkRef(ref, sliderRef);

const createHandleHiddenInputFocus =
Expand Down Expand Up @@ -396,7 +396,7 @@ export function useSlider(parameters: UseSliderParameters): UseSliderReturnValue
changeValue(event, event.target.valueAsNumber);
};

const previousIndex = React.useRef<number>();
const previousIndex = React.useRef<number | undefined>(undefined);
let axis = orientation;
if (isRtl && orientation === 'horizontal') {
axis += '-reverse';
Expand Down Expand Up @@ -712,7 +712,7 @@ export function useSlider(parameters: UseSliderParameters): UseSliderReturnValue
type: 'range',
min: parameters.min,
max: parameters.max,
step: parameters.step === null && parameters.marks ? 'any' : parameters.step ?? undefined,
step: parameters.step === null && parameters.marks ? 'any' : (parameters.step ?? undefined),
disabled,
...externalProps,
...mergedEventHandlers,
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-base/src/useTabs/TabsProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { CompoundComponentContext, CompoundComponentContextValue } from '../useC

export type TabPanelMetadata = {
id: string | undefined;
ref: React.RefObject<HTMLElement>;
ref: React.RefObject<HTMLElement | null>;
};

export type TabsProviderValue = CompoundComponentContextValue<string | number, TabPanelMetadata> &
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-base/src/useTabs/useTabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { TabPanelMetadata } from './TabsProvider';
export interface TabMetadata {
disabled: boolean;
id: string | undefined;
ref: React.RefObject<HTMLElement>;
ref: React.RefObject<HTMLElement | null>;
}

type IdLookupFunction = (id: string | number) => string | undefined;
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-base/src/utils/useMessageBus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function createMessageBus(): MessageBus {
* @ignore - internal hook.
*/
export function useMessageBus() {
const bus = React.useRef<MessageBus>();
const bus = React.useRef<MessageBus | undefined>(undefined);
if (!bus.current) {
bus.current = createMessageBus();
}
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-base/test/describeConformanceUnstyled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ function testSlotPropsProp(
});
}

function testClassName(element: React.ReactElement, getOptions: () => ConformanceOptions) {
function testClassName(element: React.ReactElement<any>, getOptions: () => ConformanceOptions) {
it('applies the className to the root component', async () => {
const { render } = getOptions();

Expand Down
2 changes: 1 addition & 1 deletion packages/mui-docs/src/Ad/Ad.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export function Ad() {
const ad = React.useContext(AdContext);
const eventLabel = label ? `${label}-${ad.placement}-${adShape}` : null;

const timerAdblock = React.useRef<ReturnType<typeof setTimeout>>();
const timerAdblock = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined);

const checkAdblock = React.useCallback(
(attempt = 1) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-docs/src/CodeCopy/useClipboardCopy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import clipboardCopy from 'clipboard-copy';

export default function useClipboardCopy() {
const [isCopied, setIsCopied] = React.useState(false);
const timeout = React.useRef<ReturnType<typeof setTimeout>>();
const timeout = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined);

React.useEffect(
() => () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-joy/src/Autocomplete/Autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import useSlot from '../utils/useSlot';

type OwnerState = Omit<AutocompleteOwnerState<any, any, any, any>, 'onChange' | 'defaultValue'>;

const defaultIsActiveElementInListbox = (listboxRef: React.RefObject<HTMLElement>) =>
const defaultIsActiveElementInListbox = (listboxRef: React.RefObject<HTMLElement | null>) =>
listboxRef.current !== null && listboxRef.current.contains(document.activeElement);
// @ts-ignore
const defaultGetOptionLabel = (option) => option.label ?? option;
Expand Down
7 changes: 4 additions & 3 deletions packages/mui-joy/src/ButtonGroup/ButtonGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import ButtonGroupContext from './ButtonGroupContext';
import useSlot from '../utils/useSlot';
import buttonClasses from '../Button/buttonClasses';
import iconButtonClasses from '../IconButton/iconButtonClasses';
import { DividerProps } from '../Divider';

const useUtilityClasses = (ownerState: ButtonGroupOwnerState) => {
const { size, variant, color, orientation } = ownerState;
Expand Down Expand Up @@ -236,11 +237,11 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(inProps, ref) {
}
const extraProps: Record<string, any> = {};
if (isMuiElement(child, ['Divider'])) {
extraProps.inset = 'inset' in child.props ? child.props.inset : 'context';
const childProps = child.props as DividerProps;
extraProps.inset = childProps?.inset ?? 'context';

const dividerOrientation = orientation === 'vertical' ? 'horizontal' : 'vertical';
extraProps.orientation =
'orientation' in child.props ? child.props.orientation : dividerOrientation;
extraProps.orientation = childProps?.orientation ?? dividerOrientation;
extraProps.role = 'presentation';
extraProps.component = 'span';
}
Expand Down
Loading