Skip to content

Commit

Permalink
[docs] New recipe of a read-only field (#14606)
Browse files Browse the repository at this point in the history
Signed-off-by: Flavien DELANGLE <flaviendelangle@gmail.com>
Co-authored-by: Lukas Tyla <llukas.tyla@gmail.com>
  • Loading branch information
flaviendelangle and LukasTy authored Oct 7, 2024
1 parent c2cff49 commit b1a8dd4
Show file tree
Hide file tree
Showing 26 changed files with 331 additions and 146 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import * as React from 'react';

import TextField from '@mui/material/TextField';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import { useValidation, validateDate } from '@mui/x-date-pickers/validation';
import {
useSplitFieldProps,
useParsedFormat,
usePickersContext,
} from '@mui/x-date-pickers/hooks';
import { CalendarIcon } from '@mui/x-date-pickers/icons';

function ReadOnlyDateField(props) {
const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date');
const { value, timezone, format } = internalProps;
const { InputProps, slotProps, slots, ...other } = forwardedProps;

const pickersContext = usePickersContext();

const parsedFormat = useParsedFormat(internalProps);
const { hasValidationError } = useValidation({
validator: validateDate,
value,
timezone,
props: internalProps,
});

const handleTogglePicker = (event) => {
if (pickersContext.open) {
pickersContext.onClose(event);
} else {
pickersContext.onOpen(event);
}
};

return (
<TextField
{...other}
value={value == null ? '' : value.format(format)}
placeholder={parsedFormat}
InputProps={{
...InputProps,
readOnly: true,
endAdornment: <CalendarIcon color="action" />,
sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } },
}}
error={hasValidationError}
onClick={handleTogglePicker}
/>
);
}

function ReadOnlyFieldDatePicker(props) {
return (
<DatePicker {...props} slots={{ ...props.slots, field: ReadOnlyDateField }} />
);
}

export default function ReadOnlyMaterialTextField() {
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<ReadOnlyFieldDatePicker />
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import * as React from 'react';
import { Dayjs } from 'dayjs';
import TextField from '@mui/material/TextField';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import {
DatePicker,
DatePickerProps,
DatePickerFieldProps,
} from '@mui/x-date-pickers/DatePicker';
import { useValidation, validateDate } from '@mui/x-date-pickers/validation';
import {
useSplitFieldProps,
useParsedFormat,
usePickersContext,
} from '@mui/x-date-pickers/hooks';
import { CalendarIcon } from '@mui/x-date-pickers/icons';

function ReadOnlyDateField(props: DatePickerFieldProps<Dayjs, false>) {
const { internalProps, forwardedProps } = useSplitFieldProps(props, 'date');
const { value, timezone, format } = internalProps;
const { InputProps, slotProps, slots, ...other } = forwardedProps;

const pickersContext = usePickersContext();

const parsedFormat = useParsedFormat(internalProps);
const { hasValidationError } = useValidation({
validator: validateDate,
value,
timezone,
props: internalProps,
});

const handleTogglePicker = (event: React.UIEvent) => {
if (pickersContext.open) {
pickersContext.onClose(event);
} else {
pickersContext.onOpen(event);
}
};

return (
<TextField
{...other}
value={value == null ? '' : value.format(format)}
placeholder={parsedFormat}
InputProps={{
...InputProps,
readOnly: true,
endAdornment: <CalendarIcon color="action" />,
sx: { cursor: 'pointer', '& *': { cursor: 'inherit' } },
}}
error={hasValidationError}
onClick={handleTogglePicker}
/>
);
}

function ReadOnlyFieldDatePicker(props: DatePickerProps<Dayjs>) {
return (
<DatePicker {...props} slots={{ ...props.slots, field: ReadOnlyDateField }} />
);
}

export default function ReadOnlyMaterialTextField() {
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<ReadOnlyFieldDatePicker />
</LocalizationProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<ReadOnlyFieldDatePicker />
11 changes: 9 additions & 2 deletions docs/data/date-pickers/custom-field/custom-field.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,17 @@ you can replace the field with an `Autocomplete` listing those dates:

{{"demo": "PickerWithAutocompleteField.js", "defaultCodeOpen": false}}

### Using a read-only `TextField`

If you want users to select a value exclusively through the views
but you still want the UI to look like a `TextField`, you can replace the field with a read-only `TextField`:

{{"demo": "custom-behavior/ReadOnlyMaterialTextField.js", "defaultCodeOpen": false}}

### Using a `Button`

If you only want to allow the user to pick a value through the views,
you can replace the field with a `Button`:
If you want users to select a value exclusively through the views
and you don't want the UI to look like a `TextField`, you can replace the field with a `Button`:

{{"demo": "PickerWithButtonField.js", "defaultCodeOpen": false}}

Expand Down
47 changes: 0 additions & 47 deletions docs/data/date-pickers/experimentation/CustomField.js

This file was deleted.

47 changes: 0 additions & 47 deletions docs/data/date-pickers/experimentation/CustomField.tsx

This file was deleted.

This file was deleted.

4 changes: 0 additions & 4 deletions docs/data/date-pickers/experimentation/experimentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,3 @@ productId: x-date-pickers
# Date and Time Pickers experimentation

<p class="description">Demos not accessible through the navbar of the doc</p>

## Custom field

{{"demo": "CustomField.js"}}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from 'react';
import useSlotProps from '@mui/utils/useSlotProps';
import { useLicenseVerifier } from '@mui/x-license';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { PickersLayout, PickersLayoutSlotProps } from '@mui/x-date-pickers/PickersLayout';
import {
executeInTheNextEventLoopTick,
Expand All @@ -11,6 +10,7 @@ import {
ExportedBaseToolbarProps,
DateOrTimeViewWithMeridiem,
ExportedBaseTabsProps,
PickersProvider,
} from '@mui/x-date-pickers/internals';
import { PickerValidDate, FieldRef, InferError } from '@mui/x-date-pickers/models';
import {
Expand Down Expand Up @@ -93,6 +93,7 @@ export const useDesktopRangePicker = <
renderCurrentView,
shouldRestoreFocus,
fieldProps: pickerFieldProps,
contextValue,
} = usePicker<
DateRange<TDate>,
TDate,
Expand Down Expand Up @@ -209,7 +210,7 @@ export const useDesktopRangePicker = <
const Layout = slots?.layout ?? PickersLayout;

const renderPicker = () => (
<LocalizationProvider localeText={localeText}>
<PickersProvider contextValue={contextValue} localeText={localeText}>
<Field {...enrichedFieldProps} />
<PickersPopper
role="tooltip"
Expand All @@ -233,7 +234,7 @@ export const useDesktopRangePicker = <
{renderCurrentView()}
</Layout>
</PickersPopper>
</LocalizationProvider>
</PickersProvider>
);

return {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import * as React from 'react';
import useSlotProps from '@mui/utils/useSlotProps';
import { useLicenseVerifier } from '@mui/x-license';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { PickersLayout, PickersLayoutSlotProps } from '@mui/x-date-pickers/PickersLayout';
import {
usePicker,
PickersModalDialog,
ExportedBaseToolbarProps,
DateOrTimeViewWithMeridiem,
ExportedBaseTabsProps,
PickersProvider,
} from '@mui/x-date-pickers/internals';
import { usePickersTranslations } from '@mui/x-date-pickers/hooks';
import { PickerValidDate, FieldRef, InferError } from '@mui/x-date-pickers/models';
Expand Down Expand Up @@ -88,6 +88,7 @@ export const useMobileRangePicker = <
layoutProps,
renderCurrentView,
fieldProps: pickerFieldProps,
contextValue,
} = usePicker<
DateRange<TDate>,
TDate,
Expand Down Expand Up @@ -214,7 +215,7 @@ export const useMobileRangePicker = <
};

const renderPicker = () => (
<LocalizationProvider localeText={localeText}>
<PickersProvider contextValue={contextValue} localeText={localeText}>
<Field {...enrichedFieldProps} />
<PickersModalDialog {...actions} open={open} slots={slots} slotProps={slotProps}>
<Layout
Expand All @@ -226,7 +227,7 @@ export const useMobileRangePicker = <
{renderCurrentView()}
</Layout>
</PickersModalDialog>
</LocalizationProvider>
</PickersProvider>
);

return {
Expand Down
4 changes: 4 additions & 0 deletions packages/x-date-pickers/src/hooks/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ export type {
export { usePickersTranslations } from './usePickersTranslations';

export { useSplitFieldProps } from './useSplitFieldProps';

export { useParsedFormat } from './useParsedFormat';

export { usePickersContext } from './usePickersContext';
Loading

0 comments on commit b1a8dd4

Please sign in to comment.