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

[pickers] Fix disableOpenPicker prop behavior #13212

Merged
merged 6 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ function DesktopDateTimePickerLayout<
TView extends DateOrTimeViewWithMeridiem,
>(props: PickersLayoutProps<TValue, TDate, TView>) {
const { toolbar, tabs, content, actionBar, shortcuts } = usePickerLayout(props);
const { sx, className, isLandscape, ref } = props;
const { sx, className, isLandscape, ref, classes } = props;
const isActionBarVisible = actionBar && (actionBar.props.actions?.length ?? 0) > 0;

return (
<PickersLayoutRoot
ref={ref}
className={clsx(className, pickersLayoutClasses.root)}
className={clsx(className, pickersLayoutClasses.root, classes?.root)}
sx={[
{
[`& .${pickersLayoutClasses.tabs}`]: { gridRow: 4, gridColumn: '1 / 4' },
Expand All @@ -40,7 +40,7 @@ function DesktopDateTimePickerLayout<
{isLandscape ? shortcuts : toolbar}
{isLandscape ? toolbar : shortcuts}
<PickersLayoutContentWrapper
className={pickersLayoutClasses.contentWrapper}
className={clsx(pickersLayoutClasses.contentWrapper, classes?.contentWrapper)}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The addition of the test allowed me to discover this "bug"—the slotProps.layout.classes were not used in the case of DesktopDateTimePicker and DesktopDateTimeRangePicker. 🙈

sx={{ display: 'grid' }}
>
{content}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,15 @@ export const useDesktopPicker = <
fieldProps.InputProps = {
...fieldProps.InputProps,
ref: containerRef,
[`${inputAdornmentProps.position}Adornment`]: (
<InputAdornment {...inputAdornmentProps}>
<OpenPickerButton {...openPickerButtonProps}>
<OpenPickerIcon {...innerSlotProps?.openPickerIcon} />
</OpenPickerButton>
</InputAdornment>
),
...(!props.disableOpenPicker && {
[`${inputAdornmentProps.position}Adornment`]: (
<InputAdornment {...inputAdornmentProps}>
<OpenPickerButton {...openPickerButtonProps}>
<OpenPickerIcon {...innerSlotProps?.openPickerIcon} />
</OpenPickerButton>
</InputAdornment>
),
}),
} as typeof fieldProps.InputProps;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@ export interface UsePickerViewsProps<
TView extends DateOrTimeViewWithMeridiem,
TExternalProps extends UsePickerViewsProps<TValue, TDate, TView, any, any>,
TAdditionalProps extends {},
> extends UsePickerViewsBaseProps<TValue, TDate, TView, TExternalProps, TAdditionalProps>,
UsePickerViewsNonStaticProps {
> extends UsePickerViewsBaseProps<TValue, TDate, TView, TExternalProps, TAdditionalProps> {
className?: string;
sx?: SxProps<Theme>;
}
Expand Down Expand Up @@ -141,8 +140,7 @@ export interface UsePickerViewParams<

export interface UsePickerViewsResponse<TView extends DateOrTimeViewWithMeridiem> {
/**
* Does the picker have at least one view that should be rendered in UI mode ?
* If not, we can hide the icon to open the picker.
* Indicates if the the picker has at least one view that should be rendered in UI.
*/
hasUIView: boolean;
renderCurrentView: () => React.ReactNode;
Expand Down Expand Up @@ -185,7 +183,7 @@ export const usePickerViews = <
TAdditionalProps
>): UsePickerViewsResponse<TView> => {
const { onChange, open, onClose } = propsFromPickerValue;
const { views, openTo, onViewChange, disableOpenPicker, viewRenderers, timezone } = props;
const { views, openTo, onViewChange, viewRenderers, timezone } = props;
Copy link
Member

@flaviendelangle flaviendelangle May 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may be able to simplify the typing and get rid of UsePickerViewsNonStaticProps if disableOpenPicker is no longer used in this file, and instead have disableOpenPicker defined directly in UseDesktopPickerProps

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for noting it.
Did you mean this 4c3da18? 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly
From what I see, disableOpenPicker is defined in UsePickerViewsNonStaticProps
Which is weird now that this prop is never used in the usePickerViews hook.
If you move it to UseDesktopPickerProps, it would be removed from the mobile pickers (which make sense since it does nothing on them).

Or maybe I'm missing something, I did not dive deeper tbh

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Mobile, it currently doesn't change anything, but on range pickers, it prevents the picker from opening on click. 🤔
That's why I didn't move anything more than needed now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK
The current position of this prop's definition seems odd to me but we can move it later if we find a better interface to put it in.

const { className, sx, ...propsToForwardToView } = props;

const { view, setView, defaultView, focusedView, setFocusedView, setValueAndGoToNextView } =
Expand All @@ -203,9 +201,7 @@ export const usePickerViews = <
views.reduce(
(acc, viewForReduce) => {
let viewMode: 'field' | 'UI';
if (disableOpenPicker) {
viewMode = 'field';
} else if (viewRenderers[viewForReduce] != null) {
if (viewRenderers[viewForReduce] != null) {
viewMode = 'UI';
} else {
viewMode = 'field';
Expand All @@ -220,7 +216,7 @@ export const usePickerViews = <
},
{ hasUIView: false, viewModeLookup: {} as Record<TView, 'field' | 'UI'> },
),
[disableOpenPicker, viewRenderers, views],
[viewRenderers, views],
);

const timeViewsCount = React.useMemo(
Expand Down
30 changes: 29 additions & 1 deletion test/utils/pickers/describePicker/describePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ function innerDescribePicker(ElementToTest: React.ElementType, options: Describe
}
});

it.skip('should render toolbar when `hidden` is `false`', function test() {
it('should render toolbar when `hidden` is `false`', function test() {
if (hasNoView) {
this.skip();
}
Expand Down Expand Up @@ -178,6 +178,34 @@ function innerDescribePicker(ElementToTest: React.ElementType, options: Describe
expect(screen.queryByTestId('pickers-toolbar')).to.equal(null);
});
});

describe('prop: disableOpenPicker', () => {
it('should not render the open picker button, but still render the picker if its open', function test() {
if (variant === 'static') {
this.skip();
}

render(
<ElementToTest
disableOpenPicker
{...propsToOpen}
slotProps={{
layout: {
classes: {
contentWrapper: 'test-pickers-content-wrapper',
},
},
}}
/>,
);

expect(screen.queryByRole('button', { name: /Choose/ })).to.equal(null);
// check if anything has been rendered inside the layout content wrapper
expect(document.querySelector('.test-pickers-content-wrapper')?.hasChildNodes()).to.equal(
true,
);
});
});
}

/**
Expand Down
Loading