Added Statistics calculation
Statistics now show calculated values
This commit is contained in:
parent
fe87374e47
commit
fc0f69dacb
2147 changed files with 141321 additions and 39 deletions
24
node_modules/@mui/x-date-pickers/esm/internals/hooks/date-helpers-hooks.d.ts
generated
vendored
Normal file
24
node_modules/@mui/x-date-pickers/esm/internals/hooks/date-helpers-hooks.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { PickerOnChangeFn } from "./useViews.js";
|
||||
import { PickerSelectionState } from "./usePicker/index.js";
|
||||
import { PickersTimezone, PickerValidDate } from "../../models/index.js";
|
||||
export interface MonthValidationOptions {
|
||||
disablePast?: boolean;
|
||||
disableFuture?: boolean;
|
||||
minDate: PickerValidDate;
|
||||
maxDate: PickerValidDate;
|
||||
timezone: PickersTimezone;
|
||||
}
|
||||
export declare function useNextMonthDisabled(month: PickerValidDate, {
|
||||
disableFuture,
|
||||
maxDate,
|
||||
timezone
|
||||
}: Pick<MonthValidationOptions, 'disableFuture' | 'maxDate' | 'timezone'>): boolean;
|
||||
export declare function usePreviousMonthDisabled(month: PickerValidDate, {
|
||||
disablePast,
|
||||
minDate,
|
||||
timezone
|
||||
}: Pick<MonthValidationOptions, 'disablePast' | 'minDate' | 'timezone'>): boolean;
|
||||
export declare function useMeridiemMode(date: PickerValidDate | null, ampm: boolean | undefined, onChange: PickerOnChangeFn, selectionState?: PickerSelectionState): {
|
||||
meridiemMode: import("../utils/time-utils.js").Meridiem | null;
|
||||
handleMeridiemChange: (mode: "am" | "pm") => void;
|
||||
};
|
||||
40
node_modules/@mui/x-date-pickers/esm/internals/hooks/date-helpers-hooks.js
generated
vendored
Normal file
40
node_modules/@mui/x-date-pickers/esm/internals/hooks/date-helpers-hooks.js
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import * as React from 'react';
|
||||
import { getMeridiem, convertToMeridiem } from "../utils/time-utils.js";
|
||||
import { usePickerAdapter } from "../../hooks/usePickerAdapter.js";
|
||||
export function useNextMonthDisabled(month, {
|
||||
disableFuture,
|
||||
maxDate,
|
||||
timezone
|
||||
}) {
|
||||
const adapter = usePickerAdapter();
|
||||
return React.useMemo(() => {
|
||||
const now = adapter.date(undefined, timezone);
|
||||
const lastEnabledMonth = adapter.startOfMonth(disableFuture && adapter.isBefore(now, maxDate) ? now : maxDate);
|
||||
return !adapter.isAfter(lastEnabledMonth, month);
|
||||
}, [disableFuture, maxDate, month, adapter, timezone]);
|
||||
}
|
||||
export function usePreviousMonthDisabled(month, {
|
||||
disablePast,
|
||||
minDate,
|
||||
timezone
|
||||
}) {
|
||||
const adapter = usePickerAdapter();
|
||||
return React.useMemo(() => {
|
||||
const now = adapter.date(undefined, timezone);
|
||||
const firstEnabledMonth = adapter.startOfMonth(disablePast && adapter.isAfter(now, minDate) ? now : minDate);
|
||||
return !adapter.isBefore(firstEnabledMonth, month);
|
||||
}, [disablePast, minDate, month, adapter, timezone]);
|
||||
}
|
||||
export function useMeridiemMode(date, ampm, onChange, selectionState) {
|
||||
const adapter = usePickerAdapter();
|
||||
const cleanDate = React.useMemo(() => !adapter.isValid(date) ? null : date, [adapter, date]);
|
||||
const meridiemMode = getMeridiem(cleanDate, adapter);
|
||||
const handleMeridiemChange = React.useCallback(mode => {
|
||||
const timeWithMeridiem = cleanDate == null ? null : convertToMeridiem(cleanDate, mode, Boolean(ampm), adapter);
|
||||
onChange(timeWithMeridiem, selectionState ?? 'partial');
|
||||
}, [ampm, cleanDate, onChange, selectionState, adapter]);
|
||||
return {
|
||||
meridiemMode,
|
||||
handleMeridiemChange
|
||||
};
|
||||
}
|
||||
15
node_modules/@mui/x-date-pickers/esm/internals/hooks/useClockReferenceDate.d.ts
generated
vendored
Normal file
15
node_modules/@mui/x-date-pickers/esm/internals/hooks/useClockReferenceDate.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { MuiPickersAdapter, PickersTimezone, PickerValidDate } from "../../models/index.js";
|
||||
import { PickerValue } from "../models/index.js";
|
||||
export declare const useClockReferenceDate: <TProps extends {}>({
|
||||
value,
|
||||
referenceDate: referenceDateProp,
|
||||
adapter,
|
||||
props,
|
||||
timezone
|
||||
}: {
|
||||
value: PickerValue;
|
||||
referenceDate: PickerValidDate | undefined;
|
||||
adapter: MuiPickersAdapter;
|
||||
props: TProps;
|
||||
timezone: PickersTimezone;
|
||||
}) => PickerValidDate;
|
||||
25
node_modules/@mui/x-date-pickers/esm/internals/hooks/useClockReferenceDate.js
generated
vendored
Normal file
25
node_modules/@mui/x-date-pickers/esm/internals/hooks/useClockReferenceDate.js
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import * as React from 'react';
|
||||
import { singleItemValueManager } from "../utils/valueManagers.js";
|
||||
import { getTodayDate } from "../utils/date-utils.js";
|
||||
import { SECTION_TYPE_GRANULARITY } from "../utils/getDefaultReferenceDate.js";
|
||||
export const useClockReferenceDate = ({
|
||||
value,
|
||||
referenceDate: referenceDateProp,
|
||||
adapter,
|
||||
props,
|
||||
timezone
|
||||
}) => {
|
||||
const referenceDate = React.useMemo(() => singleItemValueManager.getInitialReferenceValue({
|
||||
value,
|
||||
adapter,
|
||||
props,
|
||||
referenceDate: referenceDateProp,
|
||||
granularity: SECTION_TYPE_GRANULARITY.day,
|
||||
timezone,
|
||||
getTodayDate: () => getTodayDate(adapter, timezone, 'date')
|
||||
}),
|
||||
// We want the `referenceDate` to update on prop and `timezone` change (https://github.com/mui/mui-x/issues/10804)
|
||||
[referenceDateProp, timezone] // eslint-disable-line react-hooks/exhaustive-deps
|
||||
);
|
||||
return value ?? referenceDate;
|
||||
};
|
||||
38
node_modules/@mui/x-date-pickers/esm/internals/hooks/useControlledValue.d.ts
generated
vendored
Normal file
38
node_modules/@mui/x-date-pickers/esm/internals/hooks/useControlledValue.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import type { PickerRangeValue, PickerValueManager } from "../models/index.js";
|
||||
import { PickersTimezone, PickerValidDate } from "../../models/index.js";
|
||||
import { PickerValidValue } from "../models/index.js";
|
||||
/**
|
||||
* Hooks controlling the value while making sure that:
|
||||
* - The value returned by `onChange` always have the timezone of `props.value` or `props.defaultValue` if defined
|
||||
* - The value rendered is always the one from `props.timezone` if defined
|
||||
*/
|
||||
export declare const useControlledValue: <TValue extends PickerValidValue, TChange extends (...params: any[]) => void>({
|
||||
name,
|
||||
timezone: timezoneProp,
|
||||
value: valueProp,
|
||||
defaultValue,
|
||||
referenceDate,
|
||||
onChange: onChangeProp,
|
||||
valueManager
|
||||
}: UseControlledValueWithTimezoneParameters<TValue, TChange>) => {
|
||||
value: TValue;
|
||||
handleValueChange: TChange;
|
||||
timezone: string;
|
||||
};
|
||||
interface UseValueWithTimezoneParameters<TValue extends PickerValidValue, TChange extends (...params: any[]) => void> {
|
||||
timezone: PickersTimezone | undefined;
|
||||
value: TValue | undefined;
|
||||
defaultValue: TValue | undefined;
|
||||
/**
|
||||
* The reference date as passed to `props.referenceDate`.
|
||||
* It does not need to have its default value.
|
||||
* This is only used to determine the timezone to use when `props.value` and `props.defaultValue` are not defined.
|
||||
*/
|
||||
referenceDate?: TValue extends PickerRangeValue ? TValue | PickerValidDate : PickerValidDate;
|
||||
onChange: TChange | undefined;
|
||||
valueManager: PickerValueManager<TValue, any>;
|
||||
}
|
||||
interface UseControlledValueWithTimezoneParameters<TValue extends PickerValidValue, TChange extends (...params: any[]) => void> extends UseValueWithTimezoneParameters<TValue, TChange> {
|
||||
name: string;
|
||||
}
|
||||
export {};
|
||||
57
node_modules/@mui/x-date-pickers/esm/internals/hooks/useControlledValue.js
generated
vendored
Normal file
57
node_modules/@mui/x-date-pickers/esm/internals/hooks/useControlledValue.js
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import * as React from 'react';
|
||||
import useEventCallback from '@mui/utils/useEventCallback';
|
||||
import useControlled from '@mui/utils/useControlled';
|
||||
import { usePickerAdapter } from "../../hooks/usePickerAdapter.js";
|
||||
|
||||
/**
|
||||
* Hooks controlling the value while making sure that:
|
||||
* - The value returned by `onChange` always have the timezone of `props.value` or `props.defaultValue` if defined
|
||||
* - The value rendered is always the one from `props.timezone` if defined
|
||||
*/
|
||||
export const useControlledValue = ({
|
||||
name,
|
||||
timezone: timezoneProp,
|
||||
value: valueProp,
|
||||
defaultValue,
|
||||
referenceDate,
|
||||
onChange: onChangeProp,
|
||||
valueManager
|
||||
}) => {
|
||||
const adapter = usePickerAdapter();
|
||||
const [valueWithInputTimezone, setValue] = useControlled({
|
||||
name,
|
||||
state: 'value',
|
||||
controlled: valueProp,
|
||||
default: defaultValue ?? valueManager.emptyValue
|
||||
});
|
||||
const inputTimezone = React.useMemo(() => valueManager.getTimezone(adapter, valueWithInputTimezone), [adapter, valueManager, valueWithInputTimezone]);
|
||||
const setInputTimezone = useEventCallback(newValue => {
|
||||
if (inputTimezone == null) {
|
||||
return newValue;
|
||||
}
|
||||
return valueManager.setTimezone(adapter, inputTimezone, newValue);
|
||||
});
|
||||
const timezoneToRender = React.useMemo(() => {
|
||||
if (timezoneProp) {
|
||||
return timezoneProp;
|
||||
}
|
||||
if (inputTimezone) {
|
||||
return inputTimezone;
|
||||
}
|
||||
if (referenceDate) {
|
||||
return adapter.getTimezone(Array.isArray(referenceDate) ? referenceDate[0] : referenceDate);
|
||||
}
|
||||
return 'default';
|
||||
}, [timezoneProp, inputTimezone, referenceDate, adapter]);
|
||||
const valueWithTimezoneToRender = React.useMemo(() => valueManager.setTimezone(adapter, timezoneToRender, valueWithInputTimezone), [valueManager, adapter, timezoneToRender, valueWithInputTimezone]);
|
||||
const handleValueChange = useEventCallback((newValue, ...otherParams) => {
|
||||
const newValueWithInputTimezone = setInputTimezone(newValue);
|
||||
setValue(newValueWithInputTimezone);
|
||||
onChangeProp?.(newValueWithInputTimezone, ...otherParams);
|
||||
});
|
||||
return {
|
||||
value: valueWithTimezoneToRender,
|
||||
handleValueChange,
|
||||
timezone: timezoneToRender
|
||||
};
|
||||
};
|
||||
2
node_modules/@mui/x-date-pickers/esm/internals/hooks/useDesktopPicker/index.d.ts
generated
vendored
Normal file
2
node_modules/@mui/x-date-pickers/esm/internals/hooks/useDesktopPicker/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export { useDesktopPicker } from "./useDesktopPicker.js";
|
||||
export type { UseDesktopPickerSlots, UseDesktopPickerSlotProps, ExportedUseDesktopPickerSlotProps, DesktopOnlyPickerProps, UseDesktopPickerProps } from "./useDesktopPicker.types.js";
|
||||
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/useDesktopPicker/index.js
generated
vendored
Normal file
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/useDesktopPicker/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { useDesktopPicker } from "./useDesktopPicker.js";
|
||||
16
node_modules/@mui/x-date-pickers/esm/internals/hooks/useDesktopPicker/useDesktopPicker.d.ts
generated
vendored
Normal file
16
node_modules/@mui/x-date-pickers/esm/internals/hooks/useDesktopPicker/useDesktopPicker.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import * as React from 'react';
|
||||
import { UseDesktopPickerParams, UseDesktopPickerProps } from "./useDesktopPicker.types.js";
|
||||
import { DateOrTimeViewWithMeridiem } from "../../models/index.js";
|
||||
/**
|
||||
* Hook managing all the single-date desktop pickers:
|
||||
* - DesktopDatePicker
|
||||
* - DesktopDateTimePicker
|
||||
* - DesktopTimePicker
|
||||
*/
|
||||
export declare const useDesktopPicker: <TView extends DateOrTimeViewWithMeridiem, TEnableAccessibleFieldDOMStructure extends boolean, TExternalProps extends UseDesktopPickerProps<TView, TEnableAccessibleFieldDOMStructure, any, TExternalProps>>({
|
||||
props,
|
||||
steps,
|
||||
...pickerParams
|
||||
}: UseDesktopPickerParams<TView, TEnableAccessibleFieldDOMStructure, TExternalProps>) => {
|
||||
renderPicker: () => React.JSX.Element;
|
||||
};
|
||||
98
node_modules/@mui/x-date-pickers/esm/internals/hooks/useDesktopPicker/useDesktopPicker.js
generated
vendored
Normal file
98
node_modules/@mui/x-date-pickers/esm/internals/hooks/useDesktopPicker/useDesktopPicker.js
generated
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
import _extends from "@babel/runtime/helpers/esm/extends";
|
||||
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
||||
const _excluded = ["props", "steps"],
|
||||
_excluded2 = ["ownerState"];
|
||||
import * as React from 'react';
|
||||
import useSlotProps from '@mui/utils/useSlotProps';
|
||||
import { PickerPopper } from "../../components/PickerPopper/PickerPopper.js";
|
||||
import { usePicker } from "../usePicker/index.js";
|
||||
import { PickersLayout } from "../../../PickersLayout/index.js";
|
||||
import { PickerProvider } from "../../components/PickerProvider.js";
|
||||
import { PickerFieldUIContextProvider } from "../../components/PickerFieldUI.js";
|
||||
import { createNonRangePickerStepNavigation } from "../../utils/createNonRangePickerStepNavigation.js";
|
||||
|
||||
/**
|
||||
* Hook managing all the single-date desktop pickers:
|
||||
* - DesktopDatePicker
|
||||
* - DesktopDateTimePicker
|
||||
* - DesktopTimePicker
|
||||
*/
|
||||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
export const useDesktopPicker = _ref => {
|
||||
let {
|
||||
props,
|
||||
steps
|
||||
} = _ref,
|
||||
pickerParams = _objectWithoutPropertiesLoose(_ref, _excluded);
|
||||
const {
|
||||
slots,
|
||||
slotProps: innerSlotProps,
|
||||
label,
|
||||
inputRef,
|
||||
localeText
|
||||
} = props;
|
||||
const getStepNavigation = createNonRangePickerStepNavigation({
|
||||
steps
|
||||
});
|
||||
const {
|
||||
providerProps,
|
||||
renderCurrentView,
|
||||
ownerState
|
||||
} = usePicker(_extends({}, pickerParams, {
|
||||
props,
|
||||
localeText,
|
||||
autoFocusView: true,
|
||||
viewContainerRole: 'dialog',
|
||||
variant: 'desktop',
|
||||
getStepNavigation
|
||||
}));
|
||||
const labelId = providerProps.privateContextValue.labelId;
|
||||
const isToolbarHidden = innerSlotProps?.toolbar?.hidden ?? false;
|
||||
const Field = slots.field;
|
||||
const _useSlotProps = useSlotProps({
|
||||
elementType: Field,
|
||||
externalSlotProps: innerSlotProps?.field,
|
||||
additionalProps: _extends({}, isToolbarHidden && {
|
||||
id: labelId
|
||||
}),
|
||||
ownerState
|
||||
}),
|
||||
fieldProps = _objectWithoutPropertiesLoose(_useSlotProps, _excluded2);
|
||||
const Layout = slots.layout ?? PickersLayout;
|
||||
let labelledById = labelId;
|
||||
if (isToolbarHidden) {
|
||||
if (label) {
|
||||
labelledById = `${labelId}-label`;
|
||||
} else {
|
||||
labelledById = undefined;
|
||||
}
|
||||
}
|
||||
const slotProps = _extends({}, innerSlotProps, {
|
||||
toolbar: _extends({}, innerSlotProps?.toolbar, {
|
||||
titleId: labelId
|
||||
}),
|
||||
popper: _extends({
|
||||
'aria-labelledby': labelledById
|
||||
}, innerSlotProps?.popper)
|
||||
});
|
||||
const renderPicker = () => /*#__PURE__*/_jsx(PickerProvider, _extends({}, providerProps, {
|
||||
children: /*#__PURE__*/_jsxs(PickerFieldUIContextProvider, {
|
||||
slots: slots,
|
||||
slotProps: slotProps,
|
||||
inputRef: inputRef,
|
||||
children: [/*#__PURE__*/_jsx(Field, _extends({}, fieldProps)), /*#__PURE__*/_jsx(PickerPopper, {
|
||||
slots: slots,
|
||||
slotProps: slotProps,
|
||||
children: /*#__PURE__*/_jsx(Layout, _extends({}, slotProps?.layout, {
|
||||
slots: slots,
|
||||
slotProps: slotProps,
|
||||
children: renderCurrentView()
|
||||
}))
|
||||
})]
|
||||
})
|
||||
}));
|
||||
if (process.env.NODE_ENV !== "production") renderPicker.displayName = "renderPicker";
|
||||
return {
|
||||
renderPicker
|
||||
};
|
||||
};
|
||||
48
node_modules/@mui/x-date-pickers/esm/internals/hooks/useDesktopPicker/useDesktopPicker.types.d.ts
generated
vendored
Normal file
48
node_modules/@mui/x-date-pickers/esm/internals/hooks/useDesktopPicker/useDesktopPicker.types.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import * as React from 'react';
|
||||
import { MakeRequired, SlotComponentPropsFromProps } from '@mui/x-internals/types';
|
||||
import { BasePickerProps } from "../../models/props/basePickerProps.js";
|
||||
import { PickerPopperSlots, PickerPopperSlotProps } from "../../components/PickerPopper/PickerPopper.js";
|
||||
import { UsePickerParameters, UsePickerNonStaticProps, UsePickerProps } from "../usePicker/index.js";
|
||||
import { PickerFieldSlotProps, PickerOwnerState } from "../../../models/index.js";
|
||||
import { ExportedPickersLayoutSlots, ExportedPickersLayoutSlotProps, PickersLayoutSlotProps } from "../../../PickersLayout/PickersLayout.types.js";
|
||||
import { DateOrTimeViewWithMeridiem, PickerValue } from "../../models/index.js";
|
||||
import { PickerFieldUISlotsFromContext, PickerFieldUISlotPropsFromContext } from "../../components/PickerFieldUI.js";
|
||||
import { PickerStep } from "../../utils/createNonRangePickerStepNavigation.js";
|
||||
export interface UseDesktopPickerSlots extends Pick<PickerPopperSlots, 'desktopPaper' | 'desktopTransition' | 'desktopTrapFocus' | 'popper'>, ExportedPickersLayoutSlots<PickerValue>, PickerFieldUISlotsFromContext {
|
||||
/**
|
||||
* Component used to enter the date with the keyboard.
|
||||
*/
|
||||
field: React.ElementType;
|
||||
}
|
||||
export interface ExportedUseDesktopPickerSlotProps<TEnableAccessibleFieldDOMStructure extends boolean> extends PickerPopperSlotProps, ExportedPickersLayoutSlotProps<PickerValue>, PickerFieldUISlotPropsFromContext {
|
||||
field?: SlotComponentPropsFromProps<PickerFieldSlotProps<PickerValue, TEnableAccessibleFieldDOMStructure>, {}, PickerOwnerState>;
|
||||
}
|
||||
export interface UseDesktopPickerSlotProps<TEnableAccessibleFieldDOMStructure extends boolean> extends ExportedUseDesktopPickerSlotProps<TEnableAccessibleFieldDOMStructure>, Pick<PickersLayoutSlotProps<PickerValue>, 'toolbar'> {}
|
||||
export interface DesktopOnlyPickerProps extends UsePickerNonStaticProps {
|
||||
/**
|
||||
* If `true`, the `input` element is focused during the first mount.
|
||||
* @default false
|
||||
*/
|
||||
autoFocus?: boolean;
|
||||
}
|
||||
export interface UseDesktopPickerProps<TView extends DateOrTimeViewWithMeridiem, TEnableAccessibleFieldDOMStructure extends boolean, TError, TExternalProps extends UsePickerProps<PickerValue, TView, TError, any>> extends BasePickerProps<PickerValue, any, TError, TExternalProps>, MakeRequired<DesktopOnlyPickerProps, 'format'> {
|
||||
/**
|
||||
* Overridable component slots.
|
||||
* @default {}
|
||||
*/
|
||||
slots: UseDesktopPickerSlots;
|
||||
/**
|
||||
* The props used for each component slot.
|
||||
* @default {}
|
||||
*/
|
||||
slotProps?: UseDesktopPickerSlotProps<TEnableAccessibleFieldDOMStructure>;
|
||||
}
|
||||
export interface UseDesktopPickerParams<TView extends DateOrTimeViewWithMeridiem, TEnableAccessibleFieldDOMStructure extends boolean, TExternalProps extends UseDesktopPickerProps<TView, TEnableAccessibleFieldDOMStructure, any, TExternalProps>> extends Pick<UsePickerParameters<PickerValue, TView, TExternalProps>, 'valueManager' | 'valueType' | 'validator' | 'rendererInterceptor' | 'ref'> {
|
||||
props: TExternalProps;
|
||||
/**
|
||||
* Steps available for the picker.
|
||||
* This will be used to define the behavior of navigation actions.
|
||||
* If null, the picker will not have any step navigation.
|
||||
*/
|
||||
steps: PickerStep[] | null;
|
||||
}
|
||||
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/useDesktopPicker/useDesktopPicker.types.js
generated
vendored
Normal file
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/useDesktopPicker/useDesktopPicker.types.js
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
export {};
|
||||
15
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/buildSectionsFromFormat.d.ts
generated
vendored
Normal file
15
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/buildSectionsFromFormat.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { FieldSection, MuiPickersAdapter, PickerValidDate } from "../../../models/index.js";
|
||||
import { PickersLocaleText } from "../../../locales/index.js";
|
||||
interface BuildSectionsFromFormatParameters {
|
||||
adapter: MuiPickersAdapter;
|
||||
format: string;
|
||||
formatDensity: 'dense' | 'spacious';
|
||||
isRtl: boolean;
|
||||
shouldRespectLeadingZeros: boolean;
|
||||
localeText: PickersLocaleText;
|
||||
localizedDigits: string[];
|
||||
date: PickerValidDate | null;
|
||||
enableAccessibleFieldDOMStructure: boolean;
|
||||
}
|
||||
export declare const buildSectionsFromFormat: (parameters: BuildSectionsFromFormatParameters) => FieldSection[];
|
||||
export {};
|
||||
255
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/buildSectionsFromFormat.js
generated
vendored
Normal file
255
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/buildSectionsFromFormat.js
generated
vendored
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
import _extends from "@babel/runtime/helpers/esm/extends";
|
||||
import { applyLocalizedDigits, cleanLeadingZeros, doesSectionFormatHaveLeadingZeros, getDateSectionConfigFromFormatToken, removeLocalizedDigits } from "./useField.utils.js";
|
||||
const expandFormat = ({
|
||||
adapter,
|
||||
format
|
||||
}) => {
|
||||
// Expand the provided format
|
||||
let formatExpansionOverflow = 10;
|
||||
let prevFormat = format;
|
||||
let nextFormat = adapter.expandFormat(format);
|
||||
while (nextFormat !== prevFormat) {
|
||||
prevFormat = nextFormat;
|
||||
nextFormat = adapter.expandFormat(prevFormat);
|
||||
formatExpansionOverflow -= 1;
|
||||
if (formatExpansionOverflow < 0) {
|
||||
throw new Error('MUI X: The format expansion seems to be in an infinite loop. Please open an issue with the format passed to the component.');
|
||||
}
|
||||
}
|
||||
return nextFormat;
|
||||
};
|
||||
const getEscapedPartsFromFormat = ({
|
||||
adapter,
|
||||
expandedFormat
|
||||
}) => {
|
||||
const escapedParts = [];
|
||||
const {
|
||||
start: startChar,
|
||||
end: endChar
|
||||
} = adapter.escapedCharacters;
|
||||
const regExp = new RegExp(`(\\${startChar}[^\\${endChar}]*\\${endChar})+`, 'g');
|
||||
let match = null;
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
while (match = regExp.exec(expandedFormat)) {
|
||||
escapedParts.push({
|
||||
start: match.index,
|
||||
end: regExp.lastIndex - 1
|
||||
});
|
||||
}
|
||||
return escapedParts;
|
||||
};
|
||||
const getSectionPlaceholder = (adapter, localeText, sectionConfig, sectionFormat) => {
|
||||
switch (sectionConfig.type) {
|
||||
case 'year':
|
||||
{
|
||||
return localeText.fieldYearPlaceholder({
|
||||
digitAmount: adapter.formatByString(adapter.date(undefined, 'default'), sectionFormat).length,
|
||||
format: sectionFormat
|
||||
});
|
||||
}
|
||||
case 'month':
|
||||
{
|
||||
return localeText.fieldMonthPlaceholder({
|
||||
contentType: sectionConfig.contentType,
|
||||
format: sectionFormat
|
||||
});
|
||||
}
|
||||
case 'day':
|
||||
{
|
||||
return localeText.fieldDayPlaceholder({
|
||||
format: sectionFormat
|
||||
});
|
||||
}
|
||||
case 'weekDay':
|
||||
{
|
||||
return localeText.fieldWeekDayPlaceholder({
|
||||
contentType: sectionConfig.contentType,
|
||||
format: sectionFormat
|
||||
});
|
||||
}
|
||||
case 'hours':
|
||||
{
|
||||
return localeText.fieldHoursPlaceholder({
|
||||
format: sectionFormat
|
||||
});
|
||||
}
|
||||
case 'minutes':
|
||||
{
|
||||
return localeText.fieldMinutesPlaceholder({
|
||||
format: sectionFormat
|
||||
});
|
||||
}
|
||||
case 'seconds':
|
||||
{
|
||||
return localeText.fieldSecondsPlaceholder({
|
||||
format: sectionFormat
|
||||
});
|
||||
}
|
||||
case 'meridiem':
|
||||
{
|
||||
return localeText.fieldMeridiemPlaceholder({
|
||||
format: sectionFormat
|
||||
});
|
||||
}
|
||||
default:
|
||||
{
|
||||
return sectionFormat;
|
||||
}
|
||||
}
|
||||
};
|
||||
const createSection = ({
|
||||
adapter,
|
||||
date,
|
||||
shouldRespectLeadingZeros,
|
||||
localeText,
|
||||
localizedDigits,
|
||||
now,
|
||||
token,
|
||||
startSeparator
|
||||
}) => {
|
||||
if (token === '') {
|
||||
throw new Error('MUI X: Should not call `commitToken` with an empty token');
|
||||
}
|
||||
const sectionConfig = getDateSectionConfigFromFormatToken(adapter, token);
|
||||
const hasLeadingZerosInFormat = doesSectionFormatHaveLeadingZeros(adapter, sectionConfig.contentType, sectionConfig.type, token);
|
||||
const hasLeadingZerosInInput = shouldRespectLeadingZeros ? hasLeadingZerosInFormat : sectionConfig.contentType === 'digit';
|
||||
const isValidDate = adapter.isValid(date);
|
||||
let sectionValue = isValidDate ? adapter.formatByString(date, token) : '';
|
||||
let maxLength = null;
|
||||
if (hasLeadingZerosInInput) {
|
||||
if (hasLeadingZerosInFormat) {
|
||||
maxLength = sectionValue === '' ? adapter.formatByString(now, token).length : sectionValue.length;
|
||||
} else {
|
||||
if (sectionConfig.maxLength == null) {
|
||||
throw new Error(`MUI X: The token ${token} should have a 'maxLength' property on it's adapter`);
|
||||
}
|
||||
maxLength = sectionConfig.maxLength;
|
||||
if (isValidDate) {
|
||||
sectionValue = applyLocalizedDigits(cleanLeadingZeros(removeLocalizedDigits(sectionValue, localizedDigits), maxLength), localizedDigits);
|
||||
}
|
||||
}
|
||||
}
|
||||
return _extends({}, sectionConfig, {
|
||||
format: token,
|
||||
maxLength,
|
||||
value: sectionValue,
|
||||
placeholder: getSectionPlaceholder(adapter, localeText, sectionConfig, token),
|
||||
hasLeadingZerosInFormat,
|
||||
hasLeadingZerosInInput,
|
||||
startSeparator,
|
||||
endSeparator: '',
|
||||
modified: false
|
||||
});
|
||||
};
|
||||
const buildSections = parameters => {
|
||||
const {
|
||||
adapter,
|
||||
expandedFormat,
|
||||
escapedParts
|
||||
} = parameters;
|
||||
const now = adapter.date(undefined);
|
||||
const sections = [];
|
||||
let startSeparator = '';
|
||||
|
||||
// This RegExp tests if the beginning of a string corresponds to a supported token
|
||||
const validTokens = Object.keys(adapter.formatTokenMap).sort((a, b) => b.length - a.length); // Sort to put longest word first
|
||||
|
||||
const regExpFirstWordInFormat = /^([a-zA-Z]+)/;
|
||||
const regExpWordOnlyComposedOfTokens = new RegExp(`^(${validTokens.join('|')})*$`);
|
||||
const regExpFirstTokenInWord = new RegExp(`^(${validTokens.join('|')})`);
|
||||
const getEscapedPartOfCurrentChar = i => escapedParts.find(escapeIndex => escapeIndex.start <= i && escapeIndex.end >= i);
|
||||
let i = 0;
|
||||
while (i < expandedFormat.length) {
|
||||
const escapedPartOfCurrentChar = getEscapedPartOfCurrentChar(i);
|
||||
const isEscapedChar = escapedPartOfCurrentChar != null;
|
||||
const firstWordInFormat = regExpFirstWordInFormat.exec(expandedFormat.slice(i))?.[1];
|
||||
|
||||
// The first word in the format is only composed of tokens.
|
||||
// We extract those tokens to create a new sections.
|
||||
if (!isEscapedChar && firstWordInFormat != null && regExpWordOnlyComposedOfTokens.test(firstWordInFormat)) {
|
||||
let word = firstWordInFormat;
|
||||
while (word.length > 0) {
|
||||
const firstWord = regExpFirstTokenInWord.exec(word)[1];
|
||||
word = word.slice(firstWord.length);
|
||||
sections.push(createSection(_extends({}, parameters, {
|
||||
now,
|
||||
token: firstWord,
|
||||
startSeparator
|
||||
})));
|
||||
startSeparator = '';
|
||||
}
|
||||
i += firstWordInFormat.length;
|
||||
}
|
||||
// The remaining format does not start with a token,
|
||||
// We take the first character and add it to the current section's end separator.
|
||||
else {
|
||||
const char = expandedFormat[i];
|
||||
|
||||
// If we are on the opening or closing character of an escaped part of the format,
|
||||
// Then we ignore this character.
|
||||
const isEscapeBoundary = isEscapedChar && escapedPartOfCurrentChar?.start === i || escapedPartOfCurrentChar?.end === i;
|
||||
if (!isEscapeBoundary) {
|
||||
if (sections.length === 0) {
|
||||
startSeparator += char;
|
||||
} else {
|
||||
sections[sections.length - 1].endSeparator += char;
|
||||
sections[sections.length - 1].isEndFormatSeparator = true;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
if (sections.length === 0 && startSeparator.length > 0) {
|
||||
sections.push({
|
||||
type: 'empty',
|
||||
contentType: 'letter',
|
||||
maxLength: null,
|
||||
format: '',
|
||||
value: '',
|
||||
placeholder: '',
|
||||
hasLeadingZerosInFormat: false,
|
||||
hasLeadingZerosInInput: false,
|
||||
startSeparator,
|
||||
endSeparator: '',
|
||||
modified: false
|
||||
});
|
||||
}
|
||||
return sections;
|
||||
};
|
||||
const postProcessSections = ({
|
||||
isRtl,
|
||||
formatDensity,
|
||||
sections
|
||||
}) => {
|
||||
return sections.map(section => {
|
||||
const cleanSeparator = separator => {
|
||||
let cleanedSeparator = separator;
|
||||
if (isRtl && cleanedSeparator !== null && cleanedSeparator.includes(' ')) {
|
||||
cleanedSeparator = `\u2069${cleanedSeparator}\u2066`;
|
||||
}
|
||||
if (formatDensity === 'spacious' && ['/', '.', '-'].includes(cleanedSeparator)) {
|
||||
cleanedSeparator = ` ${cleanedSeparator} `;
|
||||
}
|
||||
return cleanedSeparator;
|
||||
};
|
||||
section.startSeparator = cleanSeparator(section.startSeparator);
|
||||
section.endSeparator = cleanSeparator(section.endSeparator);
|
||||
return section;
|
||||
});
|
||||
};
|
||||
export const buildSectionsFromFormat = parameters => {
|
||||
let expandedFormat = expandFormat(parameters);
|
||||
if (parameters.isRtl && parameters.enableAccessibleFieldDOMStructure) {
|
||||
expandedFormat = expandedFormat.split(' ').reverse().join(' ');
|
||||
}
|
||||
const escapedParts = getEscapedPartsFromFormat(_extends({}, parameters, {
|
||||
expandedFormat
|
||||
}));
|
||||
const sections = buildSections(_extends({}, parameters, {
|
||||
expandedFormat,
|
||||
escapedParts
|
||||
}));
|
||||
return postProcessSections(_extends({}, parameters, {
|
||||
sections
|
||||
}));
|
||||
};
|
||||
4
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/index.d.ts
generated
vendored
Normal file
4
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export { useField } from "./useField.js";
|
||||
export type { UseFieldInternalProps, UseFieldParameters, UseFieldReturnValue, UseFieldProps, FieldValueManager, FieldChangeHandler, FieldChangeHandlerContext } from "./useField.types.js";
|
||||
export { createDateStrForV7HiddenInputFromSections, createDateStrForV6InputFromSections } from "./useField.utils.js";
|
||||
export { useFieldInternalPropsWithDefaults } from "./useFieldInternalPropsWithDefaults.js";
|
||||
3
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/index.js
generated
vendored
Normal file
3
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export { useField } from "./useField.js";
|
||||
export { createDateStrForV7HiddenInputFromSections, createDateStrForV6InputFromSections } from "./useField.utils.js";
|
||||
export { useFieldInternalPropsWithDefaults } from "./useFieldInternalPropsWithDefaults.js";
|
||||
9
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/syncSelectionToDOM.d.ts
generated
vendored
Normal file
9
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/syncSelectionToDOM.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { PickerValidValue } from "../../models/index.js";
|
||||
import { UseFieldDOMGetters } from "./useField.types.js";
|
||||
import { UseFieldStateReturnValue } from "./useFieldState.js";
|
||||
export declare function syncSelectionToDOM<TValue extends PickerValidValue>(parameters: SyncSelectionToDOMParameters<TValue>): void;
|
||||
export interface SyncSelectionToDOMParameters<TValue extends PickerValidValue> {
|
||||
domGetters: UseFieldDOMGetters;
|
||||
stateResponse: UseFieldStateReturnValue<TValue>;
|
||||
focused: boolean;
|
||||
}
|
||||
53
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/syncSelectionToDOM.js
generated
vendored
Normal file
53
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/syncSelectionToDOM.js
generated
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import ownerDocument from '@mui/utils/ownerDocument';
|
||||
import { getActiveElement } from "../../utils/utils.js";
|
||||
export function syncSelectionToDOM(parameters) {
|
||||
const {
|
||||
focused,
|
||||
domGetters,
|
||||
stateResponse: {
|
||||
// States and derived states
|
||||
parsedSelectedSections,
|
||||
state
|
||||
}
|
||||
} = parameters;
|
||||
if (!domGetters.isReady()) {
|
||||
return;
|
||||
}
|
||||
const selection = ownerDocument(domGetters.getRoot()).getSelection();
|
||||
if (!selection) {
|
||||
return;
|
||||
}
|
||||
if (parsedSelectedSections == null) {
|
||||
// If the selection contains an element inside the field, we reset it.
|
||||
if (selection.rangeCount > 0 &&
|
||||
// Firefox can return a Restricted object here
|
||||
selection.getRangeAt(0).startContainer instanceof Node && domGetters.getRoot().contains(selection.getRangeAt(0).startContainer)) {
|
||||
selection.removeAllRanges();
|
||||
}
|
||||
if (focused) {
|
||||
domGetters.getRoot().blur();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// On multi input range pickers we want to update selection range only for the active input
|
||||
if (!domGetters.getRoot().contains(getActiveElement(domGetters.getRoot()))) {
|
||||
return;
|
||||
}
|
||||
const range = new window.Range();
|
||||
let target;
|
||||
if (parsedSelectedSections === 'all') {
|
||||
target = domGetters.getRoot();
|
||||
} else {
|
||||
const section = state.sections[parsedSelectedSections];
|
||||
if (section.type === 'empty') {
|
||||
target = domGetters.getSectionContainer(parsedSelectedSections);
|
||||
} else {
|
||||
target = domGetters.getSectionContent(parsedSelectedSections);
|
||||
}
|
||||
}
|
||||
range.selectNodeContents(target);
|
||||
target.focus();
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
3
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useField.d.ts
generated
vendored
Normal file
3
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useField.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import { UseFieldParameters, UseFieldReturnValue, UseFieldProps } from "./useField.types.js";
|
||||
import { PickerValidValue } from "../../models/index.js";
|
||||
export declare const useField: <TValue extends PickerValidValue, TEnableAccessibleFieldDOMStructure extends boolean, TError, TValidationProps extends {}, TProps extends UseFieldProps<TEnableAccessibleFieldDOMStructure>>(parameters: UseFieldParameters<TValue, TEnableAccessibleFieldDOMStructure, TError, TValidationProps, TProps>) => UseFieldReturnValue<TEnableAccessibleFieldDOMStructure, TProps>;
|
||||
9
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useField.js
generated
vendored
Normal file
9
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useField.js
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { useFieldV7TextField } from "./useFieldV7TextField.js";
|
||||
import { useFieldV6TextField } from "./useFieldV6TextField.js";
|
||||
import { useNullableFieldPrivateContext } from "../useNullableFieldPrivateContext.js";
|
||||
export const useField = parameters => {
|
||||
const fieldPrivateContext = useNullableFieldPrivateContext();
|
||||
const enableAccessibleFieldDOMStructure = parameters.props.enableAccessibleFieldDOMStructure ?? fieldPrivateContext?.enableAccessibleFieldDOMStructure ?? true;
|
||||
const useFieldTextField = enableAccessibleFieldDOMStructure ? useFieldV7TextField : useFieldV6TextField;
|
||||
return useFieldTextField(parameters);
|
||||
};
|
||||
329
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useField.types.d.ts
generated
vendored
Normal file
329
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useField.types.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
import * as React from 'react';
|
||||
import { FieldSectionType, FieldSection, FieldSelectedSections, MuiPickersAdapter, TimezoneProps, FieldSectionContentType, PickerValidDate, FieldRef, OnErrorProps, InferFieldSection, PickerManager, PickerValueType } from "../../../models/index.js";
|
||||
import { InternalPropNames } from "../../../hooks/useSplitFieldProps.js";
|
||||
import type { PickersSectionElement, PickersSectionListRef } from "../../../PickersSectionList/index.js";
|
||||
import { FormProps, InferNonNullablePickerValue, PickerRangeValue, PickerValidValue } from "../../models/index.js";
|
||||
export interface UseFieldParameters<TValue extends PickerValidValue, TEnableAccessibleFieldDOMStructure extends boolean, TError, TValidationProps extends {}, TProps extends UseFieldProps<TEnableAccessibleFieldDOMStructure>> {
|
||||
manager: PickerManager<TValue, TEnableAccessibleFieldDOMStructure, TError, TValidationProps, any>;
|
||||
props: TProps;
|
||||
skipContextFieldRefAssignment?: boolean;
|
||||
}
|
||||
export interface UseFieldInternalProps<TValue extends PickerValidValue, TEnableAccessibleFieldDOMStructure extends boolean, TError> extends TimezoneProps, FormProps, OnErrorProps<TValue, TError> {
|
||||
/**
|
||||
* The selected value.
|
||||
* Used when the component is controlled.
|
||||
*/
|
||||
value?: TValue;
|
||||
/**
|
||||
* The default value. Use when the component is not controlled.
|
||||
*/
|
||||
defaultValue?: TValue;
|
||||
/**
|
||||
* The date used to generate a part of the new value that is not present in the format when both `value` and `defaultValue` are empty.
|
||||
* For example, on time fields it will be used to determine the date to set.
|
||||
* @default The closest valid date using the validation props, except callbacks such as `shouldDisableDate`. Value is rounded to the most granular section used.
|
||||
*/
|
||||
referenceDate?: TValue extends PickerRangeValue ? TValue | PickerValidDate : PickerValidDate;
|
||||
/**
|
||||
* Callback fired when the value changes.
|
||||
* @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @template TError The validation error type. It will be either `string` or a `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @param {TValue} value The new value.
|
||||
* @param {FieldChangeHandlerContext<TError>} context The context containing the validation result of the current value.
|
||||
*/
|
||||
onChange?: FieldChangeHandler<TValue, TError>;
|
||||
/**
|
||||
* Format of the date when rendered in the input(s).
|
||||
*/
|
||||
format: string;
|
||||
/**
|
||||
* Density of the format when rendered in the input.
|
||||
* Setting `formatDensity` to `"spacious"` will add a space before and after each `/`, `-` and `.` character.
|
||||
* @default "dense"
|
||||
*/
|
||||
formatDensity?: 'dense' | 'spacious';
|
||||
/**
|
||||
* If `true`, the format will respect the leading zeroes (for example on dayjs, the format `M/D/YYYY` will render `8/16/2018`)
|
||||
* If `false`, the format will always add leading zeroes (for example on dayjs, the format `M/D/YYYY` will render `08/16/2018`)
|
||||
*
|
||||
* Warning n°1: Luxon is not able to respect the leading zeroes when using macro tokens (for example "DD"), so `shouldRespectLeadingZeros={true}` might lead to inconsistencies when using `AdapterLuxon`.
|
||||
*
|
||||
* Warning n°2: When `shouldRespectLeadingZeros={true}`, the field will add an invisible character on the sections containing a single digit to make sure `onChange` is fired.
|
||||
* If you need to get the clean value from the input, you can remove this character using `input.value.replace(/\u200e/g, '')`.
|
||||
*
|
||||
* Warning n°3: When used in strict mode, dayjs and moment require to respect the leading zeros.
|
||||
* This mean that when using `shouldRespectLeadingZeros={false}`, if you retrieve the value directly from the input (not listening to `onChange`) and your format contains tokens without leading zeros, the value will not be parsed by your library.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
shouldRespectLeadingZeros?: boolean;
|
||||
/**
|
||||
* The currently selected sections.
|
||||
* This prop accepts four formats:
|
||||
* 1. If a number is provided, the section at this index will be selected.
|
||||
* 2. If a string of type `FieldSectionType` is provided, the first section with that name will be selected.
|
||||
* 3. If `"all"` is provided, all the sections will be selected.
|
||||
* 4. If `null` is provided, no section will be selected.
|
||||
* If not provided, the selected sections will be handled internally.
|
||||
*/
|
||||
selectedSections?: FieldSelectedSections;
|
||||
/**
|
||||
* Callback fired when the selected sections change.
|
||||
* @param {FieldSelectedSections} newValue The new selected sections.
|
||||
*/
|
||||
onSelectedSectionsChange?: (newValue: FieldSelectedSections) => void;
|
||||
/**
|
||||
* The ref object used to imperatively interact with the field.
|
||||
*/
|
||||
unstableFieldRef?: React.Ref<FieldRef<TValue>>;
|
||||
/**
|
||||
* @default true
|
||||
*/
|
||||
enableAccessibleFieldDOMStructure?: TEnableAccessibleFieldDOMStructure;
|
||||
/**
|
||||
* If `true`, the `input` element is focused during the first mount.
|
||||
* @default false
|
||||
*/
|
||||
autoFocus?: boolean;
|
||||
/**
|
||||
* If `true`, the component is displayed in focused state.
|
||||
*/
|
||||
focused?: boolean;
|
||||
}
|
||||
export type UseFieldForwardedProps<TEnableAccessibleFieldDOMStructure extends boolean> = TEnableAccessibleFieldDOMStructure extends false ? {
|
||||
clearable?: boolean;
|
||||
error?: boolean;
|
||||
placeholder?: string;
|
||||
inputRef?: React.Ref<HTMLInputElement>;
|
||||
onClick?: React.MouseEventHandler;
|
||||
onFocus?: React.FocusEventHandler;
|
||||
onKeyDown?: React.KeyboardEventHandler;
|
||||
onBlur?: React.FocusEventHandler;
|
||||
onPaste?: React.ClipboardEventHandler<HTMLDivElement>;
|
||||
onClear?: React.MouseEventHandler;
|
||||
} : {
|
||||
clearable?: boolean;
|
||||
error?: boolean;
|
||||
focused?: boolean;
|
||||
sectionListRef?: React.Ref<PickersSectionListRef>;
|
||||
onClick?: React.MouseEventHandler;
|
||||
onKeyDown?: React.KeyboardEventHandler;
|
||||
onFocus?: React.FocusEventHandler;
|
||||
onBlur?: React.FocusEventHandler;
|
||||
onInput?: React.FormEventHandler<HTMLDivElement>;
|
||||
onPaste?: React.ClipboardEventHandler<HTMLDivElement>;
|
||||
onClear?: React.MouseEventHandler;
|
||||
};
|
||||
type UseFieldAdditionalProps<TEnableAccessibleFieldDOMStructure extends boolean> = TEnableAccessibleFieldDOMStructure extends false ? {
|
||||
/**
|
||||
* The aria label to set on the button that opens the Picker.
|
||||
*/
|
||||
openPickerAriaLabel: string;
|
||||
enableAccessibleFieldDOMStructure: false;
|
||||
focused: boolean | undefined;
|
||||
inputMode: 'text' | 'numeric';
|
||||
placeholder: string;
|
||||
value: string;
|
||||
onChange: React.ChangeEventHandler<HTMLInputElement>;
|
||||
autoComplete: 'off';
|
||||
} : {
|
||||
/**
|
||||
* The aria label to set on the button that opens the Picker.
|
||||
*/
|
||||
openPickerAriaLabel: string;
|
||||
enableAccessibleFieldDOMStructure: true;
|
||||
elements: PickersSectionElement[];
|
||||
tabIndex: number | undefined;
|
||||
contentEditable: boolean;
|
||||
value: string;
|
||||
onChange: React.ChangeEventHandler<HTMLInputElement>;
|
||||
areAllSectionsEmpty: boolean;
|
||||
focused: boolean;
|
||||
};
|
||||
export type UseFieldReturnValue<TEnableAccessibleFieldDOMStructure extends boolean, TProps extends UseFieldProps<TEnableAccessibleFieldDOMStructure>> = Required<Pick<UseFieldInternalProps<any, any, any>, 'disabled' | 'readOnly' | 'autoFocus'>> & Required<UseFieldForwardedProps<TEnableAccessibleFieldDOMStructure>> & UseFieldAdditionalProps<TEnableAccessibleFieldDOMStructure> & Omit<TProps, InternalPropNames<PickerValueType>>;
|
||||
export type FieldSectionValueBoundaries<SectionType extends FieldSectionType> = {
|
||||
minimum: number;
|
||||
maximum: number;
|
||||
} & (SectionType extends 'day' ? {
|
||||
longestMonth: PickerValidDate;
|
||||
} : {});
|
||||
export type FieldSectionsValueBoundaries = { [SectionType in FieldSectionType]: (params: {
|
||||
currentDate: PickerValidDate | null;
|
||||
format: string;
|
||||
contentType: FieldSectionContentType;
|
||||
}) => FieldSectionValueBoundaries<SectionType> };
|
||||
export type FieldSectionsBoundaries = { [SectionType in FieldSectionType]: {
|
||||
minimum: number;
|
||||
maximum: number;
|
||||
} };
|
||||
export type FieldChangeHandler<TValue extends PickerValidValue, TError> = (value: TValue, context: FieldChangeHandlerContext<TError>) => void;
|
||||
export interface FieldChangeHandlerContext<TError> {
|
||||
validationError: TError;
|
||||
}
|
||||
export type FieldParsedSelectedSections = number | 'all' | null;
|
||||
export interface FieldValueManager<TValue extends PickerValidValue> {
|
||||
/**
|
||||
* Creates the section list from the current value.
|
||||
* The `prevSections` are used on the range fields to avoid losing the sections of a partially filled date when editing the other date.
|
||||
* @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @param {TValue} value The current value to generate sections from.
|
||||
* @param {(date: PickerValidDate | null) => FieldSection[]} getSectionsFromDate Returns the sections of the given date.
|
||||
* @returns {InferFieldSection<TValue>[]} The new section list.
|
||||
*/
|
||||
getSectionsFromValue: (value: TValue, getSectionsFromDate: (date: PickerValidDate | null) => FieldSection[]) => InferFieldSection<TValue>[];
|
||||
/**
|
||||
* Creates the string value to render in the input based on the current section list.
|
||||
* @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @param {InferFieldSection<TValue>[]} sections The current section list.
|
||||
* @param {string} localizedDigits The conversion table from localized to 0-9 digits.
|
||||
* @param {boolean} isRtl `true` if the current orientation is "right to left"
|
||||
* @returns {string} The string value to render in the input.
|
||||
*/
|
||||
getV6InputValueFromSections: (sections: InferFieldSection<TValue>[], localizedDigits: string[], isRtl: boolean) => string;
|
||||
/**
|
||||
* Creates the string value to render in the input based on the current section list.
|
||||
* @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @param {InferFieldSection<TValue>[]} sections The current section list.
|
||||
* @returns {string} The string value to render in the input.
|
||||
*/
|
||||
getV7HiddenInputValueFromSections: (sections: InferFieldSection<TValue>[]) => string;
|
||||
/**
|
||||
* Parses a string version (most of the time coming from the input).
|
||||
* This method should only be used when the change does not come from a single section.
|
||||
* @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @param {string} valueStr The string value to parse.
|
||||
* @param {TValue} referenceValue The reference value currently stored in state.
|
||||
* @param {(dateStr: string, referenceDate: PickerValidDate) => PickerValidDate | null} parseDate A method to convert a string date into a parsed one.
|
||||
* @returns {TValue} The new parsed value.
|
||||
*/
|
||||
parseValueStr: (valueStr: string, referenceValue: InferNonNullablePickerValue<TValue>, parseDate: (dateStr: string, referenceDate: PickerValidDate) => PickerValidDate | null) => TValue;
|
||||
/**
|
||||
* Update the reference value with the new value.
|
||||
* This method must make sure that no date inside the returned `referenceValue` is invalid.
|
||||
* @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @param {MuiPickersAdapter} adapter The adapter to manipulate the date.
|
||||
* @param {TValue} value The new value from which we want to take all valid dates in the `referenceValue` state.
|
||||
* @param {TValue} prevReferenceValue The previous reference value. It is used as a fallback for invalid dates in the new value.
|
||||
* @returns {TValue} The new reference value with no invalid date.
|
||||
*/
|
||||
updateReferenceValue: (adapter: MuiPickersAdapter, value: TValue, prevReferenceValue: InferNonNullablePickerValue<TValue>) => InferNonNullablePickerValue<TValue>;
|
||||
/**
|
||||
* Extract from the given value the date that contains the given section.
|
||||
* @param {TValue} value The value to extract the date from.
|
||||
* @param {InferFieldSection<TValue>} section The section to get the date from.
|
||||
* @returns {PickerValidDate | null} The date that contains the section.
|
||||
*/
|
||||
getDateFromSection: (value: TValue, section: InferFieldSection<TValue>) => PickerValidDate | null;
|
||||
/**
|
||||
* Get the sections of the date that contains the given section.
|
||||
* @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @param {InferFieldSection<TValue>[]} sections The sections of the full value.
|
||||
* @param {InferFieldSection<TValue>} section A section of the date from which we want to get all the sections.
|
||||
* @returns {InferFieldSection<TValue>[]} The sections of the date that contains the section.
|
||||
*/
|
||||
getDateSectionsFromValue: (sections: InferFieldSection<TValue>[], section: InferFieldSection<TValue>) => InferFieldSection<TValue>[];
|
||||
/**
|
||||
* Creates a new value based on the provided date and the current value.
|
||||
* @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @param {TValue} value The value to update the date in.
|
||||
* @param {InferFieldSection<TValue>} section A section of the date we want to update in the value.
|
||||
* @param {PickerValidDate | null} date The date that contains the section.
|
||||
* @returns {TValue} The updated value.
|
||||
*/
|
||||
updateDateInValue: (value: TValue, section: InferFieldSection<TValue>, date: PickerValidDate | null) => TValue;
|
||||
/**
|
||||
* @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @param {InferFieldSection<TValue>[]} sections The sections of the full value.
|
||||
* @param {InferFieldSection<TValue>} section A section of the date from which we want to clear all the sections.
|
||||
* @returns {InferFieldSection<TValue>[]} The sections of the full value with all the sections of the target date cleared.
|
||||
*/
|
||||
clearDateSections: (sections: InferFieldSection<TValue>[], section: InferFieldSection<TValue>) => InferFieldSection<TValue>[];
|
||||
}
|
||||
export interface UseFieldState<TValue extends PickerValidValue> {
|
||||
/**
|
||||
* Last value returned by `useControlledValue`.
|
||||
*/
|
||||
lastExternalValue: TValue;
|
||||
/**
|
||||
* Last set of parameters used to generate the sections.
|
||||
*/
|
||||
lastSectionsDependencies: {
|
||||
format: string;
|
||||
isRtl: boolean;
|
||||
locale: any;
|
||||
};
|
||||
/**
|
||||
* Non-nullable value used to keep trace of the timezone and the date parts not present in the format.
|
||||
* It is updated whenever we have a valid date (for the Range Pickers we update only the portion of the range that is valid).
|
||||
*/
|
||||
referenceValue: InferNonNullablePickerValue<TValue>;
|
||||
/**
|
||||
* Sections currently displayed in the field.
|
||||
*/
|
||||
sections: InferFieldSection<TValue>[];
|
||||
/**
|
||||
* Android `onChange` behavior when the input selection is not empty is quite different from a desktop behavior.
|
||||
* There are two `onChange` calls:
|
||||
* 1. A call with the selected content removed.
|
||||
* 2. A call with the key pressed added to the value.
|
||||
**
|
||||
* For instance, if the input value equals `month / day / year` and `day` is selected.
|
||||
* The pressing `1` will have the following behavior:
|
||||
* 1. A call with `month / / year`.
|
||||
* 2. A call with `month / 1 / year`.
|
||||
*
|
||||
* But if you don't update the input with the value passed on the first `onChange`.
|
||||
* Then the second `onChange` will add the key press at the beginning of the selected value.
|
||||
* 1. A call with `month / / year` that we don't set into state.
|
||||
* 2. A call with `month / 1day / year`.
|
||||
*
|
||||
* The property below allows us to set the first `onChange` value into state waiting for the second one.
|
||||
*/
|
||||
tempValueStrAndroid: string | null;
|
||||
/**
|
||||
* The current query when editing the field using letters or digits.
|
||||
*/
|
||||
characterQuery: CharacterEditingQuery | null;
|
||||
}
|
||||
export type SectionNeighbors = {
|
||||
[sectionIndex: number]: {
|
||||
/**
|
||||
* Index of the next section displayed on the left. `null` if it's the leftmost section.
|
||||
*/
|
||||
leftIndex: number | null;
|
||||
/**
|
||||
* Index of the next section displayed on the right. `null` if it's the rightmost section.
|
||||
*/
|
||||
rightIndex: number | null;
|
||||
};
|
||||
};
|
||||
export type SectionOrdering = {
|
||||
/**
|
||||
* For each section index provide the index of the section displayed on the left and on the right.
|
||||
*/
|
||||
neighbors: SectionNeighbors;
|
||||
/**
|
||||
* Index of the section displayed on the far left
|
||||
*/
|
||||
startIndex: number;
|
||||
/**
|
||||
* Index of the section displayed on the far right
|
||||
*/
|
||||
endIndex: number;
|
||||
};
|
||||
export interface CharacterEditingQuery {
|
||||
value: string;
|
||||
sectionIndex: number;
|
||||
sectionType: FieldSectionType;
|
||||
}
|
||||
export type UseFieldProps<TEnableAccessibleFieldDOMStructure extends boolean> = UseFieldForwardedProps<TEnableAccessibleFieldDOMStructure> & {
|
||||
enableAccessibleFieldDOMStructure?: boolean;
|
||||
};
|
||||
export interface UseFieldDOMGetters {
|
||||
isReady: () => boolean;
|
||||
getRoot: () => HTMLElement;
|
||||
getSectionContainer: (sectionIndex: number) => HTMLElement;
|
||||
getSectionContent: (sectionIndex: number) => HTMLElement;
|
||||
getSectionIndexFromDOMElement: (element: Element | null | undefined) => number | null;
|
||||
}
|
||||
export {};
|
||||
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useField.types.js
generated
vendored
Normal file
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useField.types.js
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
export {};
|
||||
36
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useField.utils.d.ts
generated
vendored
Normal file
36
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useField.utils.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { FieldSectionsValueBoundaries, SectionOrdering, FieldSectionValueBoundaries, FieldParsedSelectedSections } from "./useField.types.js";
|
||||
import { FieldSectionType, FieldSection, MuiPickersAdapter, FieldSectionContentType, PickersTimezone, PickerValidDate, FieldSelectedSections, PickerValueType, InferFieldSection } from "../../../models/index.js";
|
||||
import { PickerValidValue } from "../../models/index.js";
|
||||
export declare const getDateSectionConfigFromFormatToken: (adapter: MuiPickersAdapter, formatToken: string) => Pick<FieldSection, "type" | "contentType"> & {
|
||||
maxLength: number | undefined;
|
||||
};
|
||||
export declare const getDaysInWeekStr: (adapter: MuiPickersAdapter, format: string) => string[];
|
||||
export declare const getLetterEditingOptions: (adapter: MuiPickersAdapter, timezone: PickersTimezone, sectionType: FieldSectionType, format: string) => string[];
|
||||
export declare const FORMAT_SECONDS_NO_LEADING_ZEROS = "s";
|
||||
export declare const getLocalizedDigits: (adapter: MuiPickersAdapter) => string[];
|
||||
export declare const removeLocalizedDigits: (valueStr: string, localizedDigits: string[]) => string;
|
||||
export declare const applyLocalizedDigits: (valueStr: string, localizedDigits: string[]) => string;
|
||||
export declare const isStringNumber: (valueStr: string, localizedDigits: string[]) => boolean;
|
||||
/**
|
||||
* Make sure the value of a digit section have the right amount of leading zeros.
|
||||
* E.g.: `03` => `3`
|
||||
* Warning: Should only be called with non-localized digits. Call `removeLocalizedDigits` with your value if needed.
|
||||
*/
|
||||
export declare const cleanLeadingZeros: (valueStr: string, size: number) => string;
|
||||
export declare const cleanDigitSectionValue: (adapter: MuiPickersAdapter, value: number, sectionBoundaries: FieldSectionValueBoundaries<any>, localizedDigits: string[], section: Pick<FieldSection, "format" | "type" | "contentType" | "hasLeadingZerosInFormat" | "hasLeadingZerosInInput" | "maxLength">) => string;
|
||||
export declare const getSectionVisibleValue: (section: FieldSection, target: "input-rtl" | "input-ltr" | "non-input", localizedDigits: string[]) => string;
|
||||
export declare const changeSectionValueFormat: (adapter: MuiPickersAdapter, valueStr: string, currentFormat: string, newFormat: string) => string;
|
||||
export declare const doesSectionFormatHaveLeadingZeros: (adapter: MuiPickersAdapter, contentType: FieldSectionContentType, sectionType: FieldSectionType, format: string) => boolean;
|
||||
/**
|
||||
* Some date libraries like `dayjs` don't support parsing from date with escaped characters.
|
||||
* To make sure that the parsing works, we are building a format and a date without any separator.
|
||||
*/
|
||||
export declare const getDateFromDateSections: (adapter: MuiPickersAdapter, sections: FieldSection[], localizedDigits: string[]) => PickerValidDate;
|
||||
export declare const createDateStrForV7HiddenInputFromSections: (sections: FieldSection[]) => string;
|
||||
export declare const createDateStrForV6InputFromSections: (sections: FieldSection[], localizedDigits: string[], isRtl: boolean) => string;
|
||||
export declare const getSectionsBoundaries: (adapter: MuiPickersAdapter, localizedDigits: string[], timezone: PickersTimezone) => FieldSectionsValueBoundaries;
|
||||
export declare const validateSections: <TValue extends PickerValidValue>(sections: InferFieldSection<TValue>[], valueType: PickerValueType) => void;
|
||||
export declare const mergeDateIntoReferenceDate: (adapter: MuiPickersAdapter, dateToTransferFrom: PickerValidDate, sections: FieldSection[], referenceDate: PickerValidDate, shouldLimitToEditedSections: boolean) => PickerValidDate;
|
||||
export declare const isAndroid: () => boolean;
|
||||
export declare const getSectionOrder: (sections: FieldSection[], shouldApplyRTL: boolean) => SectionOrdering;
|
||||
export declare const parseSelectedSections: (selectedSections: FieldSelectedSections, sections: FieldSection[]) => FieldParsedSelectedSections;
|
||||
496
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useField.utils.js
generated
vendored
Normal file
496
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useField.utils.js
generated
vendored
Normal file
|
|
@ -0,0 +1,496 @@
|
|||
import { getMonthsInYear } from "../../utils/date-utils.js";
|
||||
export const getDateSectionConfigFromFormatToken = (adapter, formatToken) => {
|
||||
const config = adapter.formatTokenMap[formatToken];
|
||||
if (config == null) {
|
||||
throw new Error([`MUI X: The token "${formatToken}" is not supported by the Date and Time Pickers.`, 'Please try using another token or open an issue on https://github.com/mui/mui-x/issues/new/choose if you think it should be supported.'].join('\n'));
|
||||
}
|
||||
if (typeof config === 'string') {
|
||||
return {
|
||||
type: config,
|
||||
contentType: config === 'meridiem' ? 'letter' : 'digit',
|
||||
maxLength: undefined
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: config.sectionType,
|
||||
contentType: config.contentType,
|
||||
maxLength: config.maxLength
|
||||
};
|
||||
};
|
||||
export const getDaysInWeekStr = (adapter, format) => {
|
||||
const elements = [];
|
||||
const now = adapter.date(undefined, 'default');
|
||||
const startDate = adapter.startOfWeek(now);
|
||||
const endDate = adapter.endOfWeek(now);
|
||||
let current = startDate;
|
||||
while (adapter.isBefore(current, endDate)) {
|
||||
elements.push(current);
|
||||
current = adapter.addDays(current, 1);
|
||||
}
|
||||
return elements.map(weekDay => adapter.formatByString(weekDay, format));
|
||||
};
|
||||
export const getLetterEditingOptions = (adapter, timezone, sectionType, format) => {
|
||||
switch (sectionType) {
|
||||
case 'month':
|
||||
{
|
||||
return getMonthsInYear(adapter, adapter.date(undefined, timezone)).map(month => adapter.formatByString(month, format));
|
||||
}
|
||||
case 'weekDay':
|
||||
{
|
||||
return getDaysInWeekStr(adapter, format);
|
||||
}
|
||||
case 'meridiem':
|
||||
{
|
||||
const now = adapter.date(undefined, timezone);
|
||||
return [adapter.startOfDay(now), adapter.endOfDay(now)].map(date => adapter.formatByString(date, format));
|
||||
}
|
||||
default:
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// This format should be the same on all the adapters
|
||||
// If some adapter does not respect this convention, then we will need to hardcode the format on each adapter.
|
||||
export const FORMAT_SECONDS_NO_LEADING_ZEROS = 's';
|
||||
const NON_LOCALIZED_DIGITS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||
export const getLocalizedDigits = adapter => {
|
||||
const today = adapter.date(undefined);
|
||||
const formattedZero = adapter.formatByString(adapter.setSeconds(today, 0), FORMAT_SECONDS_NO_LEADING_ZEROS);
|
||||
if (formattedZero === '0') {
|
||||
return NON_LOCALIZED_DIGITS;
|
||||
}
|
||||
return Array.from({
|
||||
length: 10
|
||||
}).map((_, index) => adapter.formatByString(adapter.setSeconds(today, index), FORMAT_SECONDS_NO_LEADING_ZEROS));
|
||||
};
|
||||
export const removeLocalizedDigits = (valueStr, localizedDigits) => {
|
||||
if (localizedDigits[0] === '0') {
|
||||
return valueStr;
|
||||
}
|
||||
const digits = [];
|
||||
let currentFormattedDigit = '';
|
||||
for (let i = 0; i < valueStr.length; i += 1) {
|
||||
currentFormattedDigit += valueStr[i];
|
||||
const matchingDigitIndex = localizedDigits.indexOf(currentFormattedDigit);
|
||||
if (matchingDigitIndex > -1) {
|
||||
digits.push(matchingDigitIndex.toString());
|
||||
currentFormattedDigit = '';
|
||||
}
|
||||
}
|
||||
return digits.join('');
|
||||
};
|
||||
export const applyLocalizedDigits = (valueStr, localizedDigits) => {
|
||||
if (localizedDigits[0] === '0') {
|
||||
return valueStr;
|
||||
}
|
||||
return valueStr.split('').map(char => localizedDigits[Number(char)]).join('');
|
||||
};
|
||||
export const isStringNumber = (valueStr, localizedDigits) => {
|
||||
const nonLocalizedValueStr = removeLocalizedDigits(valueStr, localizedDigits);
|
||||
// `Number(' ')` returns `0` even if ' ' is not a valid number.
|
||||
return nonLocalizedValueStr !== ' ' && !Number.isNaN(Number(nonLocalizedValueStr));
|
||||
};
|
||||
|
||||
/**
|
||||
* Make sure the value of a digit section have the right amount of leading zeros.
|
||||
* E.g.: `03` => `3`
|
||||
* Warning: Should only be called with non-localized digits. Call `removeLocalizedDigits` with your value if needed.
|
||||
*/
|
||||
export const cleanLeadingZeros = (valueStr, size) => {
|
||||
// Remove the leading zeros and then add back as many as needed.
|
||||
return Number(valueStr).toString().padStart(size, '0');
|
||||
};
|
||||
export const cleanDigitSectionValue = (adapter, value, sectionBoundaries, localizedDigits, section) => {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (section.type !== 'day' && section.contentType === 'digit-with-letter') {
|
||||
throw new Error([`MUI X: The token "${section.format}" is a digit format with letter in it.'
|
||||
This type of format is only supported for 'day' sections`].join('\n'));
|
||||
}
|
||||
}
|
||||
if (section.type === 'day' && section.contentType === 'digit-with-letter') {
|
||||
const date = adapter.setDate(sectionBoundaries.longestMonth, value);
|
||||
return adapter.formatByString(date, section.format);
|
||||
}
|
||||
|
||||
// queryValue without leading `0` (`01` => `1`)
|
||||
let valueStr = value.toString();
|
||||
if (section.hasLeadingZerosInInput) {
|
||||
valueStr = cleanLeadingZeros(valueStr, section.maxLength);
|
||||
}
|
||||
return applyLocalizedDigits(valueStr, localizedDigits);
|
||||
};
|
||||
export const getSectionVisibleValue = (section, target, localizedDigits) => {
|
||||
let value = section.value || section.placeholder;
|
||||
const hasLeadingZeros = target === 'non-input' ? section.hasLeadingZerosInFormat : section.hasLeadingZerosInInput;
|
||||
if (target === 'non-input' && section.hasLeadingZerosInInput && !section.hasLeadingZerosInFormat) {
|
||||
value = Number(removeLocalizedDigits(value, localizedDigits)).toString();
|
||||
}
|
||||
|
||||
// In the input, we add an empty character at the end of each section without leading zeros.
|
||||
// This makes sure that `onChange` will always be fired.
|
||||
// Otherwise, when your input value equals `1/dd/yyyy` (format `M/DD/YYYY` on DayJs),
|
||||
// If you press `1`, on the first section, the new value is also `1/dd/yyyy`,
|
||||
// So the browser will not fire the input `onChange`.
|
||||
const shouldAddInvisibleSpace = ['input-rtl', 'input-ltr'].includes(target) && section.contentType === 'digit' && !hasLeadingZeros && value.length === 1;
|
||||
if (shouldAddInvisibleSpace) {
|
||||
value = `${value}\u200e`;
|
||||
}
|
||||
if (target === 'input-rtl') {
|
||||
value = `\u2068${value}\u2069`;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
export const changeSectionValueFormat = (adapter, valueStr, currentFormat, newFormat) => {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (getDateSectionConfigFromFormatToken(adapter, currentFormat).type === 'weekDay') {
|
||||
throw new Error("changeSectionValueFormat doesn't support week day formats");
|
||||
}
|
||||
}
|
||||
return adapter.formatByString(adapter.parse(valueStr, currentFormat), newFormat);
|
||||
};
|
||||
const isFourDigitYearFormat = (adapter, format) => adapter.formatByString(adapter.date(undefined, 'system'), format).length === 4;
|
||||
export const doesSectionFormatHaveLeadingZeros = (adapter, contentType, sectionType, format) => {
|
||||
if (contentType !== 'digit') {
|
||||
return false;
|
||||
}
|
||||
const now = adapter.date(undefined, 'default');
|
||||
switch (sectionType) {
|
||||
// We can't use `changeSectionValueFormat`, because `adapter.parse('1', 'YYYY')` returns `1971` instead of `1`.
|
||||
case 'year':
|
||||
{
|
||||
// Remove once https://github.com/iamkun/dayjs/pull/2847 is merged and bump dayjs version
|
||||
if (adapter.lib === 'dayjs' && format === 'YY') {
|
||||
return true;
|
||||
}
|
||||
return adapter.formatByString(adapter.setYear(now, 1), format).startsWith('0');
|
||||
}
|
||||
case 'month':
|
||||
{
|
||||
return adapter.formatByString(adapter.startOfYear(now), format).length > 1;
|
||||
}
|
||||
case 'day':
|
||||
{
|
||||
return adapter.formatByString(adapter.startOfMonth(now), format).length > 1;
|
||||
}
|
||||
case 'weekDay':
|
||||
{
|
||||
return adapter.formatByString(adapter.startOfWeek(now), format).length > 1;
|
||||
}
|
||||
case 'hours':
|
||||
{
|
||||
return adapter.formatByString(adapter.setHours(now, 1), format).length > 1;
|
||||
}
|
||||
case 'minutes':
|
||||
{
|
||||
return adapter.formatByString(adapter.setMinutes(now, 1), format).length > 1;
|
||||
}
|
||||
case 'seconds':
|
||||
{
|
||||
return adapter.formatByString(adapter.setSeconds(now, 1), format).length > 1;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new Error('Invalid section type');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Some date libraries like `dayjs` don't support parsing from date with escaped characters.
|
||||
* To make sure that the parsing works, we are building a format and a date without any separator.
|
||||
*/
|
||||
export const getDateFromDateSections = (adapter, sections, localizedDigits) => {
|
||||
// If we have both a day and a weekDay section,
|
||||
// Then we skip the weekDay in the parsing because libraries like dayjs can't parse complicated formats containing a weekDay.
|
||||
// dayjs(dayjs().format('dddd MMMM D YYYY'), 'dddd MMMM D YYYY')) // returns `Invalid Date` even if the format is valid.
|
||||
const shouldSkipWeekDays = sections.some(section => section.type === 'day');
|
||||
const sectionFormats = [];
|
||||
const sectionValues = [];
|
||||
for (let i = 0; i < sections.length; i += 1) {
|
||||
const section = sections[i];
|
||||
const shouldSkip = shouldSkipWeekDays && section.type === 'weekDay';
|
||||
if (!shouldSkip) {
|
||||
sectionFormats.push(section.format);
|
||||
sectionValues.push(getSectionVisibleValue(section, 'non-input', localizedDigits));
|
||||
}
|
||||
}
|
||||
const formatWithoutSeparator = sectionFormats.join(' ');
|
||||
const dateWithoutSeparatorStr = sectionValues.join(' ');
|
||||
return adapter.parse(dateWithoutSeparatorStr, formatWithoutSeparator);
|
||||
};
|
||||
export const createDateStrForV7HiddenInputFromSections = sections => sections.map(section => {
|
||||
return `${section.startSeparator}${section.value || section.placeholder}${section.endSeparator}`;
|
||||
}).join('');
|
||||
export const createDateStrForV6InputFromSections = (sections, localizedDigits, isRtl) => {
|
||||
const formattedSections = sections.map(section => {
|
||||
const dateValue = getSectionVisibleValue(section, isRtl ? 'input-rtl' : 'input-ltr', localizedDigits);
|
||||
return `${section.startSeparator}${dateValue}${section.endSeparator}`;
|
||||
});
|
||||
const dateStr = formattedSections.join('');
|
||||
if (!isRtl) {
|
||||
return dateStr;
|
||||
}
|
||||
|
||||
// \u2066: start left-to-right isolation
|
||||
// \u2067: start right-to-left isolation
|
||||
// \u2068: start first strong character isolation
|
||||
// \u2069: pop isolation
|
||||
// wrap into an isolated group such that separators can split the string in smaller ones by adding \u2069\u2068
|
||||
return `\u2066${dateStr}\u2069`;
|
||||
};
|
||||
export const getSectionsBoundaries = (adapter, localizedDigits, timezone) => {
|
||||
const today = adapter.date(undefined, timezone);
|
||||
const endOfYear = adapter.endOfYear(today);
|
||||
const endOfDay = adapter.endOfDay(today);
|
||||
const {
|
||||
maxDaysInMonth,
|
||||
longestMonth
|
||||
} = getMonthsInYear(adapter, today).reduce((acc, month) => {
|
||||
const daysInMonth = adapter.getDaysInMonth(month);
|
||||
if (daysInMonth > acc.maxDaysInMonth) {
|
||||
return {
|
||||
maxDaysInMonth: daysInMonth,
|
||||
longestMonth: month
|
||||
};
|
||||
}
|
||||
return acc;
|
||||
}, {
|
||||
maxDaysInMonth: 0,
|
||||
longestMonth: null
|
||||
});
|
||||
return {
|
||||
year: ({
|
||||
format
|
||||
}) => ({
|
||||
minimum: 0,
|
||||
maximum: isFourDigitYearFormat(adapter, format) ? 9999 : 99
|
||||
}),
|
||||
month: () => ({
|
||||
minimum: 1,
|
||||
// Assumption: All years have the same amount of months
|
||||
maximum: adapter.getMonth(endOfYear) + 1
|
||||
}),
|
||||
day: ({
|
||||
currentDate
|
||||
}) => ({
|
||||
minimum: 1,
|
||||
maximum: adapter.isValid(currentDate) ? adapter.getDaysInMonth(currentDate) : maxDaysInMonth,
|
||||
longestMonth: longestMonth
|
||||
}),
|
||||
weekDay: ({
|
||||
format,
|
||||
contentType
|
||||
}) => {
|
||||
if (contentType === 'digit') {
|
||||
const daysInWeek = getDaysInWeekStr(adapter, format).map(Number);
|
||||
return {
|
||||
minimum: Math.min(...daysInWeek),
|
||||
maximum: Math.max(...daysInWeek)
|
||||
};
|
||||
}
|
||||
return {
|
||||
minimum: 1,
|
||||
maximum: 7
|
||||
};
|
||||
},
|
||||
hours: ({
|
||||
format
|
||||
}) => {
|
||||
const lastHourInDay = adapter.getHours(endOfDay);
|
||||
const hasMeridiem = removeLocalizedDigits(adapter.formatByString(adapter.endOfDay(today), format), localizedDigits) !== lastHourInDay.toString();
|
||||
if (hasMeridiem) {
|
||||
return {
|
||||
minimum: 1,
|
||||
maximum: Number(removeLocalizedDigits(adapter.formatByString(adapter.startOfDay(today), format), localizedDigits))
|
||||
};
|
||||
}
|
||||
return {
|
||||
minimum: 0,
|
||||
maximum: lastHourInDay
|
||||
};
|
||||
},
|
||||
minutes: () => ({
|
||||
minimum: 0,
|
||||
// Assumption: All years have the same amount of minutes
|
||||
maximum: adapter.getMinutes(endOfDay)
|
||||
}),
|
||||
seconds: () => ({
|
||||
minimum: 0,
|
||||
// Assumption: All years have the same amount of seconds
|
||||
maximum: adapter.getSeconds(endOfDay)
|
||||
}),
|
||||
meridiem: () => ({
|
||||
minimum: 0,
|
||||
maximum: 1
|
||||
}),
|
||||
empty: () => ({
|
||||
minimum: 0,
|
||||
maximum: 0
|
||||
})
|
||||
};
|
||||
};
|
||||
let warnedOnceInvalidSection = false;
|
||||
export const validateSections = (sections, valueType) => {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (!warnedOnceInvalidSection) {
|
||||
const supportedSections = ['empty'];
|
||||
if (['date', 'date-time'].includes(valueType)) {
|
||||
supportedSections.push('weekDay', 'day', 'month', 'year');
|
||||
}
|
||||
if (['time', 'date-time'].includes(valueType)) {
|
||||
supportedSections.push('hours', 'minutes', 'seconds', 'meridiem');
|
||||
}
|
||||
const invalidSection = sections.find(section => !supportedSections.includes(section.type));
|
||||
if (invalidSection) {
|
||||
console.warn(`MUI X: The field component you are using is not compatible with the "${invalidSection.type}" date section.`, `The supported date sections are ["${supportedSections.join('", "')}"]\`.`);
|
||||
warnedOnceInvalidSection = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const transferDateSectionValue = (adapter, section, dateToTransferFrom, dateToTransferTo) => {
|
||||
switch (section.type) {
|
||||
case 'year':
|
||||
{
|
||||
return adapter.setYear(dateToTransferTo, adapter.getYear(dateToTransferFrom));
|
||||
}
|
||||
case 'month':
|
||||
{
|
||||
return adapter.setMonth(dateToTransferTo, adapter.getMonth(dateToTransferFrom));
|
||||
}
|
||||
case 'weekDay':
|
||||
{
|
||||
let dayInWeekStrOfActiveDate = adapter.formatByString(dateToTransferFrom, section.format);
|
||||
if (section.hasLeadingZerosInInput) {
|
||||
dayInWeekStrOfActiveDate = cleanLeadingZeros(dayInWeekStrOfActiveDate, section.maxLength);
|
||||
}
|
||||
const formattedDaysInWeek = getDaysInWeekStr(adapter, section.format);
|
||||
const dayInWeekOfActiveDate = formattedDaysInWeek.indexOf(dayInWeekStrOfActiveDate);
|
||||
const dayInWeekOfNewSectionValue = formattedDaysInWeek.indexOf(section.value);
|
||||
const diff = dayInWeekOfNewSectionValue - dayInWeekOfActiveDate;
|
||||
return adapter.addDays(dateToTransferFrom, diff);
|
||||
}
|
||||
case 'day':
|
||||
{
|
||||
return adapter.setDate(dateToTransferTo, adapter.getDate(dateToTransferFrom));
|
||||
}
|
||||
case 'meridiem':
|
||||
{
|
||||
const isAM = adapter.getHours(dateToTransferFrom) < 12;
|
||||
const mergedDateHours = adapter.getHours(dateToTransferTo);
|
||||
if (isAM && mergedDateHours >= 12) {
|
||||
return adapter.addHours(dateToTransferTo, -12);
|
||||
}
|
||||
if (!isAM && mergedDateHours < 12) {
|
||||
return adapter.addHours(dateToTransferTo, 12);
|
||||
}
|
||||
return dateToTransferTo;
|
||||
}
|
||||
case 'hours':
|
||||
{
|
||||
return adapter.setHours(dateToTransferTo, adapter.getHours(dateToTransferFrom));
|
||||
}
|
||||
case 'minutes':
|
||||
{
|
||||
return adapter.setMinutes(dateToTransferTo, adapter.getMinutes(dateToTransferFrom));
|
||||
}
|
||||
case 'seconds':
|
||||
{
|
||||
return adapter.setSeconds(dateToTransferTo, adapter.getSeconds(dateToTransferFrom));
|
||||
}
|
||||
default:
|
||||
{
|
||||
return dateToTransferTo;
|
||||
}
|
||||
}
|
||||
};
|
||||
const reliableSectionModificationOrder = {
|
||||
year: 1,
|
||||
month: 2,
|
||||
day: 3,
|
||||
weekDay: 4,
|
||||
hours: 5,
|
||||
minutes: 6,
|
||||
seconds: 7,
|
||||
meridiem: 8,
|
||||
empty: 9
|
||||
};
|
||||
export const mergeDateIntoReferenceDate = (adapter, dateToTransferFrom, sections, referenceDate, shouldLimitToEditedSections) =>
|
||||
// cloning sections before sort to avoid mutating it
|
||||
[...sections].sort((a, b) => reliableSectionModificationOrder[a.type] - reliableSectionModificationOrder[b.type]).reduce((mergedDate, section) => {
|
||||
if (!shouldLimitToEditedSections || section.modified) {
|
||||
return transferDateSectionValue(adapter, section, dateToTransferFrom, mergedDate);
|
||||
}
|
||||
return mergedDate;
|
||||
}, referenceDate);
|
||||
export const isAndroid = () => navigator.userAgent.toLowerCase().includes('android');
|
||||
|
||||
// TODO v9: Remove
|
||||
export const getSectionOrder = (sections, shouldApplyRTL) => {
|
||||
const neighbors = {};
|
||||
if (!shouldApplyRTL) {
|
||||
sections.forEach((_, index) => {
|
||||
const leftIndex = index === 0 ? null : index - 1;
|
||||
const rightIndex = index === sections.length - 1 ? null : index + 1;
|
||||
neighbors[index] = {
|
||||
leftIndex,
|
||||
rightIndex
|
||||
};
|
||||
});
|
||||
return {
|
||||
neighbors,
|
||||
startIndex: 0,
|
||||
endIndex: sections.length - 1
|
||||
};
|
||||
}
|
||||
const rtl2ltr = {};
|
||||
const ltr2rtl = {};
|
||||
let groupedSectionsStart = 0;
|
||||
let groupedSectionsEnd = 0;
|
||||
let RTLIndex = sections.length - 1;
|
||||
while (RTLIndex >= 0) {
|
||||
groupedSectionsEnd = sections.findIndex(
|
||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||
(section, index) => index >= groupedSectionsStart && section.endSeparator?.includes(' ') &&
|
||||
// Special case where the spaces were not there in the initial input
|
||||
section.endSeparator !== ' / ');
|
||||
if (groupedSectionsEnd === -1) {
|
||||
groupedSectionsEnd = sections.length - 1;
|
||||
}
|
||||
for (let i = groupedSectionsEnd; i >= groupedSectionsStart; i -= 1) {
|
||||
ltr2rtl[i] = RTLIndex;
|
||||
rtl2ltr[RTLIndex] = i;
|
||||
RTLIndex -= 1;
|
||||
}
|
||||
groupedSectionsStart = groupedSectionsEnd + 1;
|
||||
}
|
||||
sections.forEach((_, index) => {
|
||||
const rtlIndex = ltr2rtl[index];
|
||||
const leftIndex = rtlIndex === 0 ? null : rtl2ltr[rtlIndex - 1];
|
||||
const rightIndex = rtlIndex === sections.length - 1 ? null : rtl2ltr[rtlIndex + 1];
|
||||
neighbors[index] = {
|
||||
leftIndex,
|
||||
rightIndex
|
||||
};
|
||||
});
|
||||
return {
|
||||
neighbors,
|
||||
startIndex: rtl2ltr[0],
|
||||
endIndex: rtl2ltr[sections.length - 1]
|
||||
};
|
||||
};
|
||||
export const parseSelectedSections = (selectedSections, sections) => {
|
||||
if (selectedSections == null) {
|
||||
return null;
|
||||
}
|
||||
if (selectedSections === 'all') {
|
||||
return 'all';
|
||||
}
|
||||
if (typeof selectedSections === 'string') {
|
||||
const index = sections.findIndex(section => section.type === selectedSections);
|
||||
return index === -1 ? null : index;
|
||||
}
|
||||
return selectedSections;
|
||||
};
|
||||
29
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldCharacterEditing.d.ts
generated
vendored
Normal file
29
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldCharacterEditing.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { UseFieldStateReturnValue } from "./useFieldState.js";
|
||||
import { PickerValidValue } from "../../models/index.js";
|
||||
/**
|
||||
* Update the active section value when the user pressed a key that is not a navigation key (arrow key for example).
|
||||
* This hook has two main editing behaviors
|
||||
*
|
||||
* 1. The numeric editing when the user presses a digit
|
||||
* 2. The letter editing when the user presses another key
|
||||
*/
|
||||
export declare const useFieldCharacterEditing: <TValue extends PickerValidValue>({
|
||||
stateResponse: {
|
||||
localizedDigits,
|
||||
sectionsValueBoundaries,
|
||||
state,
|
||||
timezone,
|
||||
setCharacterQuery,
|
||||
setTempAndroidValueStr,
|
||||
updateSectionValue
|
||||
}
|
||||
}: UseFieldCharacterEditingParameters<TValue>) => UseFieldCharacterEditingReturnValue;
|
||||
export interface ApplyCharacterEditingParameters {
|
||||
keyPressed: string;
|
||||
sectionIndex: number;
|
||||
}
|
||||
interface UseFieldCharacterEditingParameters<TValue extends PickerValidValue> {
|
||||
stateResponse: UseFieldStateReturnValue<TValue>;
|
||||
}
|
||||
export type UseFieldCharacterEditingReturnValue = (params: ApplyCharacterEditingParameters) => void;
|
||||
export {};
|
||||
256
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldCharacterEditing.js
generated
vendored
Normal file
256
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldCharacterEditing.js
generated
vendored
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
import _extends from "@babel/runtime/helpers/esm/extends";
|
||||
import useEventCallback from '@mui/utils/useEventCallback';
|
||||
import { changeSectionValueFormat, cleanDigitSectionValue, doesSectionFormatHaveLeadingZeros, getDateSectionConfigFromFormatToken, getDaysInWeekStr, getLetterEditingOptions, applyLocalizedDigits, removeLocalizedDigits, isStringNumber } from "./useField.utils.js";
|
||||
import { usePickerAdapter } from "../../../hooks/usePickerAdapter.js";
|
||||
const isQueryResponseWithoutValue = response => response.saveQuery != null;
|
||||
|
||||
/**
|
||||
* Update the active section value when the user pressed a key that is not a navigation key (arrow key for example).
|
||||
* This hook has two main editing behaviors
|
||||
*
|
||||
* 1. The numeric editing when the user presses a digit
|
||||
* 2. The letter editing when the user presses another key
|
||||
*/
|
||||
export const useFieldCharacterEditing = ({
|
||||
stateResponse: {
|
||||
// States and derived states
|
||||
localizedDigits,
|
||||
sectionsValueBoundaries,
|
||||
state,
|
||||
timezone,
|
||||
// Methods to update the states
|
||||
setCharacterQuery,
|
||||
setTempAndroidValueStr,
|
||||
updateSectionValue
|
||||
}
|
||||
}) => {
|
||||
const adapter = usePickerAdapter();
|
||||
const applyQuery = ({
|
||||
keyPressed,
|
||||
sectionIndex
|
||||
}, getFirstSectionValueMatchingWithQuery, isValidQueryValue) => {
|
||||
const cleanKeyPressed = keyPressed.toLowerCase();
|
||||
const activeSection = state.sections[sectionIndex];
|
||||
|
||||
// The current query targets the section being editing
|
||||
// We can try to concatenate the value
|
||||
if (state.characterQuery != null && (!isValidQueryValue || isValidQueryValue(state.characterQuery.value)) && state.characterQuery.sectionIndex === sectionIndex) {
|
||||
const concatenatedQueryValue = `${state.characterQuery.value}${cleanKeyPressed}`;
|
||||
const queryResponse = getFirstSectionValueMatchingWithQuery(concatenatedQueryValue, activeSection);
|
||||
if (!isQueryResponseWithoutValue(queryResponse)) {
|
||||
setCharacterQuery({
|
||||
sectionIndex,
|
||||
value: concatenatedQueryValue,
|
||||
sectionType: activeSection.type
|
||||
});
|
||||
return queryResponse;
|
||||
}
|
||||
}
|
||||
const queryResponse = getFirstSectionValueMatchingWithQuery(cleanKeyPressed, activeSection);
|
||||
if (isQueryResponseWithoutValue(queryResponse) && !queryResponse.saveQuery) {
|
||||
setCharacterQuery(null);
|
||||
return null;
|
||||
}
|
||||
setCharacterQuery({
|
||||
sectionIndex,
|
||||
value: cleanKeyPressed,
|
||||
sectionType: activeSection.type
|
||||
});
|
||||
if (isQueryResponseWithoutValue(queryResponse)) {
|
||||
return null;
|
||||
}
|
||||
return queryResponse;
|
||||
};
|
||||
const applyLetterEditing = params => {
|
||||
const findMatchingOptions = (format, options, queryValue) => {
|
||||
const matchingValues = options.filter(option => option.toLowerCase().startsWith(queryValue));
|
||||
if (matchingValues.length === 0) {
|
||||
return {
|
||||
saveQuery: false
|
||||
};
|
||||
}
|
||||
return {
|
||||
sectionValue: matchingValues[0],
|
||||
shouldGoToNextSection: matchingValues.length === 1
|
||||
};
|
||||
};
|
||||
const testQueryOnFormatAndFallbackFormat = (queryValue, activeSection, fallbackFormat, formatFallbackValue) => {
|
||||
const getOptions = format => getLetterEditingOptions(adapter, timezone, activeSection.type, format);
|
||||
if (activeSection.contentType === 'letter') {
|
||||
return findMatchingOptions(activeSection.format, getOptions(activeSection.format), queryValue);
|
||||
}
|
||||
|
||||
// When editing a digit-format month / weekDay and the user presses a letter,
|
||||
// We can support the letter editing by using the letter-format month / weekDay and re-formatting the result.
|
||||
// We just have to make sure that the default month / weekDay format is a letter format,
|
||||
if (fallbackFormat && formatFallbackValue != null && getDateSectionConfigFromFormatToken(adapter, fallbackFormat).contentType === 'letter') {
|
||||
const fallbackOptions = getOptions(fallbackFormat);
|
||||
const response = findMatchingOptions(fallbackFormat, fallbackOptions, queryValue);
|
||||
if (isQueryResponseWithoutValue(response)) {
|
||||
return {
|
||||
saveQuery: false
|
||||
};
|
||||
}
|
||||
return _extends({}, response, {
|
||||
sectionValue: formatFallbackValue(response.sectionValue, fallbackOptions)
|
||||
});
|
||||
}
|
||||
return {
|
||||
saveQuery: false
|
||||
};
|
||||
};
|
||||
const getFirstSectionValueMatchingWithQuery = (queryValue, activeSection) => {
|
||||
switch (activeSection.type) {
|
||||
case 'month':
|
||||
{
|
||||
const formatFallbackValue = fallbackValue => changeSectionValueFormat(adapter, fallbackValue, adapter.formats.month, activeSection.format);
|
||||
return testQueryOnFormatAndFallbackFormat(queryValue, activeSection, adapter.formats.month, formatFallbackValue);
|
||||
}
|
||||
case 'weekDay':
|
||||
{
|
||||
const formatFallbackValue = (fallbackValue, fallbackOptions) => fallbackOptions.indexOf(fallbackValue).toString();
|
||||
return testQueryOnFormatAndFallbackFormat(queryValue, activeSection, adapter.formats.weekday, formatFallbackValue);
|
||||
}
|
||||
case 'meridiem':
|
||||
{
|
||||
return testQueryOnFormatAndFallbackFormat(queryValue, activeSection);
|
||||
}
|
||||
default:
|
||||
{
|
||||
return {
|
||||
saveQuery: false
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
return applyQuery(params, getFirstSectionValueMatchingWithQuery);
|
||||
};
|
||||
const applyNumericEditing = params => {
|
||||
const getNewSectionValue = ({
|
||||
queryValue,
|
||||
skipIfBelowMinimum,
|
||||
section
|
||||
}) => {
|
||||
const cleanQueryValue = removeLocalizedDigits(queryValue, localizedDigits);
|
||||
const queryValueNumber = Number(cleanQueryValue);
|
||||
const sectionBoundaries = sectionsValueBoundaries[section.type]({
|
||||
currentDate: null,
|
||||
format: section.format,
|
||||
contentType: section.contentType
|
||||
});
|
||||
if (queryValueNumber > sectionBoundaries.maximum) {
|
||||
return {
|
||||
saveQuery: false
|
||||
};
|
||||
}
|
||||
|
||||
// If the user types `0` on a month section,
|
||||
// It is below the minimum, but we want to store the `0` in the query,
|
||||
// So that when he pressed `1`, it will store `01` and move to the next section.
|
||||
if (skipIfBelowMinimum && queryValueNumber < sectionBoundaries.minimum) {
|
||||
return {
|
||||
saveQuery: true
|
||||
};
|
||||
}
|
||||
const shouldGoToNextSection = queryValueNumber * 10 > sectionBoundaries.maximum || cleanQueryValue.length === sectionBoundaries.maximum.toString().length;
|
||||
const newSectionValue = cleanDigitSectionValue(adapter, queryValueNumber, sectionBoundaries, localizedDigits, section);
|
||||
return {
|
||||
sectionValue: newSectionValue,
|
||||
shouldGoToNextSection
|
||||
};
|
||||
};
|
||||
const getFirstSectionValueMatchingWithQuery = (queryValue, activeSection) => {
|
||||
if (activeSection.contentType === 'digit' || activeSection.contentType === 'digit-with-letter') {
|
||||
return getNewSectionValue({
|
||||
queryValue,
|
||||
skipIfBelowMinimum: false,
|
||||
section: activeSection
|
||||
});
|
||||
}
|
||||
|
||||
// When editing a letter-format month and the user presses a digit,
|
||||
// We can support the numeric editing by using the digit-format month and re-formatting the result.
|
||||
if (activeSection.type === 'month') {
|
||||
const hasLeadingZerosInFormat = doesSectionFormatHaveLeadingZeros(adapter, 'digit', 'month', 'MM');
|
||||
const response = getNewSectionValue({
|
||||
queryValue,
|
||||
skipIfBelowMinimum: true,
|
||||
section: {
|
||||
type: activeSection.type,
|
||||
format: 'MM',
|
||||
hasLeadingZerosInFormat,
|
||||
hasLeadingZerosInInput: true,
|
||||
contentType: 'digit',
|
||||
maxLength: 2
|
||||
}
|
||||
});
|
||||
if (isQueryResponseWithoutValue(response)) {
|
||||
return response;
|
||||
}
|
||||
const formattedValue = changeSectionValueFormat(adapter, response.sectionValue, 'MM', activeSection.format);
|
||||
return _extends({}, response, {
|
||||
sectionValue: formattedValue
|
||||
});
|
||||
}
|
||||
|
||||
// When editing a letter-format weekDay and the user presses a digit,
|
||||
// We can support the numeric editing by returning the nth day in the week day array.
|
||||
if (activeSection.type === 'weekDay') {
|
||||
const response = getNewSectionValue({
|
||||
queryValue,
|
||||
skipIfBelowMinimum: true,
|
||||
section: activeSection
|
||||
});
|
||||
if (isQueryResponseWithoutValue(response)) {
|
||||
return response;
|
||||
}
|
||||
const formattedValue = getDaysInWeekStr(adapter, activeSection.format)[Number(response.sectionValue) - 1];
|
||||
return _extends({}, response, {
|
||||
sectionValue: formattedValue
|
||||
});
|
||||
}
|
||||
return {
|
||||
saveQuery: false
|
||||
};
|
||||
};
|
||||
return applyQuery(params, getFirstSectionValueMatchingWithQuery, queryValue => isStringNumber(queryValue, localizedDigits));
|
||||
};
|
||||
return useEventCallback(params => {
|
||||
const section = state.sections[params.sectionIndex];
|
||||
const isNumericEditing = isStringNumber(params.keyPressed, localizedDigits);
|
||||
const response = isNumericEditing ? applyNumericEditing(_extends({}, params, {
|
||||
keyPressed: applyLocalizedDigits(params.keyPressed, localizedDigits)
|
||||
})) : applyLetterEditing(params);
|
||||
if (response == null) {
|
||||
setTempAndroidValueStr(null);
|
||||
return;
|
||||
}
|
||||
updateSectionValue({
|
||||
section,
|
||||
newSectionValue: response.sectionValue,
|
||||
shouldGoToNextSection: response.shouldGoToNextSection
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* The letter editing and the numeric editing each define a `CharacterEditingApplier`.
|
||||
* This function decides what the new section value should be and if the focus should switch to the next section.
|
||||
*
|
||||
* If it returns `null`, then the section value is not updated and the focus does not move.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function called by `applyQuery` which decides:
|
||||
* - what is the new section value ?
|
||||
* - should the query used to get this value be stored for the next key press ?
|
||||
*
|
||||
* If it returns `{ sectionValue: string; shouldGoToNextSection: boolean }`,
|
||||
* Then we store the query and update the section with the new value.
|
||||
*
|
||||
* If it returns `{ saveQuery: true` },
|
||||
* Then we store the query and don't update the section.
|
||||
*
|
||||
* If it returns `{ saveQuery: false },
|
||||
* Then we do nothing.
|
||||
*/
|
||||
20
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldHiddenInputProps.d.ts
generated
vendored
Normal file
20
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldHiddenInputProps.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import * as React from 'react';
|
||||
import { PickerManager } from "../../../models/index.js";
|
||||
import { UseFieldStateReturnValue } from "./useFieldState.js";
|
||||
/**
|
||||
* Generate the props to pass to the hidden input element of the field.
|
||||
* It is not used by the non-accessible DOM structure (with an <input /> element for editing).
|
||||
* It should be used in the MUI accessible DOM structure and the Base UI implementation.
|
||||
* @param {UseFieldHiddenInputPropsParameters} parameters The parameters of the hook.
|
||||
* @returns {UseFieldHiddenInputPropsReturnValue} The props to forward to the hidden input element of the field.
|
||||
*/
|
||||
export declare function useFieldHiddenInputProps(parameters: UseFieldHiddenInputPropsParameters): UseFieldHiddenInputPropsReturnValue;
|
||||
interface UseFieldHiddenInputPropsParameters {
|
||||
manager: PickerManager<any, any, any, any, any>;
|
||||
stateResponse: UseFieldStateReturnValue<any>;
|
||||
}
|
||||
interface UseFieldHiddenInputPropsReturnValue {
|
||||
value: string;
|
||||
onChange: React.ChangeEventHandler<HTMLInputElement>;
|
||||
}
|
||||
export {};
|
||||
31
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldHiddenInputProps.js
generated
vendored
Normal file
31
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldHiddenInputProps.js
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import * as React from 'react';
|
||||
import useEventCallback from '@mui/utils/useEventCallback';
|
||||
/**
|
||||
* Generate the props to pass to the hidden input element of the field.
|
||||
* It is not used by the non-accessible DOM structure (with an <input /> element for editing).
|
||||
* It should be used in the MUI accessible DOM structure and the Base UI implementation.
|
||||
* @param {UseFieldHiddenInputPropsParameters} parameters The parameters of the hook.
|
||||
* @returns {UseFieldHiddenInputPropsReturnValue} The props to forward to the hidden input element of the field.
|
||||
*/
|
||||
export function useFieldHiddenInputProps(parameters) {
|
||||
const {
|
||||
manager: {
|
||||
internal_fieldValueManager: fieldValueManager
|
||||
},
|
||||
stateResponse: {
|
||||
// States and derived states
|
||||
areAllSectionsEmpty,
|
||||
state,
|
||||
// Methods to update the states
|
||||
updateValueFromValueStr
|
||||
}
|
||||
} = parameters;
|
||||
const handleChange = useEventCallback(event => {
|
||||
updateValueFromValueStr(event.target.value);
|
||||
});
|
||||
const valueStr = React.useMemo(() => areAllSectionsEmpty ? '' : fieldValueManager.getV7HiddenInputValueFromSections(state.sections), [areAllSectionsEmpty, state.sections, fieldValueManager]);
|
||||
return {
|
||||
value: valueStr,
|
||||
onChange: handleChange
|
||||
};
|
||||
}
|
||||
17
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldInternalPropsWithDefaults.d.ts
generated
vendored
Normal file
17
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldInternalPropsWithDefaults.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { PickerAnyManager, PickerManagerFieldInternalProps, PickerManagerFieldInternalPropsWithDefaults } from "../../models/index.js";
|
||||
/**
|
||||
* Applies the default values to the field internal props.
|
||||
* This is a temporary hook that will be removed during a follow up when `useField` will receive the internal props without the defaults.
|
||||
* It is only here to allow the migration to be done in smaller steps.
|
||||
*/
|
||||
export declare function useFieldInternalPropsWithDefaults<TManager extends PickerAnyManager>(parameters: UseFieldInternalPropsWithDefaultsParameters<TManager>): PickerManagerFieldInternalPropsWithDefaults<TManager>;
|
||||
interface UseFieldInternalPropsWithDefaultsParameters<TManager extends PickerAnyManager> {
|
||||
manager: TManager;
|
||||
internalProps: PickerManagerFieldInternalProps<TManager>;
|
||||
/**
|
||||
* Hack to make sure that on multi input range field, the `useNullableFieldPrivateContext().fieldRef` is only bound to the field matching the range position.
|
||||
* @default false
|
||||
*/
|
||||
skipContextFieldRefAssignment?: boolean;
|
||||
}
|
||||
export {};
|
||||
53
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldInternalPropsWithDefaults.js
generated
vendored
Normal file
53
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldInternalPropsWithDefaults.js
generated
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import _extends from "@babel/runtime/helpers/esm/extends";
|
||||
import * as React from 'react';
|
||||
import useForkRef from '@mui/utils/useForkRef';
|
||||
import { useNullablePickerContext } from "../useNullablePickerContext.js";
|
||||
import { useNullableFieldPrivateContext } from "../useNullableFieldPrivateContext.js";
|
||||
|
||||
/**
|
||||
* Applies the default values to the field internal props.
|
||||
* This is a temporary hook that will be removed during a follow up when `useField` will receive the internal props without the defaults.
|
||||
* It is only here to allow the migration to be done in smaller steps.
|
||||
*/
|
||||
export function useFieldInternalPropsWithDefaults(parameters) {
|
||||
const {
|
||||
manager: {
|
||||
internal_useApplyDefaultValuesToFieldInternalProps: useApplyDefaultValuesToFieldInternalProps
|
||||
},
|
||||
internalProps,
|
||||
skipContextFieldRefAssignment
|
||||
} = parameters;
|
||||
const pickerContext = useNullablePickerContext();
|
||||
const fieldPrivateContext = useNullableFieldPrivateContext();
|
||||
const handleFieldRef = useForkRef(internalProps.unstableFieldRef, skipContextFieldRefAssignment ? null : fieldPrivateContext?.fieldRef);
|
||||
const setValue = pickerContext?.setValue;
|
||||
const handleChangeFromPicker = React.useCallback((newValue, ctx) => {
|
||||
return setValue?.(newValue, {
|
||||
validationError: ctx.validationError,
|
||||
shouldClose: false
|
||||
});
|
||||
}, [setValue]);
|
||||
const internalPropsWithDefaultsFromContext = React.useMemo(() => {
|
||||
// If one of the context is null,
|
||||
// Then the field is used as a standalone component and the other context will be null as well.
|
||||
if (fieldPrivateContext != null && pickerContext != null) {
|
||||
return _extends({
|
||||
value: pickerContext.value,
|
||||
onChange: handleChangeFromPicker,
|
||||
timezone: pickerContext.timezone,
|
||||
disabled: pickerContext.disabled,
|
||||
readOnly: pickerContext.readOnly,
|
||||
autoFocus: pickerContext.autoFocus && !pickerContext.open,
|
||||
focused: pickerContext.open ? true : undefined,
|
||||
format: pickerContext.fieldFormat,
|
||||
formatDensity: fieldPrivateContext.formatDensity,
|
||||
enableAccessibleFieldDOMStructure: fieldPrivateContext.enableAccessibleFieldDOMStructure,
|
||||
selectedSections: fieldPrivateContext.selectedSections,
|
||||
onSelectedSectionsChange: fieldPrivateContext.onSelectedSectionsChange,
|
||||
unstableFieldRef: handleFieldRef
|
||||
}, internalProps);
|
||||
}
|
||||
return internalProps;
|
||||
}, [pickerContext, fieldPrivateContext, internalProps, handleChangeFromPicker, handleFieldRef]);
|
||||
return useApplyDefaultValuesToFieldInternalProps(internalPropsWithDefaultsFromContext);
|
||||
}
|
||||
16
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldRootHandleKeyDown.d.ts
generated
vendored
Normal file
16
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldRootHandleKeyDown.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { PickerManager } from "../../../models/index.js";
|
||||
import { PickerValidValue } from "../../models/index.js";
|
||||
import { UseFieldStateReturnValue } from "./useFieldState.js";
|
||||
import { UseFieldInternalProps } from "./useField.types.js";
|
||||
/**
|
||||
* Returns the `onKeyDown` handler to pass to the root element of the field.
|
||||
*/
|
||||
export declare function useFieldRootHandleKeyDown<TValue extends PickerValidValue>(parameters: UseFieldRootHandleKeyDownParameters<TValue>): (event: React.KeyboardEvent<HTMLSpanElement>) => void;
|
||||
interface UseFieldRootHandleKeyDownParameters<TValue extends PickerValidValue> {
|
||||
manager: PickerManager<TValue, any, any, any, any>;
|
||||
stateResponse: UseFieldStateReturnValue<TValue>;
|
||||
internalPropsWithDefaults: UseFieldInternalProps<TValue, any, any> & {
|
||||
minutesStep?: number;
|
||||
};
|
||||
}
|
||||
export {};
|
||||
205
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldRootHandleKeyDown.js
generated
vendored
Normal file
205
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldRootHandleKeyDown.js
generated
vendored
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
import useEventCallback from '@mui/utils/useEventCallback';
|
||||
import { cleanDigitSectionValue, getLetterEditingOptions, removeLocalizedDigits } from "./useField.utils.js";
|
||||
import { usePickerAdapter } from "../../../hooks/usePickerAdapter.js";
|
||||
|
||||
/**
|
||||
* Returns the `onKeyDown` handler to pass to the root element of the field.
|
||||
*/
|
||||
export function useFieldRootHandleKeyDown(parameters) {
|
||||
const adapter = usePickerAdapter();
|
||||
const {
|
||||
manager: {
|
||||
internal_fieldValueManager: fieldValueManager
|
||||
},
|
||||
internalPropsWithDefaults: {
|
||||
minutesStep,
|
||||
disabled,
|
||||
readOnly
|
||||
},
|
||||
stateResponse: {
|
||||
// States and derived states
|
||||
state,
|
||||
value,
|
||||
activeSectionIndex,
|
||||
parsedSelectedSections,
|
||||
sectionsValueBoundaries,
|
||||
localizedDigits,
|
||||
timezone,
|
||||
sectionOrder,
|
||||
// Methods to update the states
|
||||
clearValue,
|
||||
clearActiveSection,
|
||||
setSelectedSections,
|
||||
updateSectionValue
|
||||
}
|
||||
} = parameters;
|
||||
return useEventCallback(event => {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line default-case
|
||||
switch (true) {
|
||||
// Select all
|
||||
case (event.ctrlKey || event.metaKey) && String.fromCharCode(event.keyCode) === 'A' && !event.shiftKey && !event.altKey:
|
||||
{
|
||||
// prevent default to make sure that the next line "select all" while updating
|
||||
// the internal state at the same time.
|
||||
event.preventDefault();
|
||||
setSelectedSections('all');
|
||||
break;
|
||||
}
|
||||
|
||||
// Move selection to next section
|
||||
case event.key === 'ArrowRight':
|
||||
{
|
||||
event.preventDefault();
|
||||
if (parsedSelectedSections == null) {
|
||||
setSelectedSections(sectionOrder.startIndex);
|
||||
} else if (parsedSelectedSections === 'all') {
|
||||
setSelectedSections(sectionOrder.endIndex);
|
||||
} else {
|
||||
const nextSectionIndex = sectionOrder.neighbors[parsedSelectedSections].rightIndex;
|
||||
if (nextSectionIndex !== null) {
|
||||
setSelectedSections(nextSectionIndex);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Move selection to previous section
|
||||
case event.key === 'ArrowLeft':
|
||||
{
|
||||
event.preventDefault();
|
||||
if (parsedSelectedSections == null) {
|
||||
setSelectedSections(sectionOrder.endIndex);
|
||||
} else if (parsedSelectedSections === 'all') {
|
||||
setSelectedSections(sectionOrder.startIndex);
|
||||
} else {
|
||||
const nextSectionIndex = sectionOrder.neighbors[parsedSelectedSections].leftIndex;
|
||||
if (nextSectionIndex !== null) {
|
||||
setSelectedSections(nextSectionIndex);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Reset the value of the selected section
|
||||
case event.key === 'Delete':
|
||||
{
|
||||
event.preventDefault();
|
||||
if (readOnly) {
|
||||
break;
|
||||
}
|
||||
if (parsedSelectedSections == null || parsedSelectedSections === 'all') {
|
||||
clearValue();
|
||||
} else {
|
||||
clearActiveSection();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Increment / decrement the selected section value
|
||||
case ['ArrowUp', 'ArrowDown', 'Home', 'End', 'PageUp', 'PageDown'].includes(event.key):
|
||||
{
|
||||
event.preventDefault();
|
||||
if (readOnly || activeSectionIndex == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
// if all sections are selected, mark the currently editing one as selected
|
||||
if (parsedSelectedSections === 'all') {
|
||||
setSelectedSections(activeSectionIndex);
|
||||
}
|
||||
const activeSection = state.sections[activeSectionIndex];
|
||||
const newSectionValue = adjustSectionValue(adapter, timezone, activeSection, event.key, sectionsValueBoundaries, localizedDigits, fieldValueManager.getDateFromSection(value, activeSection), {
|
||||
minutesStep
|
||||
});
|
||||
updateSectionValue({
|
||||
section: activeSection,
|
||||
newSectionValue,
|
||||
shouldGoToNextSection: false
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function getDeltaFromKeyCode(keyCode) {
|
||||
switch (keyCode) {
|
||||
case 'ArrowUp':
|
||||
return 1;
|
||||
case 'ArrowDown':
|
||||
return -1;
|
||||
case 'PageUp':
|
||||
return 5;
|
||||
case 'PageDown':
|
||||
return -5;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
function adjustSectionValue(adapter, timezone, section, keyCode, sectionsValueBoundaries, localizedDigits, activeDate, stepsAttributes) {
|
||||
const delta = getDeltaFromKeyCode(keyCode);
|
||||
const isStart = keyCode === 'Home';
|
||||
const isEnd = keyCode === 'End';
|
||||
const shouldSetAbsolute = section.value === '' || isStart || isEnd;
|
||||
const adjustDigitSection = () => {
|
||||
const sectionBoundaries = sectionsValueBoundaries[section.type]({
|
||||
currentDate: activeDate,
|
||||
format: section.format,
|
||||
contentType: section.contentType
|
||||
});
|
||||
const getCleanValue = value => cleanDigitSectionValue(adapter, value, sectionBoundaries, localizedDigits, section);
|
||||
const step = section.type === 'minutes' && stepsAttributes?.minutesStep ? stepsAttributes.minutesStep : 1;
|
||||
let newSectionValueNumber;
|
||||
if (shouldSetAbsolute) {
|
||||
if (section.type === 'year' && !isEnd && !isStart) {
|
||||
return adapter.formatByString(adapter.date(undefined, timezone), section.format);
|
||||
}
|
||||
if (delta > 0 || isStart) {
|
||||
newSectionValueNumber = sectionBoundaries.minimum;
|
||||
} else {
|
||||
newSectionValueNumber = sectionBoundaries.maximum;
|
||||
}
|
||||
} else {
|
||||
const currentSectionValue = parseInt(removeLocalizedDigits(section.value, localizedDigits), 10);
|
||||
newSectionValueNumber = currentSectionValue + delta * step;
|
||||
}
|
||||
if (newSectionValueNumber % step !== 0) {
|
||||
if (delta < 0 || isStart) {
|
||||
newSectionValueNumber += step - (step + newSectionValueNumber) % step; // for JS -3 % 5 = -3 (should be 2)
|
||||
}
|
||||
if (delta > 0 || isEnd) {
|
||||
newSectionValueNumber -= newSectionValueNumber % step;
|
||||
}
|
||||
}
|
||||
if (newSectionValueNumber > sectionBoundaries.maximum) {
|
||||
return getCleanValue(sectionBoundaries.minimum + (newSectionValueNumber - sectionBoundaries.maximum - 1) % (sectionBoundaries.maximum - sectionBoundaries.minimum + 1));
|
||||
}
|
||||
if (newSectionValueNumber < sectionBoundaries.minimum) {
|
||||
return getCleanValue(sectionBoundaries.maximum - (sectionBoundaries.minimum - newSectionValueNumber - 1) % (sectionBoundaries.maximum - sectionBoundaries.minimum + 1));
|
||||
}
|
||||
return getCleanValue(newSectionValueNumber);
|
||||
};
|
||||
const adjustLetterSection = () => {
|
||||
const options = getLetterEditingOptions(adapter, timezone, section.type, section.format);
|
||||
if (options.length === 0) {
|
||||
return section.value;
|
||||
}
|
||||
if (shouldSetAbsolute) {
|
||||
if (delta > 0 || isStart) {
|
||||
return options[0];
|
||||
}
|
||||
return options[options.length - 1];
|
||||
}
|
||||
const currentOptionIndex = options.indexOf(section.value);
|
||||
const newOptionIndex = (currentOptionIndex + delta) % options.length;
|
||||
const clampedIndex = (newOptionIndex + options.length) % options.length;
|
||||
return options[clampedIndex];
|
||||
};
|
||||
if (section.contentType === 'digit' || section.contentType === 'digit-with-letter') {
|
||||
return adjustDigitSection();
|
||||
}
|
||||
return adjustLetterSection();
|
||||
}
|
||||
32
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldRootProps.d.ts
generated
vendored
Normal file
32
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldRootProps.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { PickerManager } from "../../../models/index.js";
|
||||
import { UseFieldDOMGetters, UseFieldInternalProps } from "./useField.types.js";
|
||||
import { UseFieldStateReturnValue } from "./useFieldState.js";
|
||||
import { UseFieldCharacterEditingReturnValue } from "./useFieldCharacterEditing.js";
|
||||
/**
|
||||
* Generate the props to pass to the root element of the field.
|
||||
* It is not used by the non-accessible DOM structure (with an <input /> element for editing).
|
||||
* It should be used in the MUI accessible DOM structure and the Base UI implementation.
|
||||
* @param {UseFieldRootPropsParameters} parameters The parameters of the hook.
|
||||
* @returns {UseFieldRootPropsReturnValue} The props to forward to the root element of the field.
|
||||
*/
|
||||
export declare function useFieldRootProps(parameters: UseFieldRootPropsParameters): UseFieldRootPropsReturnValue;
|
||||
interface UseFieldRootPropsParameters {
|
||||
manager: PickerManager<any, any, any, any, any>;
|
||||
stateResponse: UseFieldStateReturnValue<any>;
|
||||
applyCharacterEditing: UseFieldCharacterEditingReturnValue;
|
||||
internalPropsWithDefaults: UseFieldInternalProps<any, any, any>;
|
||||
domGetters: UseFieldDOMGetters;
|
||||
focused: boolean;
|
||||
setFocused: (focused: boolean) => void;
|
||||
}
|
||||
interface UseFieldRootPropsReturnValue {
|
||||
onKeyDown: React.KeyboardEventHandler<HTMLDivElement>;
|
||||
onBlur: React.FocusEventHandler<HTMLDivElement>;
|
||||
onFocus: React.FocusEventHandler<HTMLDivElement>;
|
||||
onClick: React.MouseEventHandler<HTMLDivElement>;
|
||||
onPaste: React.ClipboardEventHandler<HTMLDivElement>;
|
||||
onInput: React.FormEventHandler<HTMLDivElement>;
|
||||
contentEditable: boolean;
|
||||
tabIndex: number;
|
||||
}
|
||||
export {};
|
||||
151
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldRootProps.js
generated
vendored
Normal file
151
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldRootProps.js
generated
vendored
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
import useEventCallback from '@mui/utils/useEventCallback';
|
||||
import useTimeout from '@mui/utils/useTimeout';
|
||||
import { useFieldRootHandleKeyDown } from "./useFieldRootHandleKeyDown.js";
|
||||
import { getActiveElement } from "../../utils/utils.js";
|
||||
import { syncSelectionToDOM } from "./syncSelectionToDOM.js";
|
||||
|
||||
/**
|
||||
* Generate the props to pass to the root element of the field.
|
||||
* It is not used by the non-accessible DOM structure (with an <input /> element for editing).
|
||||
* It should be used in the MUI accessible DOM structure and the Base UI implementation.
|
||||
* @param {UseFieldRootPropsParameters} parameters The parameters of the hook.
|
||||
* @returns {UseFieldRootPropsReturnValue} The props to forward to the root element of the field.
|
||||
*/
|
||||
export function useFieldRootProps(parameters) {
|
||||
const {
|
||||
manager,
|
||||
focused,
|
||||
setFocused,
|
||||
domGetters,
|
||||
stateResponse,
|
||||
applyCharacterEditing,
|
||||
internalPropsWithDefaults,
|
||||
stateResponse: {
|
||||
// States and derived states
|
||||
parsedSelectedSections,
|
||||
sectionOrder,
|
||||
state,
|
||||
// Methods to update the states
|
||||
clearValue,
|
||||
setCharacterQuery,
|
||||
setSelectedSections,
|
||||
updateValueFromValueStr
|
||||
},
|
||||
internalPropsWithDefaults: {
|
||||
disabled = false,
|
||||
readOnly = false
|
||||
}
|
||||
} = parameters;
|
||||
|
||||
// TODO: Inline onContainerKeyDown once the old DOM structure is removed
|
||||
const handleKeyDown = useFieldRootHandleKeyDown({
|
||||
manager,
|
||||
internalPropsWithDefaults,
|
||||
stateResponse
|
||||
});
|
||||
const containerClickTimeout = useTimeout();
|
||||
const handleClick = useEventCallback(event => {
|
||||
if (disabled || !domGetters.isReady()) {
|
||||
return;
|
||||
}
|
||||
setFocused(true);
|
||||
if (parsedSelectedSections === 'all') {
|
||||
containerClickTimeout.start(0, () => {
|
||||
const cursorPosition = document.getSelection().getRangeAt(0).startOffset;
|
||||
if (cursorPosition === 0) {
|
||||
setSelectedSections(sectionOrder.startIndex);
|
||||
return;
|
||||
}
|
||||
let sectionIndex = 0;
|
||||
let cursorOnStartOfSection = 0;
|
||||
while (cursorOnStartOfSection < cursorPosition && sectionIndex < state.sections.length) {
|
||||
const section = state.sections[sectionIndex];
|
||||
sectionIndex += 1;
|
||||
cursorOnStartOfSection += `${section.startSeparator}${section.value || section.placeholder}${section.endSeparator}`.length;
|
||||
}
|
||||
setSelectedSections(sectionIndex - 1);
|
||||
});
|
||||
} else if (!focused) {
|
||||
setFocused(true);
|
||||
setSelectedSections(sectionOrder.startIndex);
|
||||
} else {
|
||||
const hasClickedOnASection = domGetters.getRoot().contains(event.target);
|
||||
if (!hasClickedOnASection) {
|
||||
setSelectedSections(sectionOrder.startIndex);
|
||||
}
|
||||
}
|
||||
});
|
||||
const handleInput = useEventCallback(event => {
|
||||
if (!domGetters.isReady() || parsedSelectedSections !== 'all') {
|
||||
return;
|
||||
}
|
||||
const target = event.target;
|
||||
const keyPressed = target.textContent ?? '';
|
||||
domGetters.getRoot().innerHTML = state.sections.map(section => `${section.startSeparator}${section.value || section.placeholder}${section.endSeparator}`).join('');
|
||||
syncSelectionToDOM({
|
||||
focused,
|
||||
domGetters,
|
||||
stateResponse
|
||||
});
|
||||
if (keyPressed.length === 0 || keyPressed.charCodeAt(0) === 10) {
|
||||
clearValue();
|
||||
setSelectedSections('all');
|
||||
} else if (keyPressed.length > 1) {
|
||||
updateValueFromValueStr(keyPressed);
|
||||
} else {
|
||||
if (parsedSelectedSections === 'all') {
|
||||
setSelectedSections(0);
|
||||
}
|
||||
applyCharacterEditing({
|
||||
keyPressed,
|
||||
sectionIndex: 0
|
||||
});
|
||||
}
|
||||
});
|
||||
const handlePaste = useEventCallback(event => {
|
||||
if (readOnly || parsedSelectedSections !== 'all') {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
const pastedValue = event.clipboardData.getData('text');
|
||||
event.preventDefault();
|
||||
setCharacterQuery(null);
|
||||
updateValueFromValueStr(pastedValue);
|
||||
});
|
||||
const handleFocus = useEventCallback(() => {
|
||||
if (focused || disabled || !domGetters.isReady()) {
|
||||
return;
|
||||
}
|
||||
const activeElement = getActiveElement(domGetters.getRoot());
|
||||
setFocused(true);
|
||||
const isFocusInsideASection = domGetters.getSectionIndexFromDOMElement(activeElement) != null;
|
||||
if (!isFocusInsideASection) {
|
||||
setSelectedSections(sectionOrder.startIndex);
|
||||
}
|
||||
});
|
||||
const handleBlur = useEventCallback(() => {
|
||||
setTimeout(() => {
|
||||
if (!domGetters.isReady()) {
|
||||
return;
|
||||
}
|
||||
const activeElement = getActiveElement(domGetters.getRoot());
|
||||
const shouldBlur = !domGetters.getRoot().contains(activeElement);
|
||||
if (shouldBlur) {
|
||||
setFocused(false);
|
||||
setSelectedSections(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
return {
|
||||
// Event handlers
|
||||
onKeyDown: handleKeyDown,
|
||||
onBlur: handleBlur,
|
||||
onFocus: handleFocus,
|
||||
onClick: handleClick,
|
||||
onPaste: handlePaste,
|
||||
onInput: handleInput,
|
||||
// Other
|
||||
contentEditable: parsedSelectedSections === 'all',
|
||||
tabIndex: parsedSelectedSections === 0 ? -1 : 0 // TODO: Try to set to undefined when there is a section selected.
|
||||
};
|
||||
}
|
||||
17
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldSectionContainerProps.d.ts
generated
vendored
Normal file
17
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldSectionContainerProps.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import * as React from 'react';
|
||||
import { UseFieldStateReturnValue } from "./useFieldState.js";
|
||||
import { UseFieldInternalProps } from "./useField.types.js";
|
||||
/**
|
||||
* Generate the props to pass to the container element of each section of the field.
|
||||
* It is not used by the non-accessible DOM structure (with an <input /> element for editing).
|
||||
* It should be used in the MUI accessible DOM structure and the Base UI implementation.
|
||||
* @param {UseFieldRootPropsParameters} parameters The parameters of the hook.
|
||||
* @returns {UseFieldRootPropsReturnValue} The props to forward to the container element of each section of the field.
|
||||
*/
|
||||
export declare function useFieldSectionContainerProps(parameters: UseFieldSectionContainerPropsParameters): UseFieldSectionContainerPropsReturnValue;
|
||||
interface UseFieldSectionContainerPropsParameters {
|
||||
stateResponse: UseFieldStateReturnValue<any>;
|
||||
internalPropsWithDefaults: UseFieldInternalProps<any, any, any>;
|
||||
}
|
||||
type UseFieldSectionContainerPropsReturnValue = (sectionIndex: number) => React.HTMLAttributes<HTMLSpanElement>;
|
||||
export {};
|
||||
31
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldSectionContainerProps.js
generated
vendored
Normal file
31
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldSectionContainerProps.js
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import * as React from 'react';
|
||||
/**
|
||||
* Generate the props to pass to the container element of each section of the field.
|
||||
* It is not used by the non-accessible DOM structure (with an <input /> element for editing).
|
||||
* It should be used in the MUI accessible DOM structure and the Base UI implementation.
|
||||
* @param {UseFieldRootPropsParameters} parameters The parameters of the hook.
|
||||
* @returns {UseFieldRootPropsReturnValue} The props to forward to the container element of each section of the field.
|
||||
*/
|
||||
export function useFieldSectionContainerProps(parameters) {
|
||||
const {
|
||||
stateResponse: {
|
||||
// Methods to update the states
|
||||
setSelectedSections
|
||||
},
|
||||
internalPropsWithDefaults: {
|
||||
disabled = false
|
||||
}
|
||||
} = parameters;
|
||||
const createHandleClick = React.useCallback(sectionIndex => event => {
|
||||
// The click event on the clear button would propagate to the input, trigger this handler and result in a wrong section selection.
|
||||
// We avoid this by checking if the call to this function is actually intended, or a side effect.
|
||||
if (disabled || event.isDefaultPrevented()) {
|
||||
return;
|
||||
}
|
||||
setSelectedSections(sectionIndex);
|
||||
}, [disabled, setSelectedSections]);
|
||||
return React.useCallback(sectionIndex => ({
|
||||
'data-sectionindex': sectionIndex,
|
||||
onClick: createHandleClick(sectionIndex)
|
||||
}), [createHandleClick]);
|
||||
}
|
||||
23
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldSectionContentProps.d.ts
generated
vendored
Normal file
23
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldSectionContentProps.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { UseFieldStateReturnValue } from "./useFieldState.js";
|
||||
import { FieldSection, PickerManager } from "../../../models/index.js";
|
||||
import { UseFieldDOMGetters, UseFieldInternalProps } from "./useField.types.js";
|
||||
import { UseFieldCharacterEditingReturnValue } from "./useFieldCharacterEditing.js";
|
||||
import { PickersSectionElement } from "../../../PickersSectionList/index.js";
|
||||
/**
|
||||
* Generate the props to pass to the content element of each section of the field.
|
||||
* It is not used by the non-accessible DOM structure (with an <input /> element for editing).
|
||||
* It should be used in the MUI accessible DOM structure and the Base UI implementation.
|
||||
* @param {UseFieldRootPropsParameters} parameters The parameters of the hook.
|
||||
* @returns {UseFieldRootPropsReturnValue} The props to forward to the content element of each section of the field.
|
||||
*/
|
||||
export declare function useFieldSectionContentProps(parameters: UseFieldSectionContentPropsParameters): UseFieldSectionContentPropsReturnValue;
|
||||
interface UseFieldSectionContentPropsParameters {
|
||||
manager: PickerManager<any, any, any, any, any>;
|
||||
stateResponse: UseFieldStateReturnValue<any>;
|
||||
applyCharacterEditing: UseFieldCharacterEditingReturnValue;
|
||||
internalPropsWithDefaults: UseFieldInternalProps<any, any, any>;
|
||||
domGetters: UseFieldDOMGetters;
|
||||
focused: boolean;
|
||||
}
|
||||
type UseFieldSectionContentPropsReturnValue = (section: FieldSection, sectionIndex: number) => PickersSectionElement['content'];
|
||||
export {};
|
||||
228
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldSectionContentProps.js
generated
vendored
Normal file
228
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldSectionContentProps.js
generated
vendored
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
import * as React from 'react';
|
||||
import useEventCallback from '@mui/utils/useEventCallback';
|
||||
import useId from '@mui/utils/useId';
|
||||
import { usePickerAdapter, usePickerTranslations } from "../../../hooks/index.js";
|
||||
import { syncSelectionToDOM } from "./syncSelectionToDOM.js";
|
||||
/**
|
||||
* Generate the props to pass to the content element of each section of the field.
|
||||
* It is not used by the non-accessible DOM structure (with an <input /> element for editing).
|
||||
* It should be used in the MUI accessible DOM structure and the Base UI implementation.
|
||||
* @param {UseFieldRootPropsParameters} parameters The parameters of the hook.
|
||||
* @returns {UseFieldRootPropsReturnValue} The props to forward to the content element of each section of the field.
|
||||
*/
|
||||
export function useFieldSectionContentProps(parameters) {
|
||||
const adapter = usePickerAdapter();
|
||||
const translations = usePickerTranslations();
|
||||
const id = useId();
|
||||
const {
|
||||
focused,
|
||||
domGetters,
|
||||
stateResponse,
|
||||
applyCharacterEditing,
|
||||
manager: {
|
||||
internal_fieldValueManager: fieldValueManager
|
||||
},
|
||||
stateResponse: {
|
||||
// States and derived states
|
||||
parsedSelectedSections,
|
||||
sectionsValueBoundaries,
|
||||
state,
|
||||
value,
|
||||
// Methods to update the states
|
||||
clearActiveSection,
|
||||
setCharacterQuery,
|
||||
setSelectedSections,
|
||||
updateSectionValue,
|
||||
updateValueFromValueStr
|
||||
},
|
||||
internalPropsWithDefaults: {
|
||||
disabled = false,
|
||||
readOnly = false
|
||||
}
|
||||
} = parameters;
|
||||
const isContainerEditable = parsedSelectedSections === 'all';
|
||||
const isEditable = !isContainerEditable && !disabled && !readOnly;
|
||||
|
||||
/**
|
||||
* If a section content has been updated with a value we don't want to keep,
|
||||
* Then we need to imperatively revert it (we can't let React do it because the value did not change in his internal representation).
|
||||
*/
|
||||
const revertDOMSectionChange = useEventCallback(sectionIndex => {
|
||||
if (!domGetters.isReady()) {
|
||||
return;
|
||||
}
|
||||
const section = state.sections[sectionIndex];
|
||||
domGetters.getSectionContent(sectionIndex).innerHTML = section.value || section.placeholder;
|
||||
syncSelectionToDOM({
|
||||
focused,
|
||||
domGetters,
|
||||
stateResponse
|
||||
});
|
||||
});
|
||||
const handleInput = useEventCallback(event => {
|
||||
if (!domGetters.isReady()) {
|
||||
return;
|
||||
}
|
||||
const target = event.target;
|
||||
const keyPressed = target.textContent ?? '';
|
||||
const sectionIndex = domGetters.getSectionIndexFromDOMElement(target);
|
||||
const section = state.sections[sectionIndex];
|
||||
if (readOnly) {
|
||||
revertDOMSectionChange(sectionIndex);
|
||||
return;
|
||||
}
|
||||
if (keyPressed.length === 0) {
|
||||
if (section.value === '') {
|
||||
revertDOMSectionChange(sectionIndex);
|
||||
return;
|
||||
}
|
||||
const inputType = event.nativeEvent.inputType;
|
||||
if (inputType === 'insertParagraph' || inputType === 'insertLineBreak') {
|
||||
revertDOMSectionChange(sectionIndex);
|
||||
return;
|
||||
}
|
||||
revertDOMSectionChange(sectionIndex);
|
||||
clearActiveSection();
|
||||
return;
|
||||
}
|
||||
applyCharacterEditing({
|
||||
keyPressed,
|
||||
sectionIndex
|
||||
});
|
||||
|
||||
// The DOM value needs to remain the one React is expecting.
|
||||
revertDOMSectionChange(sectionIndex);
|
||||
});
|
||||
const handleMouseUp = useEventCallback(event => {
|
||||
// Without this, the browser will remove the selected when clicking inside an already-selected section.
|
||||
event.preventDefault();
|
||||
});
|
||||
const handlePaste = useEventCallback(event => {
|
||||
// prevent default to avoid the input `onInput` handler being called
|
||||
event.preventDefault();
|
||||
if (readOnly || disabled || typeof parsedSelectedSections !== 'number') {
|
||||
return;
|
||||
}
|
||||
const activeSection = state.sections[parsedSelectedSections];
|
||||
const pastedValue = event.clipboardData.getData('text');
|
||||
const lettersOnly = /^[a-zA-Z]+$/.test(pastedValue);
|
||||
const digitsOnly = /^[0-9]+$/.test(pastedValue);
|
||||
const digitsAndLetterOnly = /^(([a-zA-Z]+)|)([0-9]+)(([a-zA-Z]+)|)$/.test(pastedValue);
|
||||
const isValidPastedValue = activeSection.contentType === 'letter' && lettersOnly || activeSection.contentType === 'digit' && digitsOnly || activeSection.contentType === 'digit-with-letter' && digitsAndLetterOnly;
|
||||
if (isValidPastedValue) {
|
||||
setCharacterQuery(null);
|
||||
updateSectionValue({
|
||||
section: activeSection,
|
||||
newSectionValue: pastedValue,
|
||||
shouldGoToNextSection: true
|
||||
});
|
||||
}
|
||||
// If the pasted value corresponds to a single section, but not the expected type, we skip the modification
|
||||
else if (!lettersOnly && !digitsOnly) {
|
||||
setCharacterQuery(null);
|
||||
updateValueFromValueStr(pastedValue);
|
||||
}
|
||||
});
|
||||
const handleDragOver = useEventCallback(event => {
|
||||
event.preventDefault();
|
||||
event.dataTransfer.dropEffect = 'none';
|
||||
});
|
||||
const createFocusHandler = React.useCallback(sectionIndex => () => {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
setSelectedSections(sectionIndex);
|
||||
}, [disabled, setSelectedSections]);
|
||||
return React.useCallback((section, sectionIndex) => {
|
||||
const sectionBoundaries = sectionsValueBoundaries[section.type]({
|
||||
currentDate: fieldValueManager.getDateFromSection(value, section),
|
||||
contentType: section.contentType,
|
||||
format: section.format
|
||||
});
|
||||
return {
|
||||
// Event handlers
|
||||
onInput: handleInput,
|
||||
onPaste: handlePaste,
|
||||
onMouseUp: handleMouseUp,
|
||||
onDragOver: handleDragOver,
|
||||
onFocus: createFocusHandler(sectionIndex),
|
||||
// Aria attributes
|
||||
'aria-labelledby': `${id}-${section.type}`,
|
||||
'aria-readonly': readOnly,
|
||||
'aria-valuenow': getSectionValueNow(section, adapter),
|
||||
'aria-valuemin': sectionBoundaries.minimum,
|
||||
'aria-valuemax': sectionBoundaries.maximum,
|
||||
'aria-valuetext': section.value ? getSectionValueText(section, adapter) : translations.empty,
|
||||
'aria-label': translations[section.type],
|
||||
'aria-disabled': disabled,
|
||||
// Other
|
||||
tabIndex: isContainerEditable || sectionIndex > 0 ? -1 : 0,
|
||||
contentEditable: !isContainerEditable && !disabled && !readOnly,
|
||||
role: 'spinbutton',
|
||||
id: `${id}-${section.type}`,
|
||||
'data-range-position': section.dateName || undefined,
|
||||
spellCheck: isEditable ? false : undefined,
|
||||
autoCapitalize: isEditable ? 'off' : undefined,
|
||||
autoCorrect: isEditable ? 'off' : undefined,
|
||||
children: section.value || section.placeholder,
|
||||
inputMode: section.contentType === 'letter' ? 'text' : 'numeric'
|
||||
};
|
||||
}, [sectionsValueBoundaries, id, isContainerEditable, disabled, readOnly, isEditable, translations, adapter, handleInput, handlePaste, handleMouseUp, handleDragOver, createFocusHandler, fieldValueManager, value]);
|
||||
}
|
||||
function getSectionValueText(section, adapter) {
|
||||
if (!section.value) {
|
||||
return undefined;
|
||||
}
|
||||
switch (section.type) {
|
||||
case 'month':
|
||||
{
|
||||
if (section.contentType === 'digit') {
|
||||
return adapter.format(adapter.setMonth(adapter.date(), Number(section.value) - 1), 'month');
|
||||
}
|
||||
const parsedDate = adapter.parse(section.value, section.format);
|
||||
return parsedDate ? adapter.format(parsedDate, 'month') : undefined;
|
||||
}
|
||||
case 'day':
|
||||
return section.contentType === 'digit' ? adapter.format(adapter.setDate(adapter.startOfYear(adapter.date()), Number(section.value)), 'dayOfMonthFull') : section.value;
|
||||
case 'weekDay':
|
||||
// TODO: improve by providing the label of the week day
|
||||
return undefined;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
function getSectionValueNow(section, adapter) {
|
||||
if (!section.value) {
|
||||
return undefined;
|
||||
}
|
||||
switch (section.type) {
|
||||
case 'weekDay':
|
||||
{
|
||||
if (section.contentType === 'letter') {
|
||||
// TODO: improve by resolving the week day number from a letter week day
|
||||
return undefined;
|
||||
}
|
||||
return Number(section.value);
|
||||
}
|
||||
case 'meridiem':
|
||||
{
|
||||
const parsedDate = adapter.parse(`01:00 ${section.value}`, `${adapter.formats.hours12h}:${adapter.formats.minutes} ${section.format}`);
|
||||
if (parsedDate) {
|
||||
return adapter.getHours(parsedDate) >= 12 ? 1 : 0;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
case 'day':
|
||||
return section.contentType === 'digit-with-letter' ? parseInt(section.value, 10) : Number(section.value);
|
||||
case 'month':
|
||||
{
|
||||
if (section.contentType === 'digit') {
|
||||
return Number(section.value);
|
||||
}
|
||||
const parsedDate = adapter.parse(section.value, section.format);
|
||||
return parsedDate ? adapter.getMonth(parsedDate) + 1 : undefined;
|
||||
}
|
||||
default:
|
||||
return section.contentType !== 'letter' ? Number(section.value) : undefined;
|
||||
}
|
||||
}
|
||||
44
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldState.d.ts
generated
vendored
Normal file
44
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldState.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { UseFieldInternalProps, UseFieldState, FieldParsedSelectedSections, FieldSectionsValueBoundaries, SectionOrdering, UseFieldForwardedProps, CharacterEditingQuery } from "./useField.types.js";
|
||||
import { FieldSelectedSections, PickersTimezone, InferFieldSection, PickerManager } from "../../../models/index.js";
|
||||
import { PickerValidValue } from "../../models/index.js";
|
||||
export declare const useFieldState: <TValue extends PickerValidValue, TEnableAccessibleFieldDOMStructure extends boolean, TError, TValidationProps extends {}, TForwardedProps extends UseFieldForwardedProps<TEnableAccessibleFieldDOMStructure>>(parameters: UseFieldStateParameters<TValue, TEnableAccessibleFieldDOMStructure, TError, TValidationProps, TForwardedProps>) => UseFieldStateReturnValue<TValue>;
|
||||
interface UseFieldStateParameters<TValue extends PickerValidValue, TEnableAccessibleFieldDOMStructure extends boolean, TError, TValidationProps extends {}, TForwardedProps extends UseFieldForwardedProps<TEnableAccessibleFieldDOMStructure>> {
|
||||
manager: PickerManager<TValue, TEnableAccessibleFieldDOMStructure, TError, TValidationProps, any>;
|
||||
internalPropsWithDefaults: UseFieldInternalProps<TValue, TEnableAccessibleFieldDOMStructure, TError> & TValidationProps;
|
||||
forwardedProps: TForwardedProps;
|
||||
}
|
||||
export interface UpdateSectionValueParameters<TValue extends PickerValidValue> {
|
||||
/**
|
||||
* The section on which we want to apply the new value.
|
||||
*/
|
||||
section: InferFieldSection<TValue>;
|
||||
/**
|
||||
* Value to apply to the active section.
|
||||
*/
|
||||
newSectionValue: string;
|
||||
/**
|
||||
* If `true`, the focus will move to the next section.
|
||||
*/
|
||||
shouldGoToNextSection: boolean;
|
||||
}
|
||||
export interface UseFieldStateReturnValue<TValue extends PickerValidValue> {
|
||||
activeSectionIndex: number | null;
|
||||
areAllSectionsEmpty: boolean;
|
||||
error: boolean;
|
||||
localizedDigits: string[];
|
||||
parsedSelectedSections: FieldParsedSelectedSections;
|
||||
sectionOrder: SectionOrdering;
|
||||
sectionsValueBoundaries: FieldSectionsValueBoundaries;
|
||||
state: UseFieldState<TValue>;
|
||||
timezone: PickersTimezone;
|
||||
value: TValue;
|
||||
clearValue: () => void;
|
||||
clearActiveSection: () => void;
|
||||
setCharacterQuery: (characterQuery: CharacterEditingQuery | null) => void;
|
||||
setSelectedSections: (sections: FieldSelectedSections) => void;
|
||||
setTempAndroidValueStr: (tempAndroidValueStr: string | null) => void;
|
||||
updateSectionValue: (parameters: UpdateSectionValueParameters<TValue>) => void;
|
||||
updateValueFromValueStr: (valueStr: string) => void;
|
||||
getSectionsFromValue: (value: TValue, fallbackSections?: InferFieldSection<TValue>[] | null) => InferFieldSection<TValue>[];
|
||||
}
|
||||
export {};
|
||||
392
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldState.js
generated
vendored
Normal file
392
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldState.js
generated
vendored
Normal file
|
|
@ -0,0 +1,392 @@
|
|||
'use client';
|
||||
|
||||
import _extends from "@babel/runtime/helpers/esm/extends";
|
||||
import * as React from 'react';
|
||||
import useControlled from '@mui/utils/useControlled';
|
||||
import useTimeout from '@mui/utils/useTimeout';
|
||||
import useEventCallback from '@mui/utils/useEventCallback';
|
||||
import { useRtl } from '@mui/system/RtlProvider';
|
||||
import { usePickerAdapter, usePickerTranslations } from "../../../hooks/index.js";
|
||||
import { mergeDateIntoReferenceDate, getSectionsBoundaries, validateSections, getDateFromDateSections, parseSelectedSections, getLocalizedDigits, getSectionOrder } from "./useField.utils.js";
|
||||
import { buildSectionsFromFormat } from "./buildSectionsFromFormat.js";
|
||||
import { useValidation } from "../../../validation/index.js";
|
||||
import { useControlledValue } from "../useControlledValue.js";
|
||||
import { getSectionTypeGranularity } from "../../utils/getDefaultReferenceDate.js";
|
||||
const QUERY_LIFE_DURATION_MS = 5000;
|
||||
export const useFieldState = parameters => {
|
||||
const adapter = usePickerAdapter();
|
||||
const translations = usePickerTranslations();
|
||||
const isRtl = useRtl();
|
||||
const {
|
||||
manager: {
|
||||
validator,
|
||||
valueType,
|
||||
internal_valueManager: valueManager,
|
||||
internal_fieldValueManager: fieldValueManager
|
||||
},
|
||||
internalPropsWithDefaults,
|
||||
internalPropsWithDefaults: {
|
||||
value: valueProp,
|
||||
defaultValue,
|
||||
referenceDate: referenceDateProp,
|
||||
onChange,
|
||||
format,
|
||||
formatDensity = 'dense',
|
||||
selectedSections: selectedSectionsProp,
|
||||
onSelectedSectionsChange,
|
||||
shouldRespectLeadingZeros = false,
|
||||
timezone: timezoneProp,
|
||||
enableAccessibleFieldDOMStructure = true
|
||||
},
|
||||
forwardedProps: {
|
||||
error: errorProp
|
||||
}
|
||||
} = parameters;
|
||||
const {
|
||||
value,
|
||||
handleValueChange,
|
||||
timezone
|
||||
} = useControlledValue({
|
||||
name: 'a field component',
|
||||
timezone: timezoneProp,
|
||||
value: valueProp,
|
||||
defaultValue,
|
||||
referenceDate: referenceDateProp,
|
||||
onChange,
|
||||
valueManager
|
||||
});
|
||||
const valueRef = React.useRef(value);
|
||||
React.useEffect(() => {
|
||||
valueRef.current = value;
|
||||
}, [value]);
|
||||
const {
|
||||
hasValidationError
|
||||
} = useValidation({
|
||||
props: internalPropsWithDefaults,
|
||||
validator,
|
||||
timezone,
|
||||
value,
|
||||
onError: internalPropsWithDefaults.onError
|
||||
});
|
||||
const error = React.useMemo(() => {
|
||||
// only override when `error` is undefined.
|
||||
// in case of multi input fields, the `error` value is provided externally and will always be defined.
|
||||
if (errorProp !== undefined) {
|
||||
return errorProp;
|
||||
}
|
||||
return hasValidationError;
|
||||
}, [hasValidationError, errorProp]);
|
||||
const localizedDigits = React.useMemo(() => getLocalizedDigits(adapter), [adapter]);
|
||||
const sectionsValueBoundaries = React.useMemo(() => getSectionsBoundaries(adapter, localizedDigits, timezone), [adapter, localizedDigits, timezone]);
|
||||
const getSectionsFromValue = React.useCallback(valueToAnalyze => fieldValueManager.getSectionsFromValue(valueToAnalyze, date => buildSectionsFromFormat({
|
||||
adapter,
|
||||
localeText: translations,
|
||||
localizedDigits,
|
||||
format,
|
||||
date,
|
||||
formatDensity,
|
||||
shouldRespectLeadingZeros,
|
||||
enableAccessibleFieldDOMStructure,
|
||||
isRtl
|
||||
})), [fieldValueManager, format, translations, localizedDigits, isRtl, shouldRespectLeadingZeros, adapter, formatDensity, enableAccessibleFieldDOMStructure]);
|
||||
const [state, setState] = React.useState(() => {
|
||||
const sections = getSectionsFromValue(value);
|
||||
validateSections(sections, valueType);
|
||||
const stateWithoutReferenceDate = {
|
||||
sections,
|
||||
lastExternalValue: value,
|
||||
lastSectionsDependencies: {
|
||||
format,
|
||||
isRtl,
|
||||
locale: adapter.locale
|
||||
},
|
||||
tempValueStrAndroid: null,
|
||||
characterQuery: null
|
||||
};
|
||||
const granularity = getSectionTypeGranularity(sections);
|
||||
const referenceValue = valueManager.getInitialReferenceValue({
|
||||
referenceDate: referenceDateProp,
|
||||
value,
|
||||
adapter,
|
||||
props: internalPropsWithDefaults,
|
||||
granularity,
|
||||
timezone
|
||||
});
|
||||
return _extends({}, stateWithoutReferenceDate, {
|
||||
referenceValue
|
||||
});
|
||||
});
|
||||
const [selectedSections, innerSetSelectedSections] = useControlled({
|
||||
controlled: selectedSectionsProp,
|
||||
default: null,
|
||||
name: 'useField',
|
||||
state: 'selectedSections'
|
||||
});
|
||||
const setSelectedSections = newSelectedSections => {
|
||||
innerSetSelectedSections(newSelectedSections);
|
||||
onSelectedSectionsChange?.(newSelectedSections);
|
||||
};
|
||||
const parsedSelectedSections = React.useMemo(() => parseSelectedSections(selectedSections, state.sections), [selectedSections, state.sections]);
|
||||
const activeSectionIndex = parsedSelectedSections === 'all' ? 0 : parsedSelectedSections;
|
||||
const sectionOrder = React.useMemo(() => getSectionOrder(state.sections, isRtl && !enableAccessibleFieldDOMStructure), [state.sections, isRtl, enableAccessibleFieldDOMStructure]);
|
||||
const areAllSectionsEmpty = React.useMemo(() => state.sections.every(section => section.value === ''), [state.sections]);
|
||||
const publishValue = newValue => {
|
||||
const context = {
|
||||
validationError: validator({
|
||||
adapter,
|
||||
value: newValue,
|
||||
timezone,
|
||||
props: internalPropsWithDefaults
|
||||
})
|
||||
};
|
||||
handleValueChange(newValue, context);
|
||||
};
|
||||
const setSectionValue = (sectionIndex, newSectionValue) => {
|
||||
const newSections = [...state.sections];
|
||||
newSections[sectionIndex] = _extends({}, newSections[sectionIndex], {
|
||||
value: newSectionValue,
|
||||
modified: true
|
||||
});
|
||||
return newSections;
|
||||
};
|
||||
const sectionToUpdateOnNextInvalidDateRef = React.useRef(null);
|
||||
const updateSectionValueOnNextInvalidDateTimeout = useTimeout();
|
||||
const setSectionUpdateToApplyOnNextInvalidDate = newSectionValue => {
|
||||
if (activeSectionIndex == null) {
|
||||
return;
|
||||
}
|
||||
sectionToUpdateOnNextInvalidDateRef.current = {
|
||||
sectionIndex: activeSectionIndex,
|
||||
value: newSectionValue
|
||||
};
|
||||
updateSectionValueOnNextInvalidDateTimeout.start(0, () => {
|
||||
sectionToUpdateOnNextInvalidDateRef.current = null;
|
||||
});
|
||||
};
|
||||
const clearValue = () => {
|
||||
if (valueManager.areValuesEqual(adapter, value, valueManager.emptyValue)) {
|
||||
setState(prevState => _extends({}, prevState, {
|
||||
sections: prevState.sections.map(section => _extends({}, section, {
|
||||
value: ''
|
||||
})),
|
||||
tempValueStrAndroid: null,
|
||||
characterQuery: null
|
||||
}));
|
||||
} else {
|
||||
setState(prevState => _extends({}, prevState, {
|
||||
characterQuery: null
|
||||
}));
|
||||
publishValue(valueManager.emptyValue);
|
||||
}
|
||||
};
|
||||
const clearActiveSection = () => {
|
||||
if (activeSectionIndex == null) {
|
||||
return;
|
||||
}
|
||||
const activeSection = state.sections[activeSectionIndex];
|
||||
if (activeSection.value === '') {
|
||||
return;
|
||||
}
|
||||
setSectionUpdateToApplyOnNextInvalidDate('');
|
||||
if (fieldValueManager.getDateFromSection(value, activeSection) === null) {
|
||||
setState(prevState => _extends({}, prevState, {
|
||||
sections: setSectionValue(activeSectionIndex, ''),
|
||||
tempValueStrAndroid: null,
|
||||
characterQuery: null
|
||||
}));
|
||||
} else {
|
||||
setState(prevState => _extends({}, prevState, {
|
||||
characterQuery: null
|
||||
}));
|
||||
publishValue(fieldValueManager.updateDateInValue(value, activeSection, null));
|
||||
}
|
||||
};
|
||||
const updateValueFromValueStr = valueStr => {
|
||||
const parseDateStr = (dateStr, referenceDate) => {
|
||||
const date = adapter.parse(dateStr, format);
|
||||
if (!adapter.isValid(date)) {
|
||||
return null;
|
||||
}
|
||||
const sections = buildSectionsFromFormat({
|
||||
adapter,
|
||||
localeText: translations,
|
||||
localizedDigits,
|
||||
format,
|
||||
date,
|
||||
formatDensity,
|
||||
shouldRespectLeadingZeros,
|
||||
enableAccessibleFieldDOMStructure,
|
||||
isRtl
|
||||
});
|
||||
return mergeDateIntoReferenceDate(adapter, date, sections, referenceDate, false);
|
||||
};
|
||||
const newValue = fieldValueManager.parseValueStr(valueStr, state.referenceValue, parseDateStr);
|
||||
publishValue(newValue);
|
||||
};
|
||||
const cleanActiveDateSectionsIfValueNullTimeout = useTimeout();
|
||||
const updateSectionValue = ({
|
||||
section,
|
||||
newSectionValue,
|
||||
shouldGoToNextSection
|
||||
}) => {
|
||||
updateSectionValueOnNextInvalidDateTimeout.clear();
|
||||
cleanActiveDateSectionsIfValueNullTimeout.clear();
|
||||
const activeDate = fieldValueManager.getDateFromSection(value, section);
|
||||
|
||||
/**
|
||||
* Decide which section should be focused
|
||||
*/
|
||||
if (shouldGoToNextSection && activeSectionIndex < state.sections.length - 1) {
|
||||
setSelectedSections(activeSectionIndex + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to build a valid date from the new section value
|
||||
*/
|
||||
const newSections = setSectionValue(activeSectionIndex, newSectionValue);
|
||||
const newActiveDateSections = fieldValueManager.getDateSectionsFromValue(newSections, section);
|
||||
const newActiveDate = getDateFromDateSections(adapter, newActiveDateSections, localizedDigits);
|
||||
|
||||
/**
|
||||
* If the new date is valid,
|
||||
* Then we merge the value of the modified sections into the reference date.
|
||||
* This makes sure that we don't lose some information of the initial date (like the time on a date field).
|
||||
*/
|
||||
if (adapter.isValid(newActiveDate)) {
|
||||
const mergedDate = mergeDateIntoReferenceDate(adapter, newActiveDate, newActiveDateSections, fieldValueManager.getDateFromSection(state.referenceValue, section), true);
|
||||
if (activeDate == null) {
|
||||
cleanActiveDateSectionsIfValueNullTimeout.start(0, () => {
|
||||
if (valueRef.current === value) {
|
||||
setState(prevState => _extends({}, prevState, {
|
||||
sections: fieldValueManager.clearDateSections(state.sections, section),
|
||||
tempValueStrAndroid: null
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
return publishValue(fieldValueManager.updateDateInValue(value, section, mergedDate));
|
||||
}
|
||||
|
||||
/**
|
||||
* If all the sections are filled but the date is invalid and the previous date is valid or null,
|
||||
* Then we publish an invalid date.
|
||||
*/
|
||||
if (newActiveDateSections.every(sectionBis => sectionBis.value !== '') && (activeDate == null || adapter.isValid(activeDate))) {
|
||||
setSectionUpdateToApplyOnNextInvalidDate(newSectionValue);
|
||||
return publishValue(fieldValueManager.updateDateInValue(value, section, newActiveDate));
|
||||
}
|
||||
|
||||
/**
|
||||
* If the previous date is not null,
|
||||
* Then we publish the date as `null`.
|
||||
*/
|
||||
if (activeDate != null) {
|
||||
setSectionUpdateToApplyOnNextInvalidDate(newSectionValue);
|
||||
return publishValue(fieldValueManager.updateDateInValue(value, section, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* If the previous date is already null,
|
||||
* Then we don't publish the date and we update the sections.
|
||||
*/
|
||||
return setState(prevState => _extends({}, prevState, {
|
||||
sections: newSections,
|
||||
tempValueStrAndroid: null
|
||||
}));
|
||||
};
|
||||
const setTempAndroidValueStr = tempValueStrAndroid => setState(prevState => _extends({}, prevState, {
|
||||
tempValueStrAndroid
|
||||
}));
|
||||
const setCharacterQuery = useEventCallback(newCharacterQuery => {
|
||||
setState(prevState => _extends({}, prevState, {
|
||||
characterQuery: newCharacterQuery
|
||||
}));
|
||||
});
|
||||
|
||||
// If `prop.value` changes, we update the state to reflect the new value
|
||||
if (value !== state.lastExternalValue) {
|
||||
let sections;
|
||||
if (sectionToUpdateOnNextInvalidDateRef.current != null && !adapter.isValid(fieldValueManager.getDateFromSection(value, state.sections[sectionToUpdateOnNextInvalidDateRef.current.sectionIndex]))) {
|
||||
sections = setSectionValue(sectionToUpdateOnNextInvalidDateRef.current.sectionIndex, sectionToUpdateOnNextInvalidDateRef.current.value);
|
||||
} else {
|
||||
sections = getSectionsFromValue(value);
|
||||
}
|
||||
setState(prevState => _extends({}, prevState, {
|
||||
lastExternalValue: value,
|
||||
sections,
|
||||
sectionsDependencies: {
|
||||
format,
|
||||
isRtl,
|
||||
locale: adapter.locale
|
||||
},
|
||||
referenceValue: fieldValueManager.updateReferenceValue(adapter, value, prevState.referenceValue),
|
||||
tempValueStrAndroid: null
|
||||
}));
|
||||
}
|
||||
if (isRtl !== state.lastSectionsDependencies.isRtl || format !== state.lastSectionsDependencies.format || adapter.locale !== state.lastSectionsDependencies.locale) {
|
||||
const sections = getSectionsFromValue(value);
|
||||
validateSections(sections, valueType);
|
||||
setState(prevState => _extends({}, prevState, {
|
||||
lastSectionsDependencies: {
|
||||
format,
|
||||
isRtl,
|
||||
locale: adapter.locale
|
||||
},
|
||||
sections,
|
||||
tempValueStrAndroid: null,
|
||||
characterQuery: null
|
||||
}));
|
||||
}
|
||||
if (state.characterQuery != null && !error && activeSectionIndex == null) {
|
||||
setCharacterQuery(null);
|
||||
}
|
||||
if (state.characterQuery != null && state.sections[state.characterQuery.sectionIndex]?.type !== state.characterQuery.sectionType) {
|
||||
setCharacterQuery(null);
|
||||
}
|
||||
React.useEffect(() => {
|
||||
if (sectionToUpdateOnNextInvalidDateRef.current != null) {
|
||||
sectionToUpdateOnNextInvalidDateRef.current = null;
|
||||
}
|
||||
});
|
||||
const cleanCharacterQueryTimeout = useTimeout();
|
||||
React.useEffect(() => {
|
||||
if (state.characterQuery != null) {
|
||||
cleanCharacterQueryTimeout.start(QUERY_LIFE_DURATION_MS, () => setCharacterQuery(null));
|
||||
}
|
||||
return () => {};
|
||||
}, [state.characterQuery, setCharacterQuery, cleanCharacterQueryTimeout]);
|
||||
|
||||
// If `tempValueStrAndroid` is still defined for some section when running `useEffect`,
|
||||
// Then `onChange` has only been called once, which means the user pressed `Backspace` to reset the section.
|
||||
// This causes a small flickering on Android,
|
||||
// But we can't use `useEnhancedEffect` which is always called before the second `onChange` call and then would cause false positives.
|
||||
React.useEffect(() => {
|
||||
if (state.tempValueStrAndroid != null && activeSectionIndex != null) {
|
||||
clearActiveSection();
|
||||
}
|
||||
}, [state.sections]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
return {
|
||||
// States and derived states
|
||||
activeSectionIndex,
|
||||
areAllSectionsEmpty,
|
||||
error,
|
||||
localizedDigits,
|
||||
parsedSelectedSections,
|
||||
sectionOrder,
|
||||
sectionsValueBoundaries,
|
||||
state,
|
||||
timezone,
|
||||
value,
|
||||
// Methods to update the states
|
||||
clearValue,
|
||||
clearActiveSection,
|
||||
setCharacterQuery,
|
||||
setSelectedSections,
|
||||
setTempAndroidValueStr,
|
||||
updateSectionValue,
|
||||
updateValueFromValueStr,
|
||||
// Utilities methods
|
||||
getSectionsFromValue
|
||||
};
|
||||
};
|
||||
26
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldV6TextField.d.ts
generated
vendored
Normal file
26
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldV6TextField.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { UseFieldParameters, UseFieldProps, UseFieldReturnValue } from "./useField.types.js";
|
||||
import { InferFieldSection } from "../../../models/index.js";
|
||||
import { PickerValidValue } from "../../models/index.js";
|
||||
export declare const addPositionPropertiesToSections: <TValue extends PickerValidValue>(sections: InferFieldSection<TValue>[], localizedDigits: string[], isRtl: boolean) => FieldSectionWithPositions<TValue>[];
|
||||
export declare const useFieldV6TextField: <TValue extends PickerValidValue, TError, TValidationProps extends {}, TProps extends UseFieldProps<false>>(parameters: UseFieldParameters<TValue, false, TError, TValidationProps, TProps>) => UseFieldReturnValue<false, TProps>;
|
||||
type FieldSectionWithPositions<TValue extends PickerValidValue> = InferFieldSection<TValue> & {
|
||||
/**
|
||||
* Start index of the section in the format
|
||||
*/
|
||||
start: number;
|
||||
/**
|
||||
* End index of the section in the format
|
||||
*/
|
||||
end: number;
|
||||
/**
|
||||
* Start index of the section value in the input.
|
||||
* Takes into account invisible unicode characters such as \u2069 but does not include them
|
||||
*/
|
||||
startInInput: number;
|
||||
/**
|
||||
* End index of the section value in the input.
|
||||
* Takes into account invisible unicode characters such as \u2069 but does not include them
|
||||
*/
|
||||
endInInput: number;
|
||||
};
|
||||
export {};
|
||||
411
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldV6TextField.js
generated
vendored
Normal file
411
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldV6TextField.js
generated
vendored
Normal file
|
|
@ -0,0 +1,411 @@
|
|||
'use client';
|
||||
|
||||
import _extends from "@babel/runtime/helpers/esm/extends";
|
||||
import * as React from 'react';
|
||||
import { useRtl } from '@mui/system/RtlProvider';
|
||||
import useEnhancedEffect from '@mui/utils/useEnhancedEffect';
|
||||
import useEventCallback from '@mui/utils/useEventCallback';
|
||||
import useTimeout from '@mui/utils/useTimeout';
|
||||
import useForkRef from '@mui/utils/useForkRef';
|
||||
import { useSplitFieldProps } from "../../../hooks/index.js";
|
||||
import { getActiveElement } from "../../utils/utils.js";
|
||||
import { getSectionVisibleValue, isAndroid } from "./useField.utils.js";
|
||||
import { useFieldCharacterEditing } from "./useFieldCharacterEditing.js";
|
||||
import { useFieldRootHandleKeyDown } from "./useFieldRootHandleKeyDown.js";
|
||||
import { useFieldState } from "./useFieldState.js";
|
||||
import { useFieldInternalPropsWithDefaults } from "./useFieldInternalPropsWithDefaults.js";
|
||||
const cleanString = dirtyString => dirtyString.replace(/[\u2066\u2067\u2068\u2069]/g, '');
|
||||
export const addPositionPropertiesToSections = (sections, localizedDigits, isRtl) => {
|
||||
let position = 0;
|
||||
let positionInInput = isRtl ? 1 : 0;
|
||||
const newSections = [];
|
||||
for (let i = 0; i < sections.length; i += 1) {
|
||||
const section = sections[i];
|
||||
const renderedValue = getSectionVisibleValue(section, isRtl ? 'input-rtl' : 'input-ltr', localizedDigits);
|
||||
const sectionStr = `${section.startSeparator}${renderedValue}${section.endSeparator}`;
|
||||
const sectionLength = cleanString(sectionStr).length;
|
||||
const sectionLengthInInput = sectionStr.length;
|
||||
|
||||
// The ...InInput values consider the unicode characters but do include them in their indexes
|
||||
const cleanedValue = cleanString(renderedValue);
|
||||
const startInInput = positionInInput + (cleanedValue === '' ? 0 : renderedValue.indexOf(cleanedValue[0])) + section.startSeparator.length;
|
||||
const endInInput = startInInput + cleanedValue.length;
|
||||
newSections.push(_extends({}, section, {
|
||||
start: position,
|
||||
end: position + sectionLength,
|
||||
startInInput,
|
||||
endInInput
|
||||
}));
|
||||
position += sectionLength;
|
||||
// Move position to the end of string associated to the current section
|
||||
positionInInput += sectionLengthInInput;
|
||||
}
|
||||
return newSections;
|
||||
};
|
||||
export const useFieldV6TextField = parameters => {
|
||||
const isRtl = useRtl();
|
||||
const focusTimeout = useTimeout();
|
||||
const selectionSyncTimeout = useTimeout();
|
||||
const {
|
||||
props,
|
||||
manager,
|
||||
skipContextFieldRefAssignment,
|
||||
manager: {
|
||||
valueType,
|
||||
internal_valueManager: valueManager,
|
||||
internal_fieldValueManager: fieldValueManager,
|
||||
internal_useOpenPickerButtonAriaLabel: useOpenPickerButtonAriaLabel
|
||||
}
|
||||
} = parameters;
|
||||
const {
|
||||
internalProps,
|
||||
forwardedProps
|
||||
} = useSplitFieldProps(props, valueType);
|
||||
const internalPropsWithDefaults = useFieldInternalPropsWithDefaults({
|
||||
manager,
|
||||
internalProps,
|
||||
skipContextFieldRefAssignment
|
||||
});
|
||||
const {
|
||||
onFocus,
|
||||
onClick,
|
||||
onPaste,
|
||||
onBlur,
|
||||
onKeyDown,
|
||||
onClear,
|
||||
clearable,
|
||||
inputRef: inputRefProp,
|
||||
placeholder: inPlaceholder
|
||||
} = forwardedProps;
|
||||
const {
|
||||
readOnly = false,
|
||||
disabled = false,
|
||||
autoFocus = false,
|
||||
focused,
|
||||
unstableFieldRef
|
||||
} = internalPropsWithDefaults;
|
||||
const inputRef = React.useRef(null);
|
||||
const handleRef = useForkRef(inputRefProp, inputRef);
|
||||
const stateResponse = useFieldState({
|
||||
manager,
|
||||
internalPropsWithDefaults,
|
||||
forwardedProps
|
||||
});
|
||||
const {
|
||||
// States and derived states
|
||||
activeSectionIndex,
|
||||
areAllSectionsEmpty,
|
||||
error,
|
||||
localizedDigits,
|
||||
parsedSelectedSections,
|
||||
sectionOrder,
|
||||
state,
|
||||
value,
|
||||
// Methods to update the states
|
||||
clearValue,
|
||||
clearActiveSection,
|
||||
setCharacterQuery,
|
||||
setSelectedSections,
|
||||
setTempAndroidValueStr,
|
||||
updateSectionValue,
|
||||
updateValueFromValueStr,
|
||||
// Utilities methods
|
||||
getSectionsFromValue
|
||||
} = stateResponse;
|
||||
const applyCharacterEditing = useFieldCharacterEditing({
|
||||
stateResponse
|
||||
});
|
||||
const openPickerAriaLabel = useOpenPickerButtonAriaLabel(value);
|
||||
const sections = React.useMemo(() => addPositionPropertiesToSections(state.sections, localizedDigits, isRtl), [state.sections, localizedDigits, isRtl]);
|
||||
function syncSelectionFromDOM() {
|
||||
const browserStartIndex = inputRef.current.selectionStart ?? 0;
|
||||
let nextSectionIndex;
|
||||
if (browserStartIndex <= sections[0].startInInput) {
|
||||
// Special case if browser index is in invisible characters at the beginning
|
||||
nextSectionIndex = 1;
|
||||
} else if (browserStartIndex >= sections[sections.length - 1].endInInput) {
|
||||
// If the click is after the last character of the input, then we want to select the 1st section.
|
||||
nextSectionIndex = 1;
|
||||
} else {
|
||||
nextSectionIndex = sections.findIndex(section => section.startInInput - section.startSeparator.length > browserStartIndex);
|
||||
}
|
||||
const sectionIndex = nextSectionIndex === -1 ? sections.length - 1 : nextSectionIndex - 1;
|
||||
setSelectedSections(sectionIndex);
|
||||
}
|
||||
function focusField(newSelectedSection = 0) {
|
||||
if (getActiveElement(inputRef.current) === inputRef.current) {
|
||||
return;
|
||||
}
|
||||
inputRef.current?.focus();
|
||||
setSelectedSections(newSelectedSection);
|
||||
}
|
||||
const handleInputFocus = useEventCallback(event => {
|
||||
onFocus?.(event);
|
||||
// The ref is guaranteed to be resolved at this point.
|
||||
const input = inputRef.current;
|
||||
focusTimeout.start(0, () => {
|
||||
// The ref changed, the component got remounted, the focus event is no longer relevant.
|
||||
if (!input || input !== inputRef.current) {
|
||||
return;
|
||||
}
|
||||
if (activeSectionIndex != null) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
// avoid selecting all sections when focusing empty field without value
|
||||
input.value.length && Number(input.selectionEnd) - Number(input.selectionStart) === input.value.length) {
|
||||
setSelectedSections('all');
|
||||
} else {
|
||||
syncSelectionFromDOM();
|
||||
}
|
||||
});
|
||||
});
|
||||
const handleInputClick = useEventCallback((event, ...args) => {
|
||||
// The click event on the clear button would propagate to the input, trigger this handler and result in a wrong section selection.
|
||||
// We avoid this by checking if the call of `handleInputClick` is actually intended, or a side effect.
|
||||
if (event.isDefaultPrevented()) {
|
||||
return;
|
||||
}
|
||||
onClick?.(event, ...args);
|
||||
syncSelectionFromDOM();
|
||||
});
|
||||
const handleInputPaste = useEventCallback(event => {
|
||||
onPaste?.(event);
|
||||
|
||||
// prevent default to avoid the input `onChange` handler being called
|
||||
event.preventDefault();
|
||||
if (readOnly || disabled) {
|
||||
return;
|
||||
}
|
||||
const pastedValue = event.clipboardData.getData('text');
|
||||
if (typeof parsedSelectedSections === 'number') {
|
||||
const activeSection = state.sections[parsedSelectedSections];
|
||||
const lettersOnly = /^[a-zA-Z]+$/.test(pastedValue);
|
||||
const digitsOnly = /^[0-9]+$/.test(pastedValue);
|
||||
const digitsAndLetterOnly = /^(([a-zA-Z]+)|)([0-9]+)(([a-zA-Z]+)|)$/.test(pastedValue);
|
||||
const isValidPastedValue = activeSection.contentType === 'letter' && lettersOnly || activeSection.contentType === 'digit' && digitsOnly || activeSection.contentType === 'digit-with-letter' && digitsAndLetterOnly;
|
||||
if (isValidPastedValue) {
|
||||
setCharacterQuery(null);
|
||||
updateSectionValue({
|
||||
section: activeSection,
|
||||
newSectionValue: pastedValue,
|
||||
shouldGoToNextSection: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (lettersOnly || digitsOnly) {
|
||||
// The pasted value corresponds to a single section, but not the expected type,
|
||||
// skip the modification
|
||||
return;
|
||||
}
|
||||
}
|
||||
setCharacterQuery(null);
|
||||
updateValueFromValueStr(pastedValue);
|
||||
});
|
||||
const handleContainerBlur = useEventCallback(event => {
|
||||
onBlur?.(event);
|
||||
setSelectedSections(null);
|
||||
});
|
||||
const handleInputChange = useEventCallback(event => {
|
||||
if (readOnly) {
|
||||
return;
|
||||
}
|
||||
const targetValue = event.target.value;
|
||||
if (targetValue === '') {
|
||||
clearValue();
|
||||
return;
|
||||
}
|
||||
const eventData = event.nativeEvent.data;
|
||||
// Calling `.fill(04/11/2022)` in playwright will trigger a change event with the requested content to insert in `event.nativeEvent.data`
|
||||
// usual changes have only the currently typed character in the `event.nativeEvent.data`
|
||||
const shouldUseEventData = eventData && eventData.length > 1;
|
||||
const valueStr = shouldUseEventData ? eventData : targetValue;
|
||||
const cleanValueStr = cleanString(valueStr);
|
||||
if (parsedSelectedSections === 'all') {
|
||||
setSelectedSections(activeSectionIndex);
|
||||
}
|
||||
|
||||
// If no section is selected or eventData should be used, we just try to parse the new value
|
||||
// This line is mostly triggered by imperative code / application tests.
|
||||
if (activeSectionIndex == null || shouldUseEventData) {
|
||||
updateValueFromValueStr(shouldUseEventData ? eventData : cleanValueStr);
|
||||
return;
|
||||
}
|
||||
let keyPressed;
|
||||
if (parsedSelectedSections === 'all' && cleanValueStr.length === 1) {
|
||||
keyPressed = cleanValueStr;
|
||||
} else {
|
||||
const prevValueStr = cleanString(fieldValueManager.getV6InputValueFromSections(sections, localizedDigits, isRtl));
|
||||
let startOfDiffIndex = -1;
|
||||
let endOfDiffIndex = -1;
|
||||
for (let i = 0; i < prevValueStr.length; i += 1) {
|
||||
if (startOfDiffIndex === -1 && prevValueStr[i] !== cleanValueStr[i]) {
|
||||
startOfDiffIndex = i;
|
||||
}
|
||||
if (endOfDiffIndex === -1 && prevValueStr[prevValueStr.length - i - 1] !== cleanValueStr[cleanValueStr.length - i - 1]) {
|
||||
endOfDiffIndex = i;
|
||||
}
|
||||
}
|
||||
const activeSection = sections[activeSectionIndex];
|
||||
const hasDiffOutsideOfActiveSection = startOfDiffIndex < activeSection.start || prevValueStr.length - endOfDiffIndex - 1 > activeSection.end;
|
||||
if (hasDiffOutsideOfActiveSection) {
|
||||
// TODO: Support if the new date is valid
|
||||
return;
|
||||
}
|
||||
|
||||
// The active section being selected, the browser has replaced its value with the key pressed by the user.
|
||||
const activeSectionEndRelativeToNewValue = cleanValueStr.length - prevValueStr.length + activeSection.end - cleanString(activeSection.endSeparator || '').length;
|
||||
keyPressed = cleanValueStr.slice(activeSection.start + cleanString(activeSection.startSeparator || '').length, activeSectionEndRelativeToNewValue);
|
||||
}
|
||||
if (keyPressed.length === 0) {
|
||||
if (isAndroid()) {
|
||||
setTempAndroidValueStr(valueStr);
|
||||
}
|
||||
clearActiveSection();
|
||||
return;
|
||||
}
|
||||
applyCharacterEditing({
|
||||
keyPressed,
|
||||
sectionIndex: activeSectionIndex
|
||||
});
|
||||
});
|
||||
const handleClear = useEventCallback((event, ...args) => {
|
||||
event.preventDefault();
|
||||
onClear?.(event, ...args);
|
||||
clearValue();
|
||||
if (!isFieldFocused(inputRef)) {
|
||||
// setSelectedSections is called internally
|
||||
focusField(0);
|
||||
} else {
|
||||
setSelectedSections(sectionOrder.startIndex);
|
||||
}
|
||||
});
|
||||
const handleContainerKeyDown = useFieldRootHandleKeyDown({
|
||||
manager,
|
||||
internalPropsWithDefaults,
|
||||
stateResponse
|
||||
});
|
||||
const wrappedHandleContainerKeyDown = useEventCallback(event => {
|
||||
onKeyDown?.(event);
|
||||
handleContainerKeyDown(event);
|
||||
});
|
||||
const placeholder = React.useMemo(() => {
|
||||
if (inPlaceholder !== undefined) {
|
||||
return inPlaceholder;
|
||||
}
|
||||
return fieldValueManager.getV6InputValueFromSections(getSectionsFromValue(valueManager.emptyValue), localizedDigits, isRtl);
|
||||
}, [inPlaceholder, fieldValueManager, getSectionsFromValue, valueManager.emptyValue, localizedDigits, isRtl]);
|
||||
const valueStr = React.useMemo(() => state.tempValueStrAndroid ?? fieldValueManager.getV6InputValueFromSections(state.sections, localizedDigits, isRtl), [state.sections, fieldValueManager, state.tempValueStrAndroid, localizedDigits, isRtl]);
|
||||
React.useEffect(() => {
|
||||
// Select all the sections when focused on mount (`autoFocus = true` on the input)
|
||||
if (inputRef.current && inputRef.current === getActiveElement(inputRef.current)) {
|
||||
setSelectedSections('all');
|
||||
}
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
useEnhancedEffect(() => {
|
||||
function syncSelectionToDOM() {
|
||||
if (!inputRef.current) {
|
||||
return;
|
||||
}
|
||||
if (parsedSelectedSections == null) {
|
||||
if (inputRef.current.scrollLeft) {
|
||||
// Ensure that input content is not marked as selected.
|
||||
// setting selection range to 0 causes issues in Safari.
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=224425
|
||||
inputRef.current.scrollLeft = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// On multi input range pickers we want to update selection range only for the active input
|
||||
// This helps to avoid the focus jumping on Safari https://github.com/mui/mui-x/issues/9003
|
||||
// because WebKit implements the `setSelectionRange` based on the spec: https://bugs.webkit.org/show_bug.cgi?id=224425
|
||||
if (inputRef.current !== getActiveElement(inputRef.current)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fix scroll jumping on iOS browser: https://github.com/mui/mui-x/issues/8321
|
||||
const currentScrollTop = inputRef.current.scrollTop;
|
||||
if (parsedSelectedSections === 'all') {
|
||||
inputRef.current.select();
|
||||
} else {
|
||||
const selectedSection = sections[parsedSelectedSections];
|
||||
const selectionStart = selectedSection.type === 'empty' ? selectedSection.startInInput - selectedSection.startSeparator.length : selectedSection.startInInput;
|
||||
const selectionEnd = selectedSection.type === 'empty' ? selectedSection.endInInput + selectedSection.endSeparator.length : selectedSection.endInInput;
|
||||
if (selectionStart !== inputRef.current.selectionStart || selectionEnd !== inputRef.current.selectionEnd) {
|
||||
if (inputRef.current === getActiveElement(inputRef.current)) {
|
||||
inputRef.current.setSelectionRange(selectionStart, selectionEnd);
|
||||
}
|
||||
}
|
||||
selectionSyncTimeout.start(0, () => {
|
||||
// handle case when the selection is not updated correctly
|
||||
// could happen on Android
|
||||
if (inputRef.current && inputRef.current === getActiveElement(inputRef.current) &&
|
||||
// The section might loose all selection, where `selectionStart === selectionEnd`
|
||||
// https://github.com/mui/mui-x/pull/13652
|
||||
inputRef.current.selectionStart === inputRef.current.selectionEnd && (inputRef.current.selectionStart !== selectionStart || inputRef.current.selectionEnd !== selectionEnd)) {
|
||||
syncSelectionToDOM();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Even reading this variable seems to do the trick, but also setting it just to make use of it
|
||||
inputRef.current.scrollTop = currentScrollTop;
|
||||
}
|
||||
syncSelectionToDOM();
|
||||
});
|
||||
const inputMode = React.useMemo(() => {
|
||||
if (activeSectionIndex == null) {
|
||||
return 'text';
|
||||
}
|
||||
if (state.sections[activeSectionIndex].contentType === 'letter') {
|
||||
return 'text';
|
||||
}
|
||||
return 'numeric';
|
||||
}, [activeSectionIndex, state.sections]);
|
||||
const inputHasFocus = inputRef.current && inputRef.current === getActiveElement(inputRef.current);
|
||||
const shouldShowPlaceholder = !inputHasFocus && areAllSectionsEmpty;
|
||||
React.useImperativeHandle(unstableFieldRef, () => ({
|
||||
getSections: () => state.sections,
|
||||
getActiveSectionIndex: () => {
|
||||
const browserStartIndex = inputRef.current.selectionStart ?? 0;
|
||||
const browserEndIndex = inputRef.current.selectionEnd ?? 0;
|
||||
if (browserStartIndex === 0 && browserEndIndex === 0) {
|
||||
return null;
|
||||
}
|
||||
const nextSectionIndex = browserStartIndex <= sections[0].startInInput ? 1 // Special case if browser index is in invisible characters at the beginning.
|
||||
: sections.findIndex(section => section.startInInput - section.startSeparator.length > browserStartIndex);
|
||||
return nextSectionIndex === -1 ? sections.length - 1 : nextSectionIndex - 1;
|
||||
},
|
||||
setSelectedSections: newSelectedSections => setSelectedSections(newSelectedSections),
|
||||
focusField,
|
||||
isFieldFocused: () => isFieldFocused(inputRef)
|
||||
}));
|
||||
return _extends({}, forwardedProps, {
|
||||
error,
|
||||
clearable: Boolean(clearable && !areAllSectionsEmpty && !readOnly && !disabled),
|
||||
onBlur: handleContainerBlur,
|
||||
onClick: handleInputClick,
|
||||
onFocus: handleInputFocus,
|
||||
onPaste: handleInputPaste,
|
||||
onKeyDown: wrappedHandleContainerKeyDown,
|
||||
onClear: handleClear,
|
||||
inputRef: handleRef,
|
||||
// Additional
|
||||
enableAccessibleFieldDOMStructure: false,
|
||||
placeholder,
|
||||
inputMode,
|
||||
autoComplete: 'off',
|
||||
value: shouldShowPlaceholder ? '' : valueStr,
|
||||
onChange: handleInputChange,
|
||||
focused,
|
||||
disabled,
|
||||
readOnly,
|
||||
autoFocus,
|
||||
openPickerAriaLabel
|
||||
});
|
||||
};
|
||||
function isFieldFocused(inputRef) {
|
||||
return inputRef.current === getActiveElement(inputRef.current);
|
||||
}
|
||||
3
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldV7TextField.d.ts
generated
vendored
Normal file
3
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldV7TextField.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import { UseFieldParameters, UseFieldProps, UseFieldReturnValue } from "./useField.types.js";
|
||||
import { PickerValidValue } from "../../models/index.js";
|
||||
export declare const useFieldV7TextField: <TValue extends PickerValidValue, TError, TValidationProps extends {}, TProps extends UseFieldProps<true>>(parameters: UseFieldParameters<TValue, true, TError, TValidationProps, TProps>) => UseFieldReturnValue<true, TProps>;
|
||||
255
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldV7TextField.js
generated
vendored
Normal file
255
node_modules/@mui/x-date-pickers/esm/internals/hooks/useField/useFieldV7TextField.js
generated
vendored
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
'use client';
|
||||
|
||||
import _extends from "@babel/runtime/helpers/esm/extends";
|
||||
import * as React from 'react';
|
||||
import useForkRef from '@mui/utils/useForkRef';
|
||||
import useEventCallback from '@mui/utils/useEventCallback';
|
||||
import useEnhancedEffect from '@mui/utils/useEnhancedEffect';
|
||||
import { parseSelectedSections } from "./useField.utils.js";
|
||||
import { getActiveElement } from "../../utils/utils.js";
|
||||
import { useSplitFieldProps } from "../../../hooks/index.js";
|
||||
import { useFieldCharacterEditing } from "./useFieldCharacterEditing.js";
|
||||
import { useFieldState } from "./useFieldState.js";
|
||||
import { useFieldInternalPropsWithDefaults } from "./useFieldInternalPropsWithDefaults.js";
|
||||
import { syncSelectionToDOM } from "./syncSelectionToDOM.js";
|
||||
import { useFieldRootProps } from "./useFieldRootProps.js";
|
||||
import { useFieldHiddenInputProps } from "./useFieldHiddenInputProps.js";
|
||||
import { useFieldSectionContainerProps } from "./useFieldSectionContainerProps.js";
|
||||
import { useFieldSectionContentProps } from "./useFieldSectionContentProps.js";
|
||||
export const useFieldV7TextField = parameters => {
|
||||
const {
|
||||
props,
|
||||
manager,
|
||||
skipContextFieldRefAssignment,
|
||||
manager: {
|
||||
valueType,
|
||||
internal_useOpenPickerButtonAriaLabel: useOpenPickerButtonAriaLabel
|
||||
}
|
||||
} = parameters;
|
||||
const {
|
||||
internalProps,
|
||||
forwardedProps
|
||||
} = useSplitFieldProps(props, valueType);
|
||||
const internalPropsWithDefaults = useFieldInternalPropsWithDefaults({
|
||||
manager,
|
||||
internalProps,
|
||||
skipContextFieldRefAssignment
|
||||
});
|
||||
const {
|
||||
sectionListRef: sectionListRefProp,
|
||||
onBlur,
|
||||
onClick,
|
||||
onFocus,
|
||||
onInput,
|
||||
onPaste,
|
||||
onKeyDown,
|
||||
onClear,
|
||||
clearable
|
||||
} = forwardedProps;
|
||||
const {
|
||||
disabled = false,
|
||||
readOnly = false,
|
||||
autoFocus = false,
|
||||
focused: focusedProp,
|
||||
unstableFieldRef
|
||||
} = internalPropsWithDefaults;
|
||||
const sectionListRef = React.useRef(null);
|
||||
const handleSectionListRef = useForkRef(sectionListRefProp, sectionListRef);
|
||||
const domGetters = React.useMemo(() => ({
|
||||
isReady: () => sectionListRef.current != null,
|
||||
getRoot: () => sectionListRef.current.getRoot(),
|
||||
getSectionContainer: sectionIndex => sectionListRef.current.getSectionContainer(sectionIndex),
|
||||
getSectionContent: sectionIndex => sectionListRef.current.getSectionContent(sectionIndex),
|
||||
getSectionIndexFromDOMElement: element => sectionListRef.current.getSectionIndexFromDOMElement(element)
|
||||
}), [sectionListRef]);
|
||||
const stateResponse = useFieldState({
|
||||
manager,
|
||||
internalPropsWithDefaults,
|
||||
forwardedProps
|
||||
});
|
||||
const {
|
||||
// States and derived states
|
||||
areAllSectionsEmpty,
|
||||
error,
|
||||
parsedSelectedSections,
|
||||
sectionOrder,
|
||||
state,
|
||||
value,
|
||||
// Methods to update the states
|
||||
clearValue,
|
||||
setSelectedSections
|
||||
} = stateResponse;
|
||||
const applyCharacterEditing = useFieldCharacterEditing({
|
||||
stateResponse
|
||||
});
|
||||
const openPickerAriaLabel = useOpenPickerButtonAriaLabel(value);
|
||||
const [focused, setFocused] = React.useState(false);
|
||||
function focusField(newSelectedSections = 0) {
|
||||
if (disabled || !sectionListRef.current ||
|
||||
// if the field is already focused, we don't need to focus it again
|
||||
getActiveSectionIndex(sectionListRef) != null) {
|
||||
return;
|
||||
}
|
||||
const newParsedSelectedSections = parseSelectedSections(newSelectedSections, state.sections);
|
||||
setFocused(true);
|
||||
sectionListRef.current.getSectionContent(newParsedSelectedSections).focus();
|
||||
}
|
||||
const rootProps = useFieldRootProps({
|
||||
manager,
|
||||
internalPropsWithDefaults,
|
||||
stateResponse,
|
||||
applyCharacterEditing,
|
||||
focused,
|
||||
setFocused,
|
||||
domGetters
|
||||
});
|
||||
const hiddenInputProps = useFieldHiddenInputProps({
|
||||
manager,
|
||||
stateResponse
|
||||
});
|
||||
const createSectionContainerProps = useFieldSectionContainerProps({
|
||||
stateResponse,
|
||||
internalPropsWithDefaults
|
||||
});
|
||||
const createSectionContentProps = useFieldSectionContentProps({
|
||||
manager,
|
||||
stateResponse,
|
||||
applyCharacterEditing,
|
||||
internalPropsWithDefaults,
|
||||
domGetters,
|
||||
focused
|
||||
});
|
||||
const handleRootKeyDown = useEventCallback(event => {
|
||||
onKeyDown?.(event);
|
||||
rootProps.onKeyDown(event);
|
||||
});
|
||||
const handleRootBlur = useEventCallback(event => {
|
||||
onBlur?.(event);
|
||||
rootProps.onBlur(event);
|
||||
});
|
||||
const handleRootFocus = useEventCallback(event => {
|
||||
onFocus?.(event);
|
||||
rootProps.onFocus(event);
|
||||
});
|
||||
const handleRootClick = useEventCallback(event => {
|
||||
// The click event on the clear or open button would propagate to the input, trigger this handler and result in an inadvertent section selection.
|
||||
// We avoid this by checking if the call of `handleInputClick` is actually intended, or a propagated call, which should be skipped.
|
||||
if (event.isDefaultPrevented()) {
|
||||
return;
|
||||
}
|
||||
onClick?.(event);
|
||||
rootProps.onClick(event);
|
||||
});
|
||||
const handleRootPaste = useEventCallback(event => {
|
||||
onPaste?.(event);
|
||||
rootProps.onPaste(event);
|
||||
});
|
||||
const handleRootInput = useEventCallback(event => {
|
||||
onInput?.(event);
|
||||
rootProps.onInput(event);
|
||||
});
|
||||
const handleClear = useEventCallback((event, ...args) => {
|
||||
event.preventDefault();
|
||||
onClear?.(event, ...args);
|
||||
clearValue();
|
||||
if (!isFieldFocused(sectionListRef)) {
|
||||
// setSelectedSections is called internally
|
||||
focusField(0);
|
||||
} else {
|
||||
setSelectedSections(sectionOrder.startIndex);
|
||||
}
|
||||
});
|
||||
const elements = React.useMemo(() => {
|
||||
return state.sections.map((section, sectionIndex) => {
|
||||
const content = createSectionContentProps(section, sectionIndex);
|
||||
return {
|
||||
container: createSectionContainerProps(sectionIndex),
|
||||
content: createSectionContentProps(section, sectionIndex),
|
||||
before: {
|
||||
children: section.startSeparator
|
||||
},
|
||||
after: {
|
||||
children: section.endSeparator,
|
||||
'data-range-position': section.isEndFormatSeparator ? content['data-range-position'] : undefined
|
||||
}
|
||||
};
|
||||
});
|
||||
}, [state.sections, createSectionContainerProps, createSectionContentProps]);
|
||||
React.useEffect(() => {
|
||||
if (sectionListRef.current == null) {
|
||||
throw new Error(['MUI X: The `sectionListRef` prop has not been initialized by `PickersSectionList`', 'You probably tried to pass a component to the `textField` slot that contains an `<input />` element instead of a `PickersSectionList`.', '', 'If you want to keep using an `<input />` HTML element for the editing, please add the `enableAccessibleFieldDOMStructure={false}` prop to your Picker or Field component:', '', '<DatePicker enableAccessibleFieldDOMStructure={false} slots={{ textField: MyCustomTextField }} />', '', 'Learn more about the field accessible DOM structure on the MUI documentation: https://mui.com/x/react-date-pickers/fields/#fields-to-edit-a-single-element'].join('\n'));
|
||||
}
|
||||
if (autoFocus && !disabled && sectionListRef.current) {
|
||||
sectionListRef.current.getSectionContent(sectionOrder.startIndex).focus();
|
||||
}
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
useEnhancedEffect(() => {
|
||||
if (!focused || !sectionListRef.current) {
|
||||
return;
|
||||
}
|
||||
if (parsedSelectedSections === 'all') {
|
||||
sectionListRef.current.getRoot().focus();
|
||||
} else if (typeof parsedSelectedSections === 'number') {
|
||||
const domElement = sectionListRef.current.getSectionContent(parsedSelectedSections);
|
||||
if (domElement) {
|
||||
domElement.focus();
|
||||
}
|
||||
}
|
||||
}, [parsedSelectedSections, focused]);
|
||||
useEnhancedEffect(() => {
|
||||
syncSelectionToDOM({
|
||||
focused,
|
||||
domGetters,
|
||||
stateResponse
|
||||
});
|
||||
});
|
||||
React.useImperativeHandle(unstableFieldRef, () => ({
|
||||
getSections: () => state.sections,
|
||||
getActiveSectionIndex: () => getActiveSectionIndex(sectionListRef),
|
||||
setSelectedSections: newSelectedSections => {
|
||||
if (disabled || !sectionListRef.current) {
|
||||
return;
|
||||
}
|
||||
const newParsedSelectedSections = parseSelectedSections(newSelectedSections, state.sections);
|
||||
const newActiveSectionIndex = newParsedSelectedSections === 'all' ? 0 : newParsedSelectedSections;
|
||||
setFocused(newActiveSectionIndex !== null);
|
||||
setSelectedSections(newSelectedSections);
|
||||
},
|
||||
focusField,
|
||||
isFieldFocused: () => isFieldFocused(sectionListRef)
|
||||
}));
|
||||
return _extends({}, forwardedProps, rootProps, {
|
||||
onBlur: handleRootBlur,
|
||||
onClick: handleRootClick,
|
||||
onFocus: handleRootFocus,
|
||||
onInput: handleRootInput,
|
||||
onPaste: handleRootPaste,
|
||||
onKeyDown: handleRootKeyDown,
|
||||
onClear: handleClear
|
||||
}, hiddenInputProps, {
|
||||
error,
|
||||
clearable: Boolean(clearable && !areAllSectionsEmpty && !readOnly && !disabled),
|
||||
focused: focusedProp ?? focused,
|
||||
sectionListRef: handleSectionListRef,
|
||||
// Additional
|
||||
enableAccessibleFieldDOMStructure: true,
|
||||
elements,
|
||||
areAllSectionsEmpty,
|
||||
disabled,
|
||||
readOnly,
|
||||
autoFocus,
|
||||
openPickerAriaLabel
|
||||
});
|
||||
};
|
||||
function getActiveSectionIndex(sectionListRef) {
|
||||
const activeElement = getActiveElement(sectionListRef.current?.getRoot());
|
||||
if (!activeElement || !sectionListRef.current || !sectionListRef.current.getRoot().contains(activeElement)) {
|
||||
return null;
|
||||
}
|
||||
return sectionListRef.current.getSectionIndexFromDOMElement(activeElement);
|
||||
}
|
||||
function isFieldFocused(sectionListRef) {
|
||||
const activeElement = getActiveElement(sectionListRef.current?.getRoot());
|
||||
return !!sectionListRef.current && sectionListRef.current.getRoot().contains(activeElement);
|
||||
}
|
||||
6
node_modules/@mui/x-date-pickers/esm/internals/hooks/useFieldOwnerState.d.ts
generated
vendored
Normal file
6
node_modules/@mui/x-date-pickers/esm/internals/hooks/useFieldOwnerState.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { FieldOwnerState } from "../../models/index.js";
|
||||
import { FormProps } from "../models/index.js";
|
||||
export declare function useFieldOwnerState(parameters: UseFieldOwnerStateParameters): FieldOwnerState;
|
||||
export interface UseFieldOwnerStateParameters extends FormProps {
|
||||
required?: boolean;
|
||||
}
|
||||
16
node_modules/@mui/x-date-pickers/esm/internals/hooks/useFieldOwnerState.js
generated
vendored
Normal file
16
node_modules/@mui/x-date-pickers/esm/internals/hooks/useFieldOwnerState.js
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import _extends from "@babel/runtime/helpers/esm/extends";
|
||||
import * as React from 'react';
|
||||
import { useRtl } from '@mui/system/RtlProvider';
|
||||
import { usePickerPrivateContext } from "./usePickerPrivateContext.js";
|
||||
export function useFieldOwnerState(parameters) {
|
||||
const {
|
||||
ownerState: pickerOwnerState
|
||||
} = usePickerPrivateContext();
|
||||
const isRtl = useRtl();
|
||||
return React.useMemo(() => _extends({}, pickerOwnerState, {
|
||||
isFieldDisabled: parameters.disabled ?? false,
|
||||
isFieldReadOnly: parameters.readOnly ?? false,
|
||||
isFieldRequired: parameters.required ?? false,
|
||||
fieldDirection: isRtl ? 'rtl' : 'ltr'
|
||||
}), [pickerOwnerState, parameters.disabled, parameters.readOnly, parameters.required, isRtl]);
|
||||
}
|
||||
2
node_modules/@mui/x-date-pickers/esm/internals/hooks/useMobilePicker/index.d.ts
generated
vendored
Normal file
2
node_modules/@mui/x-date-pickers/esm/internals/hooks/useMobilePicker/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export { useMobilePicker } from "./useMobilePicker.js";
|
||||
export type { UseMobilePickerSlots, UseMobilePickerSlotProps, ExportedUseMobilePickerSlotProps, MobileOnlyPickerProps } from "./useMobilePicker.types.js";
|
||||
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/useMobilePicker/index.js
generated
vendored
Normal file
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/useMobilePicker/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { useMobilePicker } from "./useMobilePicker.js";
|
||||
16
node_modules/@mui/x-date-pickers/esm/internals/hooks/useMobilePicker/useMobilePicker.d.ts
generated
vendored
Normal file
16
node_modules/@mui/x-date-pickers/esm/internals/hooks/useMobilePicker/useMobilePicker.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import * as React from 'react';
|
||||
import { UseMobilePickerParams, UseMobilePickerProps } from "./useMobilePicker.types.js";
|
||||
import { DateOrTimeViewWithMeridiem } from "../../models/index.js";
|
||||
/**
|
||||
* Hook managing all the single-date mobile pickers:
|
||||
* - MobileDatePicker
|
||||
* - MobileDateTimePicker
|
||||
* - MobileTimePicker
|
||||
*/
|
||||
export declare const useMobilePicker: <TView extends DateOrTimeViewWithMeridiem, TEnableAccessibleFieldDOMStructure extends boolean, TExternalProps extends UseMobilePickerProps<TView, TEnableAccessibleFieldDOMStructure, any, TExternalProps>>({
|
||||
props,
|
||||
steps,
|
||||
...pickerParams
|
||||
}: UseMobilePickerParams<TView, TEnableAccessibleFieldDOMStructure, TExternalProps>) => {
|
||||
renderPicker: () => React.JSX.Element;
|
||||
};
|
||||
98
node_modules/@mui/x-date-pickers/esm/internals/hooks/useMobilePicker/useMobilePicker.js
generated
vendored
Normal file
98
node_modules/@mui/x-date-pickers/esm/internals/hooks/useMobilePicker/useMobilePicker.js
generated
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
import _extends from "@babel/runtime/helpers/esm/extends";
|
||||
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
||||
const _excluded = ["props", "steps"],
|
||||
_excluded2 = ["ownerState"];
|
||||
import * as React from 'react';
|
||||
import useSlotProps from '@mui/utils/useSlotProps';
|
||||
import { PickersModalDialog } from "../../components/PickersModalDialog.js";
|
||||
import { usePicker } from "../usePicker/index.js";
|
||||
import { PickersLayout } from "../../../PickersLayout/index.js";
|
||||
import { PickerProvider } from "../../components/PickerProvider.js";
|
||||
import { PickerFieldUIContextProvider } from "../../components/PickerFieldUI.js";
|
||||
import { createNonRangePickerStepNavigation } from "../../utils/createNonRangePickerStepNavigation.js";
|
||||
|
||||
/**
|
||||
* Hook managing all the single-date mobile pickers:
|
||||
* - MobileDatePicker
|
||||
* - MobileDateTimePicker
|
||||
* - MobileTimePicker
|
||||
*/
|
||||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
export const useMobilePicker = _ref => {
|
||||
let {
|
||||
props,
|
||||
steps
|
||||
} = _ref,
|
||||
pickerParams = _objectWithoutPropertiesLoose(_ref, _excluded);
|
||||
const {
|
||||
slots,
|
||||
slotProps: innerSlotProps,
|
||||
label,
|
||||
inputRef,
|
||||
localeText
|
||||
} = props;
|
||||
const getStepNavigation = createNonRangePickerStepNavigation({
|
||||
steps
|
||||
});
|
||||
const {
|
||||
providerProps,
|
||||
renderCurrentView,
|
||||
ownerState
|
||||
} = usePicker(_extends({}, pickerParams, {
|
||||
props,
|
||||
localeText,
|
||||
autoFocusView: true,
|
||||
viewContainerRole: 'dialog',
|
||||
variant: 'mobile',
|
||||
getStepNavigation
|
||||
}));
|
||||
const labelId = providerProps.privateContextValue.labelId;
|
||||
const isToolbarHidden = innerSlotProps?.toolbar?.hidden ?? false;
|
||||
const Field = slots.field;
|
||||
const _useSlotProps = useSlotProps({
|
||||
elementType: Field,
|
||||
externalSlotProps: innerSlotProps?.field,
|
||||
additionalProps: _extends({}, isToolbarHidden && {
|
||||
id: labelId
|
||||
}),
|
||||
ownerState
|
||||
}),
|
||||
fieldProps = _objectWithoutPropertiesLoose(_useSlotProps, _excluded2);
|
||||
const Layout = slots.layout ?? PickersLayout;
|
||||
let labelledById = labelId;
|
||||
if (isToolbarHidden) {
|
||||
if (label) {
|
||||
labelledById = `${labelId}-label`;
|
||||
} else {
|
||||
labelledById = undefined;
|
||||
}
|
||||
}
|
||||
const slotProps = _extends({}, innerSlotProps, {
|
||||
toolbar: _extends({}, innerSlotProps?.toolbar, {
|
||||
titleId: labelId
|
||||
}),
|
||||
mobilePaper: _extends({
|
||||
'aria-labelledby': labelledById
|
||||
}, innerSlotProps?.mobilePaper)
|
||||
});
|
||||
const renderPicker = () => /*#__PURE__*/_jsx(PickerProvider, _extends({}, providerProps, {
|
||||
children: /*#__PURE__*/_jsxs(PickerFieldUIContextProvider, {
|
||||
slots: slots,
|
||||
slotProps: slotProps,
|
||||
inputRef: inputRef,
|
||||
children: [/*#__PURE__*/_jsx(Field, _extends({}, fieldProps)), /*#__PURE__*/_jsx(PickersModalDialog, {
|
||||
slots: slots,
|
||||
slotProps: slotProps,
|
||||
children: /*#__PURE__*/_jsx(Layout, _extends({}, slotProps?.layout, {
|
||||
slots: slots,
|
||||
slotProps: slotProps,
|
||||
children: renderCurrentView()
|
||||
}))
|
||||
})]
|
||||
})
|
||||
}));
|
||||
if (process.env.NODE_ENV !== "production") renderPicker.displayName = "renderPicker";
|
||||
return {
|
||||
renderPicker
|
||||
};
|
||||
};
|
||||
42
node_modules/@mui/x-date-pickers/esm/internals/hooks/useMobilePicker/useMobilePicker.types.d.ts
generated
vendored
Normal file
42
node_modules/@mui/x-date-pickers/esm/internals/hooks/useMobilePicker/useMobilePicker.types.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import * as React from 'react';
|
||||
import { MakeRequired, SlotComponentPropsFromProps } from '@mui/x-internals/types';
|
||||
import { BasePickerProps } from "../../models/props/basePickerProps.js";
|
||||
import { PickersModalDialogSlots, PickersModalDialogSlotProps } from "../../components/PickersModalDialog.js";
|
||||
import { UsePickerParameters, UsePickerNonStaticProps, UsePickerProps } from "../usePicker/index.js";
|
||||
import { PickerFieldSlotProps, PickerOwnerState } from "../../../models/index.js";
|
||||
import { ExportedPickersLayoutSlots, ExportedPickersLayoutSlotProps, PickersLayoutSlotProps } from "../../../PickersLayout/PickersLayout.types.js";
|
||||
import { DateOrTimeViewWithMeridiem, PickerValue } from "../../models/index.js";
|
||||
import { PickerFieldUISlotsFromContext, PickerFieldUISlotPropsFromContext } from "../../components/PickerFieldUI.js";
|
||||
import { PickerStep } from "../../utils/createNonRangePickerStepNavigation.js";
|
||||
export interface UseMobilePickerSlots extends PickersModalDialogSlots, ExportedPickersLayoutSlots<PickerValue>, PickerFieldUISlotsFromContext {
|
||||
/**
|
||||
* Component used to enter the date with the keyboard.
|
||||
*/
|
||||
field: React.ElementType;
|
||||
}
|
||||
export interface ExportedUseMobilePickerSlotProps<TEnableAccessibleFieldDOMStructure extends boolean> extends PickersModalDialogSlotProps, ExportedPickersLayoutSlotProps<PickerValue>, PickerFieldUISlotPropsFromContext {
|
||||
field?: SlotComponentPropsFromProps<PickerFieldSlotProps<PickerValue, TEnableAccessibleFieldDOMStructure>, {}, PickerOwnerState>;
|
||||
}
|
||||
export interface UseMobilePickerSlotProps<TEnableAccessibleFieldDOMStructure extends boolean> extends ExportedUseMobilePickerSlotProps<TEnableAccessibleFieldDOMStructure>, Pick<PickersLayoutSlotProps<PickerValue>, 'toolbar'> {}
|
||||
export interface MobileOnlyPickerProps extends UsePickerNonStaticProps {}
|
||||
export interface UseMobilePickerProps<TView extends DateOrTimeViewWithMeridiem, TEnableAccessibleFieldDOMStructure extends boolean, TError, TExternalProps extends UsePickerProps<PickerValue, TView, TError, any>> extends BasePickerProps<PickerValue, TView, TError, TExternalProps>, MakeRequired<MobileOnlyPickerProps, 'format'> {
|
||||
/**
|
||||
* Overridable component slots.
|
||||
* @default {}
|
||||
*/
|
||||
slots: UseMobilePickerSlots;
|
||||
/**
|
||||
* The props used for each component slot.
|
||||
* @default {}
|
||||
*/
|
||||
slotProps?: UseMobilePickerSlotProps<TEnableAccessibleFieldDOMStructure>;
|
||||
}
|
||||
export interface UseMobilePickerParams<TView extends DateOrTimeViewWithMeridiem, TEnableAccessibleFieldDOMStructure extends boolean, TExternalProps extends UseMobilePickerProps<TView, TEnableAccessibleFieldDOMStructure, any, TExternalProps>> extends Pick<UsePickerParameters<PickerValue, TView, TExternalProps>, 'valueManager' | 'valueType' | 'validator' | 'ref'> {
|
||||
props: TExternalProps;
|
||||
/**
|
||||
* Steps available for the picker.
|
||||
* This will be used to define the behavior of navigation actions.
|
||||
* If null, the picker will not have any step navigation.
|
||||
*/
|
||||
steps: PickerStep[] | null;
|
||||
}
|
||||
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/useMobilePicker/useMobilePicker.types.js
generated
vendored
Normal file
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/useMobilePicker/useMobilePicker.types.js
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
export {};
|
||||
9
node_modules/@mui/x-date-pickers/esm/internals/hooks/useNullableFieldPrivateContext.d.ts
generated
vendored
Normal file
9
node_modules/@mui/x-date-pickers/esm/internals/hooks/useNullableFieldPrivateContext.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import * as React from 'react';
|
||||
import type { UseFieldInternalProps } from "./useField/index.js";
|
||||
import { FieldRef } from "../../models/index.js";
|
||||
import { PickerRangeValue, PickerValue } from "../models/index.js";
|
||||
export declare const PickerFieldPrivateContext: React.Context<PickerFieldPrivateContextValue | null>;
|
||||
export declare function useNullableFieldPrivateContext(): PickerFieldPrivateContextValue | null;
|
||||
export interface PickerFieldPrivateContextValue extends Pick<UseFieldInternalProps<any, any, any>, 'formatDensity' | 'enableAccessibleFieldDOMStructure' | 'selectedSections' | 'onSelectedSectionsChange'> {
|
||||
fieldRef: React.RefObject<FieldRef<PickerValue> | FieldRef<PickerRangeValue> | null>;
|
||||
}
|
||||
8
node_modules/@mui/x-date-pickers/esm/internals/hooks/useNullableFieldPrivateContext.js
generated
vendored
Normal file
8
node_modules/@mui/x-date-pickers/esm/internals/hooks/useNullableFieldPrivateContext.js
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
export const PickerFieldPrivateContext = /*#__PURE__*/React.createContext(null);
|
||||
if (process.env.NODE_ENV !== "production") PickerFieldPrivateContext.displayName = "PickerFieldPrivateContext";
|
||||
export function useNullableFieldPrivateContext() {
|
||||
return React.useContext(PickerFieldPrivateContext);
|
||||
}
|
||||
5
node_modules/@mui/x-date-pickers/esm/internals/hooks/useNullablePickerContext.d.ts
generated
vendored
Normal file
5
node_modules/@mui/x-date-pickers/esm/internals/hooks/useNullablePickerContext.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
/**
|
||||
* Returns the context passed by the Picker wrapping the current component.
|
||||
* If the context is not found, returns `null`.
|
||||
*/
|
||||
export declare const useNullablePickerContext: () => import("../index.js").PickerContextValue<any, any, any> | null;
|
||||
10
node_modules/@mui/x-date-pickers/esm/internals/hooks/useNullablePickerContext.js
generated
vendored
Normal file
10
node_modules/@mui/x-date-pickers/esm/internals/hooks/useNullablePickerContext.js
generated
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { PickerContext } from "../../hooks/usePickerContext.js";
|
||||
|
||||
/**
|
||||
* Returns the context passed by the Picker wrapping the current component.
|
||||
* If the context is not found, returns `null`.
|
||||
*/
|
||||
export const useNullablePickerContext = () => React.useContext(PickerContext);
|
||||
2
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/hooks/useOrientation.d.ts
generated
vendored
Normal file
2
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/hooks/useOrientation.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
import { DateOrTimeViewWithMeridiem, PickerOrientation } from "../../../models/index.js";
|
||||
export declare function useOrientation(views: readonly DateOrTimeViewWithMeridiem[], customOrientation: PickerOrientation | undefined): PickerOrientation;
|
||||
36
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/hooks/useOrientation.js
generated
vendored
Normal file
36
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/hooks/useOrientation.js
generated
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import useEnhancedEffect from '@mui/utils/useEnhancedEffect';
|
||||
import { arrayIncludes } from "../../../utils/utils.js";
|
||||
function getOrientation() {
|
||||
if (typeof window === 'undefined') {
|
||||
return 'portrait';
|
||||
}
|
||||
if (window.screen && window.screen.orientation && window.screen.orientation.angle) {
|
||||
return Math.abs(window.screen.orientation.angle) === 90 ? 'landscape' : 'portrait';
|
||||
}
|
||||
|
||||
// Support IOS safari
|
||||
if (window.orientation) {
|
||||
return Math.abs(Number(window.orientation)) === 90 ? 'landscape' : 'portrait';
|
||||
}
|
||||
return 'portrait';
|
||||
}
|
||||
export function useOrientation(views, customOrientation) {
|
||||
const [orientation, setOrientation] = React.useState(getOrientation);
|
||||
useEnhancedEffect(() => {
|
||||
const eventHandler = () => {
|
||||
setOrientation(getOrientation());
|
||||
};
|
||||
window.addEventListener('orientationchange', eventHandler);
|
||||
return () => {
|
||||
window.removeEventListener('orientationchange', eventHandler);
|
||||
};
|
||||
}, []);
|
||||
if (arrayIncludes(views, ['hours', 'minutes', 'seconds'])) {
|
||||
// could not display 13:34:44 in landscape mode
|
||||
return 'portrait';
|
||||
}
|
||||
return customOrientation ?? orientation;
|
||||
}
|
||||
21
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/hooks/useValueAndOpenStates.d.ts
generated
vendored
Normal file
21
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/hooks/useValueAndOpenStates.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react';
|
||||
import { DateOrTimeViewWithMeridiem, PickerValidValue, PickerValueManager } from "../../../models/index.js";
|
||||
import { PickerSelectionState, UsePickerProps, UsePickerState } from "../usePicker.types.js";
|
||||
import { InferError } from "../../../../models/index.js";
|
||||
import { SetValueActionOptions } from "../../../components/PickerProvider.js";
|
||||
import { Validator } from "../../../../validation/index.js";
|
||||
export declare function useValueAndOpenStates<TValue extends PickerValidValue, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UsePickerProps<TValue, TView, any, any>>(parameters: UsePickerDateStateParameters<TValue, TView, TExternalProps>): {
|
||||
timezone: string;
|
||||
state: UsePickerState<TValue>;
|
||||
setValue: (newValue: TValue, options?: SetValueActionOptions<InferError<TExternalProps>>) => void;
|
||||
setValueFromView: (newValue: TValue, selectionState?: PickerSelectionState) => void;
|
||||
setOpen: (action: React.SetStateAction<boolean>) => void;
|
||||
value: TValue;
|
||||
viewValue: TValue;
|
||||
};
|
||||
interface UsePickerDateStateParameters<TValue extends PickerValidValue, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UsePickerProps<TValue, TView, any, any>> {
|
||||
props: TExternalProps;
|
||||
valueManager: PickerValueManager<TValue, InferError<TExternalProps>>;
|
||||
validator: Validator<TValue, InferError<TExternalProps>, TExternalProps>;
|
||||
}
|
||||
export {};
|
||||
194
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/hooks/useValueAndOpenStates.js
generated
vendored
Normal file
194
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/hooks/useValueAndOpenStates.js
generated
vendored
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
'use client';
|
||||
|
||||
import _extends from "@babel/runtime/helpers/esm/extends";
|
||||
import * as React from 'react';
|
||||
import { warnOnce } from '@mui/x-internals/warning';
|
||||
import useEventCallback from '@mui/utils/useEventCallback';
|
||||
import { useControlledValue } from "../../useControlledValue.js";
|
||||
import { usePickerAdapter } from "../../../../hooks/usePickerAdapter.js";
|
||||
import { useValidation } from "../../../../validation/index.js";
|
||||
export function useValueAndOpenStates(parameters) {
|
||||
const {
|
||||
props,
|
||||
valueManager,
|
||||
validator
|
||||
} = parameters;
|
||||
const {
|
||||
value: valueProp,
|
||||
defaultValue: defaultValueProp,
|
||||
onChange,
|
||||
referenceDate,
|
||||
timezone: timezoneProp,
|
||||
onAccept,
|
||||
closeOnSelect,
|
||||
open: openProp,
|
||||
onOpen,
|
||||
onClose
|
||||
} = props;
|
||||
const {
|
||||
current: defaultValue
|
||||
} = React.useRef(defaultValueProp);
|
||||
const {
|
||||
current: isValueControlled
|
||||
} = React.useRef(valueProp !== undefined);
|
||||
const {
|
||||
current: isOpenControlled
|
||||
} = React.useRef(openProp !== undefined);
|
||||
const adapter = usePickerAdapter();
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (props.renderInput != null) {
|
||||
warnOnce(['MUI X: The `renderInput` prop has been removed in version 6.0 of the Date and Time Pickers.', 'You can replace it with the `textField` component slot in most cases.', 'For more information, please have a look at the migration guide (https://mui.com/x/migration/migration-pickers-v5/#input-renderer-required-in-v5).']);
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-disable react-hooks/rules-of-hooks, react-hooks/exhaustive-deps */
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
React.useEffect(() => {
|
||||
if (isValueControlled !== (valueProp !== undefined)) {
|
||||
console.error([`MUI X: A component is changing the ${isValueControlled ? '' : 'un'}controlled value of a Picker to be ${isValueControlled ? 'un' : ''}controlled.`, 'Elements should not switch from uncontrolled to controlled (or vice versa).', `Decide between using a controlled or uncontrolled value` + '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'));
|
||||
}
|
||||
}, [valueProp]);
|
||||
React.useEffect(() => {
|
||||
if (!isValueControlled && defaultValue !== defaultValueProp) {
|
||||
console.error([`MUI X: A component is changing the defaultValue of an uncontrolled Picker after being initialized. ` + `To suppress this warning opt to use a controlled value.`].join('\n'));
|
||||
}
|
||||
}, [JSON.stringify(defaultValue)]);
|
||||
}
|
||||
/* eslint-enable react-hooks/rules-of-hooks, react-hooks/exhaustive-deps */
|
||||
|
||||
const {
|
||||
timezone,
|
||||
value,
|
||||
handleValueChange
|
||||
} = useControlledValue({
|
||||
name: 'a picker component',
|
||||
timezone: timezoneProp,
|
||||
value: valueProp,
|
||||
defaultValue,
|
||||
referenceDate,
|
||||
onChange,
|
||||
valueManager
|
||||
});
|
||||
const [state, setState] = React.useState(() => ({
|
||||
open: false,
|
||||
lastExternalValue: value,
|
||||
clockShallowValue: undefined,
|
||||
lastCommittedValue: value,
|
||||
hasBeenModifiedSinceMount: false
|
||||
}));
|
||||
const {
|
||||
getValidationErrorForNewValue
|
||||
} = useValidation({
|
||||
props,
|
||||
validator,
|
||||
timezone,
|
||||
value,
|
||||
onError: props.onError
|
||||
});
|
||||
const setOpen = useEventCallback(action => {
|
||||
const newOpen = typeof action === 'function' ? action(state.open) : action;
|
||||
if (!isOpenControlled) {
|
||||
setState(prevState => _extends({}, prevState, {
|
||||
open: newOpen
|
||||
}));
|
||||
}
|
||||
if (newOpen && onOpen) {
|
||||
onOpen();
|
||||
}
|
||||
if (!newOpen) {
|
||||
onClose?.();
|
||||
}
|
||||
});
|
||||
const setValue = useEventCallback((newValue, options) => {
|
||||
const {
|
||||
changeImportance = 'accept',
|
||||
skipPublicationIfPristine = false,
|
||||
validationError,
|
||||
shortcut,
|
||||
shouldClose = changeImportance === 'accept'
|
||||
} = options ?? {};
|
||||
let shouldFireOnChange;
|
||||
let shouldFireOnAccept;
|
||||
if (!skipPublicationIfPristine && !isValueControlled && !state.hasBeenModifiedSinceMount) {
|
||||
// If the value is not controlled and the value has never been modified before,
|
||||
// Then clicking on any value (including the one equal to `defaultValue`) should call `onChange` and `onAccept`
|
||||
shouldFireOnChange = true;
|
||||
shouldFireOnAccept = changeImportance === 'accept';
|
||||
} else {
|
||||
shouldFireOnChange = !valueManager.areValuesEqual(adapter, newValue, value);
|
||||
shouldFireOnAccept = changeImportance === 'accept' && !valueManager.areValuesEqual(adapter, newValue, state.lastCommittedValue);
|
||||
}
|
||||
setState(prevState => _extends({}, prevState, {
|
||||
// We reset the shallow value whenever we fire onChange.
|
||||
clockShallowValue: shouldFireOnChange ? undefined : prevState.clockShallowValue,
|
||||
lastCommittedValue: shouldFireOnAccept ? newValue : prevState.lastCommittedValue,
|
||||
hasBeenModifiedSinceMount: true
|
||||
}));
|
||||
let cachedContext = null;
|
||||
const getContext = () => {
|
||||
if (!cachedContext) {
|
||||
cachedContext = {
|
||||
validationError: validationError == null ? getValidationErrorForNewValue(newValue) : validationError
|
||||
};
|
||||
if (shortcut) {
|
||||
cachedContext.shortcut = shortcut;
|
||||
}
|
||||
}
|
||||
return cachedContext;
|
||||
};
|
||||
if (shouldFireOnChange) {
|
||||
handleValueChange(newValue, getContext());
|
||||
}
|
||||
if (shouldFireOnAccept && onAccept) {
|
||||
onAccept(newValue, getContext());
|
||||
}
|
||||
if (shouldClose) {
|
||||
setOpen(false);
|
||||
}
|
||||
});
|
||||
|
||||
// If `prop.value` changes, we update the state to reflect the new value
|
||||
if (value !== state.lastExternalValue) {
|
||||
setState(prevState => _extends({}, prevState, {
|
||||
lastExternalValue: value,
|
||||
clockShallowValue: undefined,
|
||||
hasBeenModifiedSinceMount: true
|
||||
}));
|
||||
}
|
||||
const setValueFromView = useEventCallback((newValue, selectionState = 'partial') => {
|
||||
// TODO: Expose a new method (private?) like `setView` that only updates the clock shallow value.
|
||||
if (selectionState === 'shallow') {
|
||||
setState(prev => _extends({}, prev, {
|
||||
clockShallowValue: newValue,
|
||||
hasBeenModifiedSinceMount: true
|
||||
}));
|
||||
return;
|
||||
}
|
||||
setValue(newValue, {
|
||||
changeImportance: selectionState === 'finish' && closeOnSelect ? 'accept' : 'set'
|
||||
});
|
||||
});
|
||||
|
||||
// It is required to update inner state in useEffect in order to avoid situation when
|
||||
// Our component is not mounted yet, but `open` state is set to `true` (for example initially opened)
|
||||
React.useEffect(() => {
|
||||
if (isOpenControlled) {
|
||||
if (openProp === undefined) {
|
||||
throw new Error('You must not mix controlling and uncontrolled mode for `open` prop');
|
||||
}
|
||||
setState(prevState => _extends({}, prevState, {
|
||||
open: openProp
|
||||
}));
|
||||
}
|
||||
}, [isOpenControlled, openProp]);
|
||||
const viewValue = React.useMemo(() => valueManager.cleanValue(adapter, state.clockShallowValue === undefined ? value : state.clockShallowValue), [adapter, valueManager, state.clockShallowValue, value]);
|
||||
return {
|
||||
timezone,
|
||||
state,
|
||||
setValue,
|
||||
setValueFromView,
|
||||
setOpen,
|
||||
value,
|
||||
viewValue
|
||||
};
|
||||
}
|
||||
2
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/index.d.ts
generated
vendored
Normal file
2
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export { usePicker } from "./usePicker.js";
|
||||
export type { UsePickerProps, UsePickerBaseProps, UsePickerParameters, PickerSelectionState, PickerViewsRendererProps, PickerViewRendererLookup, PickerRendererInterceptorProps, PickerViewRenderer, UsePickerNonStaticProps } from "./usePicker.types.js";
|
||||
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/index.js
generated
vendored
Normal file
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { usePicker } from "./usePicker.js";
|
||||
16
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/usePicker.d.ts
generated
vendored
Normal file
16
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/usePicker.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { UsePickerParameters, UsePickerProps, UsePickerReturnValue } from "./usePicker.types.js";
|
||||
import { DateOrTimeViewWithMeridiem, PickerValidValue } from "../../models/index.js";
|
||||
export declare const usePicker: <TValue extends PickerValidValue, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UsePickerProps<TValue, TView, any, any>>({
|
||||
ref,
|
||||
props,
|
||||
valueManager,
|
||||
valueType,
|
||||
variant,
|
||||
validator,
|
||||
onPopperExited,
|
||||
autoFocusView,
|
||||
rendererInterceptor: RendererInterceptor,
|
||||
localeText,
|
||||
viewContainerRole,
|
||||
getStepNavigation
|
||||
}: UsePickerParameters<TValue, TView, TExternalProps>) => UsePickerReturnValue<TValue>;
|
||||
315
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/usePicker.js
generated
vendored
Normal file
315
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/usePicker.js
generated
vendored
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
'use client';
|
||||
|
||||
import _extends from "@babel/runtime/helpers/esm/extends";
|
||||
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
||||
const _excluded = ["className", "sx"];
|
||||
import * as React from 'react';
|
||||
import useEnhancedEffect from '@mui/utils/useEnhancedEffect';
|
||||
import useEventCallback from '@mui/utils/useEventCallback';
|
||||
import useForkRef from '@mui/utils/useForkRef';
|
||||
import useId from '@mui/utils/useId';
|
||||
import { usePickerAdapter } from "../../../hooks/usePickerAdapter.js";
|
||||
import { useReduceAnimations } from "../useReduceAnimations.js";
|
||||
import { isTimeView } from "../../utils/time-utils.js";
|
||||
import { useViews } from "../useViews.js";
|
||||
import { useOrientation } from "./hooks/useOrientation.js";
|
||||
import { useValueAndOpenStates } from "./hooks/useValueAndOpenStates.js";
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
export const usePicker = ({
|
||||
ref,
|
||||
props,
|
||||
valueManager,
|
||||
valueType,
|
||||
variant,
|
||||
validator,
|
||||
onPopperExited,
|
||||
autoFocusView,
|
||||
rendererInterceptor: RendererInterceptor,
|
||||
localeText,
|
||||
viewContainerRole,
|
||||
getStepNavigation
|
||||
}) => {
|
||||
const {
|
||||
// View props
|
||||
views,
|
||||
view: viewProp,
|
||||
openTo,
|
||||
onViewChange,
|
||||
viewRenderers,
|
||||
reduceAnimations: reduceAnimationsProp,
|
||||
orientation: orientationProp,
|
||||
disableOpenPicker,
|
||||
closeOnSelect,
|
||||
// Form props
|
||||
disabled,
|
||||
readOnly,
|
||||
// Field props
|
||||
formatDensity,
|
||||
enableAccessibleFieldDOMStructure,
|
||||
selectedSections,
|
||||
onSelectedSectionsChange,
|
||||
format,
|
||||
label,
|
||||
// Other props
|
||||
autoFocus,
|
||||
name
|
||||
} = props;
|
||||
const {
|
||||
className,
|
||||
sx
|
||||
} = props,
|
||||
propsToForwardToView = _objectWithoutPropertiesLoose(props, _excluded);
|
||||
|
||||
/**
|
||||
* TODO: Improve how we generate the aria-label and aria-labelledby attributes.
|
||||
*/
|
||||
const labelId = useId();
|
||||
const adapter = usePickerAdapter();
|
||||
const reduceAnimations = useReduceAnimations(reduceAnimationsProp);
|
||||
const orientation = useOrientation(views, orientationProp);
|
||||
const {
|
||||
current: initialView
|
||||
} = React.useRef(openTo ?? null);
|
||||
|
||||
/**
|
||||
* Refs
|
||||
*/
|
||||
const [triggerElement, triggerRef] = React.useState(null);
|
||||
const popupRef = React.useRef(null);
|
||||
const fieldRef = React.useRef(null);
|
||||
const rootRefObject = React.useRef(null);
|
||||
const rootRef = useForkRef(ref, rootRefObject);
|
||||
const {
|
||||
timezone,
|
||||
state,
|
||||
setOpen,
|
||||
setValue,
|
||||
setValueFromView,
|
||||
value,
|
||||
viewValue
|
||||
} = useValueAndOpenStates({
|
||||
props,
|
||||
valueManager,
|
||||
validator
|
||||
});
|
||||
const {
|
||||
view,
|
||||
setView,
|
||||
defaultView,
|
||||
focusedView,
|
||||
setFocusedView,
|
||||
setValueAndGoToNextView,
|
||||
goToNextStep,
|
||||
hasNextStep,
|
||||
hasSeveralSteps
|
||||
} = useViews({
|
||||
view: viewProp,
|
||||
views,
|
||||
openTo,
|
||||
onChange: setValueFromView,
|
||||
onViewChange,
|
||||
autoFocus: autoFocusView,
|
||||
getStepNavigation
|
||||
});
|
||||
const clearValue = useEventCallback(() => setValue(valueManager.emptyValue));
|
||||
const setValueToToday = useEventCallback(() => setValue(valueManager.getTodayValue(adapter, timezone, valueType)));
|
||||
const acceptValueChanges = useEventCallback(() => setValue(value));
|
||||
const cancelValueChanges = useEventCallback(() => setValue(state.lastCommittedValue, {
|
||||
skipPublicationIfPristine: true
|
||||
}));
|
||||
const dismissViews = useEventCallback(() => {
|
||||
setValue(value, {
|
||||
skipPublicationIfPristine: true
|
||||
});
|
||||
});
|
||||
const {
|
||||
hasUIView,
|
||||
viewModeLookup,
|
||||
timeViewsCount
|
||||
} = React.useMemo(() => views.reduce((acc, viewForReduce) => {
|
||||
const viewMode = viewRenderers[viewForReduce] == null ? 'field' : 'UI';
|
||||
acc.viewModeLookup[viewForReduce] = viewMode;
|
||||
if (viewMode === 'UI') {
|
||||
acc.hasUIView = true;
|
||||
if (isTimeView(viewForReduce)) {
|
||||
acc.timeViewsCount += 1;
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, {
|
||||
hasUIView: false,
|
||||
viewModeLookup: {},
|
||||
timeViewsCount: 0
|
||||
}), [viewRenderers, views]);
|
||||
const currentViewMode = viewModeLookup[view];
|
||||
const getCurrentViewMode = useEventCallback(() => currentViewMode);
|
||||
const [popperView, setPopperView] = React.useState(currentViewMode === 'UI' ? view : null);
|
||||
if (popperView !== view && viewModeLookup[view] === 'UI') {
|
||||
setPopperView(view);
|
||||
}
|
||||
useEnhancedEffect(() => {
|
||||
// Handle case of Date Time Picker without time renderers
|
||||
if (currentViewMode === 'field' && state.open) {
|
||||
setOpen(false);
|
||||
setTimeout(() => {
|
||||
fieldRef?.current?.setSelectedSections(view);
|
||||
// focusing the input before the range selection is done
|
||||
// calling it outside of timeout results in an inconsistent behavior between Safari And Chrome
|
||||
fieldRef?.current?.focusField(view);
|
||||
});
|
||||
}
|
||||
}, [view]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
useEnhancedEffect(() => {
|
||||
if (!state.open) {
|
||||
return;
|
||||
}
|
||||
let newView = view;
|
||||
|
||||
// If the current view is a field view, go to the last popper view
|
||||
if (currentViewMode === 'field' && popperView != null) {
|
||||
newView = popperView;
|
||||
}
|
||||
|
||||
// If the current view is not the default view and both are UI views
|
||||
if (newView !== defaultView && viewModeLookup[newView] === 'UI' && viewModeLookup[defaultView] === 'UI') {
|
||||
newView = defaultView;
|
||||
}
|
||||
if (newView !== view) {
|
||||
setView(newView);
|
||||
}
|
||||
setFocusedView(newView, true);
|
||||
}, [state.open]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const ownerState = React.useMemo(() => ({
|
||||
isPickerValueEmpty: valueManager.areValuesEqual(adapter, value, valueManager.emptyValue),
|
||||
isPickerOpen: state.open,
|
||||
isPickerDisabled: props.disabled ?? false,
|
||||
isPickerReadOnly: props.readOnly ?? false,
|
||||
pickerOrientation: orientation,
|
||||
pickerVariant: variant
|
||||
}), [adapter, valueManager, value, state.open, orientation, variant, props.disabled, props.readOnly]);
|
||||
const triggerStatus = React.useMemo(() => {
|
||||
if (disableOpenPicker || !hasUIView) {
|
||||
return 'hidden';
|
||||
}
|
||||
if (disabled || readOnly) {
|
||||
return 'disabled';
|
||||
}
|
||||
return 'enabled';
|
||||
}, [disableOpenPicker, hasUIView, disabled, readOnly]);
|
||||
const wrappedGoToNextStep = useEventCallback(goToNextStep);
|
||||
const defaultActionBarActions = React.useMemo(() => {
|
||||
if (closeOnSelect && !hasSeveralSteps) {
|
||||
return [];
|
||||
}
|
||||
return ['cancel', 'nextOrAccept'];
|
||||
}, [closeOnSelect, hasSeveralSteps]);
|
||||
const actionsContextValue = React.useMemo(() => ({
|
||||
setValue,
|
||||
setOpen,
|
||||
clearValue,
|
||||
setValueToToday,
|
||||
acceptValueChanges,
|
||||
cancelValueChanges,
|
||||
setView,
|
||||
goToNextStep: wrappedGoToNextStep
|
||||
}), [setValue, setOpen, clearValue, setValueToToday, acceptValueChanges, cancelValueChanges, setView, wrappedGoToNextStep]);
|
||||
const contextValue = React.useMemo(() => _extends({}, actionsContextValue, {
|
||||
value,
|
||||
timezone,
|
||||
open: state.open,
|
||||
views,
|
||||
view: popperView,
|
||||
initialView,
|
||||
disabled: disabled ?? false,
|
||||
readOnly: readOnly ?? false,
|
||||
autoFocus: autoFocus ?? false,
|
||||
variant,
|
||||
orientation,
|
||||
popupRef,
|
||||
reduceAnimations,
|
||||
triggerRef,
|
||||
triggerStatus,
|
||||
hasNextStep,
|
||||
fieldFormat: format ?? '',
|
||||
name,
|
||||
label,
|
||||
rootSx: sx,
|
||||
rootRef,
|
||||
rootClassName: className
|
||||
}), [actionsContextValue, value, rootRef, variant, orientation, reduceAnimations, disabled, readOnly, format, className, name, label, sx, triggerStatus, hasNextStep, timezone, state.open, popperView, views, initialView, autoFocus]);
|
||||
const privateContextValue = React.useMemo(() => ({
|
||||
dismissViews,
|
||||
ownerState,
|
||||
hasUIView,
|
||||
getCurrentViewMode,
|
||||
rootRefObject,
|
||||
labelId,
|
||||
triggerElement,
|
||||
viewContainerRole,
|
||||
defaultActionBarActions,
|
||||
onPopperExited
|
||||
}), [dismissViews, ownerState, hasUIView, getCurrentViewMode, labelId, triggerElement, viewContainerRole, defaultActionBarActions, onPopperExited]);
|
||||
const fieldPrivateContextValue = React.useMemo(() => ({
|
||||
formatDensity,
|
||||
enableAccessibleFieldDOMStructure,
|
||||
selectedSections,
|
||||
onSelectedSectionsChange,
|
||||
fieldRef
|
||||
}), [formatDensity, enableAccessibleFieldDOMStructure, selectedSections, onSelectedSectionsChange, fieldRef]);
|
||||
const isValidContextValue = testedValue => {
|
||||
const error = validator({
|
||||
adapter,
|
||||
value: testedValue,
|
||||
timezone,
|
||||
props
|
||||
});
|
||||
return !valueManager.hasError(error);
|
||||
};
|
||||
const renderCurrentView = () => {
|
||||
if (popperView == null) {
|
||||
return null;
|
||||
}
|
||||
const renderer = viewRenderers[popperView];
|
||||
if (renderer == null) {
|
||||
return null;
|
||||
}
|
||||
const rendererProps = _extends({}, propsToForwardToView, {
|
||||
views,
|
||||
timezone,
|
||||
value: viewValue,
|
||||
onChange: setValueAndGoToNextView,
|
||||
view: popperView,
|
||||
onViewChange: setView,
|
||||
showViewSwitcher: timeViewsCount > 1,
|
||||
timeViewsCount
|
||||
}, viewContainerRole === 'tooltip' ? {
|
||||
focusedView: null,
|
||||
onFocusedViewChange: () => {}
|
||||
} : {
|
||||
focusedView,
|
||||
onFocusedViewChange: setFocusedView
|
||||
});
|
||||
if (RendererInterceptor) {
|
||||
return /*#__PURE__*/_jsx(RendererInterceptor, {
|
||||
viewRenderers: viewRenderers,
|
||||
popperView: popperView,
|
||||
rendererProps: rendererProps
|
||||
});
|
||||
}
|
||||
return renderer(rendererProps);
|
||||
};
|
||||
return {
|
||||
providerProps: {
|
||||
localeText,
|
||||
contextValue,
|
||||
privateContextValue,
|
||||
actionsContextValue,
|
||||
fieldPrivateContextValue,
|
||||
isValidContextValue
|
||||
},
|
||||
renderCurrentView,
|
||||
ownerState
|
||||
};
|
||||
};
|
||||
187
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/usePicker.types.d.ts
generated
vendored
Normal file
187
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/usePicker.types.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
import { SxProps } from '@mui/system';
|
||||
import { Theme } from '@mui/material/styles';
|
||||
import { InferError, OnErrorProps, PickerChangeHandlerContext, PickerOwnerState, PickerValidDate, PickerValueType, TimezoneProps } from "../../../models/index.js";
|
||||
import { DateOrTimeViewWithMeridiem, FormProps, PickerOrientation, PickerRangeValue, PickerValidValue, PickerValueManager, PickerVariant } from "../../models/index.js";
|
||||
import { Validator } from "../../../validation/index.js";
|
||||
import { UseViewsOptions } from "../useViews.js";
|
||||
import { PickerProviderProps } from "../../components/PickerProvider.js";
|
||||
import { PickersInputLocaleText } from "../../../locales/index.js";
|
||||
import { PickerFieldPrivateContextValue } from "../useNullableFieldPrivateContext.js";
|
||||
import { CreateStepNavigationReturnValue } from "../../utils/createStepNavigation.js";
|
||||
/**
|
||||
* Props common to all Picker headless implementations.
|
||||
* Those props are exposed on all the Pickers.
|
||||
*/
|
||||
export interface UsePickerBaseProps<TValue extends PickerValidValue, TView extends DateOrTimeViewWithMeridiem, TError, TExternalProps extends UsePickerProps<TValue, TView, TError, any>> extends OnErrorProps<TValue, TError>, Omit<UseViewsOptions<any, TView>, 'onChange' | 'onFocusedViewChange' | 'focusedView' | 'getStepNavigation'>, TimezoneProps, FormProps {
|
||||
/**
|
||||
* The selected value.
|
||||
* Used when the component is controlled.
|
||||
*/
|
||||
value?: TValue;
|
||||
/**
|
||||
* The default value.
|
||||
* Used when the component is not controlled.
|
||||
*/
|
||||
defaultValue?: TValue;
|
||||
/**
|
||||
* Callback fired when the value changes.
|
||||
* @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @template TError The validation error type. It will be either `string` or a `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @param {TValue} value The new value.
|
||||
* @param {FieldChangeHandlerContext<TError>} context The context containing the validation result of the current value.
|
||||
*/
|
||||
onChange?: (value: TValue, context: PickerChangeHandlerContext<TError>) => void;
|
||||
/**
|
||||
* Callback fired when the value is accepted.
|
||||
* @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @template TError The validation error type. It will be either `string` or a `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @param {TValue} value The value that was just accepted.
|
||||
* @param {FieldChangeHandlerContext<TError>} context The context containing the validation result of the current value.
|
||||
*/
|
||||
onAccept?: (value: TValue, context: PickerChangeHandlerContext<TError>) => void;
|
||||
/**
|
||||
* If `null`, the section will only have field editing.
|
||||
* If `undefined`, internally defined view will be used.
|
||||
*/
|
||||
viewRenderers: PickerViewRendererLookup<TValue, TView, TExternalProps>;
|
||||
/**
|
||||
* The date used to generate the new value when both `value` and `defaultValue` are empty.
|
||||
* @default The closest valid date-time using the validation props, except callbacks like `shouldDisable<...>`.
|
||||
*/
|
||||
referenceDate?: TValue extends PickerRangeValue ? TValue | PickerValidDate : PickerValidDate;
|
||||
/**
|
||||
* Force rendering in particular orientation.
|
||||
*/
|
||||
orientation?: PickerOrientation;
|
||||
/**
|
||||
* If `true`, disable heavy animations.
|
||||
* @default `@media(prefers-reduced-motion: reduce)` || `navigator.userAgent` matches Android <10 or iOS <13
|
||||
*/
|
||||
reduceAnimations?: boolean;
|
||||
}
|
||||
/**
|
||||
* Props used to handle the value of non-static Pickers.
|
||||
*/
|
||||
export interface UsePickerNonStaticProps extends Omit<PickerFieldPrivateContextValue, 'fieldRef'> {
|
||||
/**
|
||||
* If `true`, the Picker will close after submitting the full date.
|
||||
* @default false
|
||||
*/
|
||||
closeOnSelect?: boolean;
|
||||
/**
|
||||
* Control the popup or dialog open state.
|
||||
* @default false
|
||||
*/
|
||||
open?: boolean;
|
||||
/**
|
||||
* Callback fired when the popup requests to be closed.
|
||||
* Use in controlled mode (see `open`).
|
||||
*/
|
||||
onClose?: () => void;
|
||||
/**
|
||||
* Callback fired when the popup requests to be opened.
|
||||
* Use in controlled mode (see `open`).
|
||||
*/
|
||||
onOpen?: () => void;
|
||||
/**
|
||||
* Format of the date when rendered in the input(s).
|
||||
* Defaults to localized format based on the used `views`.
|
||||
*/
|
||||
format?: string;
|
||||
/**
|
||||
* If `true`, the button to open the Picker will not be rendered (it will only render the field).
|
||||
* @deprecated Use the [field component](https://mui.com/x/react-date-pickers/fields/) instead.
|
||||
* @default false
|
||||
*/
|
||||
disableOpenPicker?: boolean;
|
||||
/**
|
||||
* The label content.
|
||||
*/
|
||||
label?: React.ReactNode;
|
||||
/**
|
||||
* Pass a ref to the `input` element.
|
||||
*/
|
||||
inputRef?: React.Ref<HTMLInputElement>;
|
||||
/**
|
||||
* Name attribute used by the `input` element in the Field.
|
||||
*/
|
||||
name?: string;
|
||||
}
|
||||
export interface UsePickerProps<TValue extends PickerValidValue, TView extends DateOrTimeViewWithMeridiem, TError, TExternalProps extends UsePickerProps<TValue, TView, TError, any>> extends UsePickerBaseProps<TValue, TView, TError, TExternalProps>, UsePickerNonStaticProps {
|
||||
referenceDate?: TValue extends PickerRangeValue ? TValue | PickerValidDate : PickerValidDate;
|
||||
className?: string;
|
||||
sx?: SxProps<Theme>;
|
||||
}
|
||||
export interface UsePickerParameters<TValue extends PickerValidValue, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UsePickerProps<TValue, TView, any, any>> {
|
||||
ref: React.ForwardedRef<HTMLDivElement> | undefined;
|
||||
localeText: PickersInputLocaleText | undefined;
|
||||
variant: PickerVariant;
|
||||
valueManager: PickerValueManager<TValue, InferError<TExternalProps>>;
|
||||
valueType: PickerValueType;
|
||||
validator: Validator<TValue, InferError<TExternalProps>, TExternalProps>;
|
||||
autoFocusView: boolean;
|
||||
viewContainerRole: 'dialog' | 'tooltip' | null;
|
||||
/**
|
||||
* A function that intercepts the regular Picker rendering.
|
||||
* Can be used to consume the provided `viewRenderers` and render a custom component wrapping them.
|
||||
* @param {PickerViewRendererLookup<TValue, TView, TExternalProps>} viewRenderers The `viewRenderers` provided to the Picker component.
|
||||
* @param {TView} popperView The current Picker view.
|
||||
* @param {any} rendererProps All the props being passed down to the renderer.
|
||||
* @returns {React.ReactNode} A React node that will be rendered instead of the default renderer.
|
||||
*/
|
||||
rendererInterceptor?: React.JSXElementConstructor<PickerRendererInterceptorProps<TValue, TView, TExternalProps>>;
|
||||
props: TExternalProps;
|
||||
getStepNavigation: CreateStepNavigationReturnValue;
|
||||
onPopperExited?: () => void;
|
||||
}
|
||||
export interface UsePickerReturnValue<TValue extends PickerValidValue> {
|
||||
ownerState: PickerOwnerState;
|
||||
renderCurrentView: () => React.ReactNode;
|
||||
providerProps: Omit<PickerProviderProps<TValue>, 'children'>;
|
||||
}
|
||||
export type PickerSelectionState = 'partial' | 'shallow' | 'finish';
|
||||
export interface UsePickerState<TValue extends PickerValidValue> {
|
||||
/**
|
||||
* Whether the Picker is open.
|
||||
*/
|
||||
open: boolean;
|
||||
/**
|
||||
* Last value returned by `useControlledValue`.
|
||||
*/
|
||||
lastExternalValue: TValue;
|
||||
/**
|
||||
* Date currently displayed on the views if we are dragging the cursor in the Clock component.
|
||||
*/
|
||||
clockShallowValue: TValue | undefined;
|
||||
/**
|
||||
* Last value committed (the last value for which `shouldCommitValue` returned `true`).
|
||||
* If `onAccept` is defined, it's the value that was passed on the last call to this callback.
|
||||
*/
|
||||
lastCommittedValue: TValue;
|
||||
/**
|
||||
* If we never modified the value since the mount of the component,
|
||||
* Then we might want to apply some custom logic.
|
||||
*
|
||||
* For example, when the component is not controlled and `defaultValue` is defined.
|
||||
* Then clicking on "Accept", "Today" or "Clear" should fire `onAccept` with `defaultValue`, but clicking on "Cancel" or dismissing the Picker should not.
|
||||
*/
|
||||
hasBeenModifiedSinceMount: boolean;
|
||||
}
|
||||
export interface PickerViewsRendererBaseExternalProps extends Omit<UsePickerProps<any, any, any, any>, 'openTo' | 'viewRenderers' | 'onChange'> {}
|
||||
export type PickerViewsRendererProps<TValue extends PickerValidValue, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends PickerViewsRendererBaseExternalProps> = Omit<TExternalProps, 'className' | 'sx'> & {
|
||||
value: TValue;
|
||||
onChange: (value: TValue, selectionState?: PickerSelectionState) => void;
|
||||
view: TView;
|
||||
views: readonly TView[];
|
||||
focusedView: TView | null;
|
||||
onFocusedViewChange: (viewToFocus: TView, hasFocus: boolean) => void;
|
||||
showViewSwitcher: boolean;
|
||||
timeViewsCount: number;
|
||||
};
|
||||
export type PickerViewRenderer<TValue extends PickerValidValue, TExternalProps extends PickerViewsRendererBaseExternalProps> = (props: PickerViewsRendererProps<TValue, any, TExternalProps>) => React.ReactNode;
|
||||
export type PickerViewRendererLookup<TValue extends PickerValidValue, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends PickerViewsRendererBaseExternalProps> = Record<TView, PickerViewRenderer<TValue, TExternalProps> | null>;
|
||||
export interface PickerRendererInterceptorProps<TValue extends PickerValidValue, TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UsePickerProps<TValue, TView, any, TExternalProps>> {
|
||||
viewRenderers: PickerViewRendererLookup<TValue, TView, TExternalProps>;
|
||||
popperView: TView;
|
||||
rendererProps: PickerViewsRendererProps<TValue, TView, TExternalProps>;
|
||||
}
|
||||
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/usePicker.types.js
generated
vendored
Normal file
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePicker/usePicker.types.js
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
export {};
|
||||
4
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePickerPrivateContext.d.ts
generated
vendored
Normal file
4
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePickerPrivateContext.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Returns the private context passed by the Picker wrapping the current component.
|
||||
*/
|
||||
export declare const usePickerPrivateContext: () => import("../components/PickerProvider.js").PickerPrivateContextValue;
|
||||
9
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePickerPrivateContext.js
generated
vendored
Normal file
9
node_modules/@mui/x-date-pickers/esm/internals/hooks/usePickerPrivateContext.js
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { PickerPrivateContext } from "../components/PickerProvider.js";
|
||||
|
||||
/**
|
||||
* Returns the private context passed by the Picker wrapping the current component.
|
||||
*/
|
||||
export const usePickerPrivateContext = () => React.useContext(PickerPrivateContext);
|
||||
2
node_modules/@mui/x-date-pickers/esm/internals/hooks/useReduceAnimations.d.ts
generated
vendored
Normal file
2
node_modules/@mui/x-date-pickers/esm/internals/hooks/useReduceAnimations.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export declare const slowAnimationDevices: boolean;
|
||||
export declare function useReduceAnimations(customReduceAnimations: boolean | undefined): boolean;
|
||||
17
node_modules/@mui/x-date-pickers/esm/internals/hooks/useReduceAnimations.js
generated
vendored
Normal file
17
node_modules/@mui/x-date-pickers/esm/internals/hooks/useReduceAnimations.js
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import useMediaQuery from '@mui/material/useMediaQuery';
|
||||
const PREFERS_REDUCED_MOTION = '@media (prefers-reduced-motion: reduce)';
|
||||
|
||||
// detect if user agent has Android version < 10 or iOS version < 13
|
||||
const mobileVersionMatches = typeof navigator !== 'undefined' && navigator.userAgent.match(/android\s(\d+)|OS\s(\d+)/i);
|
||||
const androidVersion = mobileVersionMatches && mobileVersionMatches[1] ? parseInt(mobileVersionMatches[1], 10) : null;
|
||||
const iOSVersion = mobileVersionMatches && mobileVersionMatches[2] ? parseInt(mobileVersionMatches[2], 10) : null;
|
||||
export const slowAnimationDevices = androidVersion && androidVersion < 10 || iOSVersion && iOSVersion < 13 || false;
|
||||
export function useReduceAnimations(customReduceAnimations) {
|
||||
const prefersReduced = useMediaQuery(PREFERS_REDUCED_MOTION, {
|
||||
defaultMatches: false
|
||||
});
|
||||
if (customReduceAnimations != null) {
|
||||
return customReduceAnimations;
|
||||
}
|
||||
return prefersReduced || slowAnimationDevices;
|
||||
}
|
||||
2
node_modules/@mui/x-date-pickers/esm/internals/hooks/useStaticPicker/index.d.ts
generated
vendored
Normal file
2
node_modules/@mui/x-date-pickers/esm/internals/hooks/useStaticPicker/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export { useStaticPicker } from "./useStaticPicker.js";
|
||||
export type { UseStaticPickerSlots, UseStaticPickerSlotProps, StaticOnlyPickerProps } from "./useStaticPicker.types.js";
|
||||
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/useStaticPicker/index.js
generated
vendored
Normal file
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/useStaticPicker/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { useStaticPicker } from "./useStaticPicker.js";
|
||||
16
node_modules/@mui/x-date-pickers/esm/internals/hooks/useStaticPicker/useStaticPicker.d.ts
generated
vendored
Normal file
16
node_modules/@mui/x-date-pickers/esm/internals/hooks/useStaticPicker/useStaticPicker.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import * as React from 'react';
|
||||
import { UseStaticPickerParams, UseStaticPickerProps } from "./useStaticPicker.types.js";
|
||||
import { DateOrTimeViewWithMeridiem } from "../../models/index.js";
|
||||
/**
|
||||
* Hook managing all the single-date static pickers:
|
||||
* - StaticDatePicker
|
||||
* - StaticDateTimePicker
|
||||
* - StaticTimePicker
|
||||
*/
|
||||
export declare const useStaticPicker: <TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseStaticPickerProps<TView, any, TExternalProps>>({
|
||||
props,
|
||||
steps,
|
||||
...pickerParams
|
||||
}: UseStaticPickerParams<TView, TExternalProps>) => {
|
||||
renderPicker: () => React.JSX.Element;
|
||||
};
|
||||
70
node_modules/@mui/x-date-pickers/esm/internals/hooks/useStaticPicker/useStaticPicker.js
generated
vendored
Normal file
70
node_modules/@mui/x-date-pickers/esm/internals/hooks/useStaticPicker/useStaticPicker.js
generated
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import _extends from "@babel/runtime/helpers/esm/extends";
|
||||
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
||||
const _excluded = ["props", "steps"];
|
||||
import * as React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import { usePicker } from "../usePicker/index.js";
|
||||
import { PickerProvider } from "../../components/PickerProvider.js";
|
||||
import { PickersLayout } from "../../../PickersLayout/index.js";
|
||||
import { DIALOG_WIDTH } from "../../constants/dimensions.js";
|
||||
import { mergeSx } from "../../utils/utils.js";
|
||||
import { createNonRangePickerStepNavigation } from "../../utils/createNonRangePickerStepNavigation.js";
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
const PickerStaticLayout = styled(PickersLayout)(({
|
||||
theme
|
||||
}) => ({
|
||||
overflow: 'hidden',
|
||||
minWidth: DIALOG_WIDTH,
|
||||
backgroundColor: (theme.vars || theme).palette.background.paper
|
||||
}));
|
||||
|
||||
/**
|
||||
* Hook managing all the single-date static pickers:
|
||||
* - StaticDatePicker
|
||||
* - StaticDateTimePicker
|
||||
* - StaticTimePicker
|
||||
*/
|
||||
export const useStaticPicker = _ref => {
|
||||
let {
|
||||
props,
|
||||
steps
|
||||
} = _ref,
|
||||
pickerParams = _objectWithoutPropertiesLoose(_ref, _excluded);
|
||||
const {
|
||||
localeText,
|
||||
slots,
|
||||
slotProps,
|
||||
displayStaticWrapperAs,
|
||||
autoFocus
|
||||
} = props;
|
||||
const getStepNavigation = createNonRangePickerStepNavigation({
|
||||
steps
|
||||
});
|
||||
const {
|
||||
providerProps,
|
||||
renderCurrentView
|
||||
} = usePicker(_extends({}, pickerParams, {
|
||||
props,
|
||||
variant: displayStaticWrapperAs,
|
||||
autoFocusView: autoFocus ?? false,
|
||||
viewContainerRole: null,
|
||||
localeText,
|
||||
getStepNavigation
|
||||
}));
|
||||
const Layout = slots?.layout ?? PickerStaticLayout;
|
||||
const renderPicker = () => /*#__PURE__*/_jsx(PickerProvider, _extends({}, providerProps, {
|
||||
children: /*#__PURE__*/_jsx(Layout, _extends({}, slotProps?.layout, {
|
||||
slots: slots,
|
||||
slotProps: slotProps,
|
||||
sx: mergeSx(providerProps.contextValue.rootSx, slotProps?.layout?.sx),
|
||||
className: clsx(providerProps.contextValue.rootClassName, slotProps?.layout?.className),
|
||||
ref: providerProps.contextValue.rootRef,
|
||||
children: renderCurrentView()
|
||||
}))
|
||||
}));
|
||||
if (process.env.NODE_ENV !== "production") renderPicker.displayName = "renderPicker";
|
||||
return {
|
||||
renderPicker
|
||||
};
|
||||
};
|
||||
46
node_modules/@mui/x-date-pickers/esm/internals/hooks/useStaticPicker/useStaticPicker.types.d.ts
generated
vendored
Normal file
46
node_modules/@mui/x-date-pickers/esm/internals/hooks/useStaticPicker/useStaticPicker.types.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { ExportedPickersLayoutSlots, ExportedPickersLayoutSlotProps } from "../../../PickersLayout/PickersLayout.types.js";
|
||||
import { BasePickerProps } from "../../models/props/basePickerProps.js";
|
||||
import { UsePickerParameters, UsePickerProps } from "../usePicker/index.js";
|
||||
import { DateOrTimeViewWithMeridiem, PickerValue } from "../../models/index.js";
|
||||
import { PickerStep } from "../../utils/createNonRangePickerStepNavigation.js";
|
||||
export interface UseStaticPickerSlots extends ExportedPickersLayoutSlots<PickerValue> {}
|
||||
export interface UseStaticPickerSlotProps extends ExportedPickersLayoutSlotProps<PickerValue> {}
|
||||
export interface StaticOnlyPickerProps {
|
||||
/**
|
||||
* Force static wrapper inner components to be rendered in mobile or desktop mode.
|
||||
* @default "mobile"
|
||||
*/
|
||||
displayStaticWrapperAs: 'desktop' | 'mobile';
|
||||
/**
|
||||
* If `true`, the view is focused during the first mount.
|
||||
* @default false
|
||||
*/
|
||||
autoFocus?: boolean;
|
||||
/**
|
||||
* Callback fired when component requests to be closed.
|
||||
* Can be fired when selecting (by default on `desktop` mode) or clearing a value.
|
||||
* @deprecated Please avoid using as it will be removed in next major version.
|
||||
*/
|
||||
onClose?: () => void;
|
||||
}
|
||||
export interface UseStaticPickerProps<TView extends DateOrTimeViewWithMeridiem, TError, TExternalProps extends UsePickerProps<PickerValue, TView, TError, any>> extends BasePickerProps<PickerValue, TView, TError, TExternalProps>, StaticOnlyPickerProps {
|
||||
/**
|
||||
* Overridable component slots.
|
||||
* @default {}
|
||||
*/
|
||||
slots?: UseStaticPickerSlots;
|
||||
/**
|
||||
* The props used for each component slot.
|
||||
* @default {}
|
||||
*/
|
||||
slotProps?: UseStaticPickerSlotProps;
|
||||
}
|
||||
export interface UseStaticPickerParams<TView extends DateOrTimeViewWithMeridiem, TExternalProps extends UseStaticPickerProps<TView, any, TExternalProps>> extends Pick<UsePickerParameters<PickerValue, TView, TExternalProps>, 'valueManager' | 'valueType' | 'validator' | 'ref'> {
|
||||
props: TExternalProps;
|
||||
/**
|
||||
* Steps available for the picker.
|
||||
* This will be used to define the behavior of navigation actions.
|
||||
* If null, the picker will not have any step navigation.
|
||||
*/
|
||||
steps: PickerStep[] | null;
|
||||
}
|
||||
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/useStaticPicker/useStaticPicker.types.js
generated
vendored
Normal file
1
node_modules/@mui/x-date-pickers/esm/internals/hooks/useStaticPicker/useStaticPicker.types.js
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
export {};
|
||||
10
node_modules/@mui/x-date-pickers/esm/internals/hooks/useToolbarOwnerState.d.ts
generated
vendored
Normal file
10
node_modules/@mui/x-date-pickers/esm/internals/hooks/useToolbarOwnerState.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { PickerOwnerState } from "../../models/index.js";
|
||||
export declare function useToolbarOwnerState(): PickerToolbarOwnerState;
|
||||
export interface PickerToolbarOwnerState extends PickerOwnerState {
|
||||
/**
|
||||
* The direction of the toolbar.
|
||||
* Is equal to "ltr" when the toolbar is in left-to-right direction.
|
||||
* Is equal to "rtl" when the toolbar is in right-to-left direction.
|
||||
*/
|
||||
toolbarDirection: 'ltr' | 'rtl';
|
||||
}
|
||||
13
node_modules/@mui/x-date-pickers/esm/internals/hooks/useToolbarOwnerState.js
generated
vendored
Normal file
13
node_modules/@mui/x-date-pickers/esm/internals/hooks/useToolbarOwnerState.js
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import _extends from "@babel/runtime/helpers/esm/extends";
|
||||
import * as React from 'react';
|
||||
import { useRtl } from '@mui/system/RtlProvider';
|
||||
import { usePickerPrivateContext } from "./usePickerPrivateContext.js";
|
||||
export function useToolbarOwnerState() {
|
||||
const {
|
||||
ownerState: pickerOwnerState
|
||||
} = usePickerPrivateContext();
|
||||
const isRtl = useRtl();
|
||||
return React.useMemo(() => _extends({}, pickerOwnerState, {
|
||||
toolbarDirection: isRtl ? 'rtl' : 'ltr'
|
||||
}), [pickerOwnerState, isRtl]);
|
||||
}
|
||||
6
node_modules/@mui/x-date-pickers/esm/internals/hooks/useUtils.d.ts
generated
vendored
Normal file
6
node_modules/@mui/x-date-pickers/esm/internals/hooks/useUtils.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { PickersTimezone, PickerValidDate } from "../../models/index.js";
|
||||
export declare const useDefaultDates: () => {
|
||||
minDate: PickerValidDate;
|
||||
maxDate: PickerValidDate;
|
||||
};
|
||||
export declare const useNow: (timezone: PickersTimezone) => PickerValidDate;
|
||||
11
node_modules/@mui/x-date-pickers/esm/internals/hooks/useUtils.js
generated
vendored
Normal file
11
node_modules/@mui/x-date-pickers/esm/internals/hooks/useUtils.js
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import * as React from 'react';
|
||||
import { useLocalizationContext, usePickerAdapter } from "../../hooks/usePickerAdapter.js";
|
||||
export const useDefaultDates = () => useLocalizationContext().defaultDates;
|
||||
export const useNow = timezone => {
|
||||
const adapter = usePickerAdapter();
|
||||
const now = React.useRef(undefined);
|
||||
if (now.current === undefined) {
|
||||
now.current = adapter.date(undefined, timezone);
|
||||
}
|
||||
return now.current;
|
||||
};
|
||||
85
node_modules/@mui/x-date-pickers/esm/internals/hooks/useViews.d.ts
generated
vendored
Normal file
85
node_modules/@mui/x-date-pickers/esm/internals/hooks/useViews.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import { MakeOptional } from '@mui/x-internals/types';
|
||||
import type { PickerSelectionState } from "./usePicker/index.js";
|
||||
import { DateOrTimeViewWithMeridiem, PickerValidValue } from "../models/index.js";
|
||||
import { PickerValidDate } from "../../models/index.js";
|
||||
import { CreateStepNavigationReturnValue } from "../utils/createStepNavigation.js";
|
||||
export type PickerOnChangeFn = (date: PickerValidDate | null, selectionState?: PickerSelectionState) => void;
|
||||
export interface UseViewsOptions<TValue extends PickerValidValue, TView extends DateOrTimeViewWithMeridiem> {
|
||||
/**
|
||||
* Callback fired when the value changes.
|
||||
* @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value.
|
||||
* @template TView The view type. Will be one of date or time views.
|
||||
* @param {TValue} value The new value.
|
||||
* @param {PickerSelectionState | undefined} selectionState Indicates if the date selection is complete.
|
||||
* @param {TView | undefined} selectedView Indicates the view in which the selection has been made.
|
||||
*/
|
||||
onChange: (value: TValue, selectionState?: PickerSelectionState, selectedView?: TView) => void;
|
||||
/**
|
||||
* Callback fired on view change.
|
||||
* @template TView Type of the view. It will vary based on the Picker type and the `views` it uses.
|
||||
* @param {TView} view The new view.
|
||||
*/
|
||||
onViewChange?: (view: TView) => void;
|
||||
/**
|
||||
* The default visible view.
|
||||
* Used when the component view is not controlled.
|
||||
* Must be a valid option from `views` list.
|
||||
*/
|
||||
openTo?: TView;
|
||||
/**
|
||||
* The visible view.
|
||||
* Used when the component view is controlled.
|
||||
* Must be a valid option from `views` list.
|
||||
*/
|
||||
view?: TView;
|
||||
/**
|
||||
* Available views.
|
||||
*/
|
||||
views: readonly TView[];
|
||||
/**
|
||||
* If `true`, the main element is focused during the first mount.
|
||||
* This main element is:
|
||||
* - the element chosen by the visible view if any (i.e: the selected day on the `day` view).
|
||||
* - the `input` element if there is a field rendered.
|
||||
*/
|
||||
autoFocus?: boolean;
|
||||
/**
|
||||
* Controlled focused view.
|
||||
*/
|
||||
focusedView?: TView | null;
|
||||
/**
|
||||
* Callback fired on focused view change.
|
||||
* @template TView Type of the view. It will vary based on the Picker type and the `views` it uses.
|
||||
* @param {TView} view The new view to focus or not.
|
||||
* @param {boolean} hasFocus `true` if the view should be focused.
|
||||
*/
|
||||
onFocusedViewChange?: (view: TView, hasFocus: boolean) => void;
|
||||
getStepNavigation?: CreateStepNavigationReturnValue;
|
||||
}
|
||||
export interface ExportedUseViewsOptions<TValue extends PickerValidValue, TView extends DateOrTimeViewWithMeridiem> extends Omit<MakeOptional<UseViewsOptions<TValue, TView>, 'onChange' | 'openTo' | 'views'>, 'getStepNavigation'> {}
|
||||
interface UseViewsResponse<TValue extends PickerValidValue, TView extends DateOrTimeViewWithMeridiem> {
|
||||
view: TView;
|
||||
setView: (view: TView) => void;
|
||||
focusedView: TView | null;
|
||||
setFocusedView: (view: TView, hasFocus: boolean) => void;
|
||||
nextView: TView | null;
|
||||
previousView: TView | null;
|
||||
defaultView: TView;
|
||||
goToNextView: () => void;
|
||||
setValueAndGoToNextView: (value: TValue, currentViewSelectionState?: PickerSelectionState, selectedView?: TView) => void;
|
||||
hasNextStep: boolean;
|
||||
hasSeveralSteps: boolean;
|
||||
goToNextStep: () => void;
|
||||
}
|
||||
export declare function useViews<TValue extends PickerValidValue, TView extends DateOrTimeViewWithMeridiem>({
|
||||
onChange,
|
||||
onViewChange,
|
||||
openTo,
|
||||
view: inView,
|
||||
views,
|
||||
autoFocus,
|
||||
focusedView: inFocusedView,
|
||||
onFocusedViewChange,
|
||||
getStepNavigation
|
||||
}: UseViewsOptions<TValue, TView>): UseViewsResponse<TValue, TView>;
|
||||
export {};
|
||||
130
node_modules/@mui/x-date-pickers/esm/internals/hooks/useViews.js
generated
vendored
Normal file
130
node_modules/@mui/x-date-pickers/esm/internals/hooks/useViews.js
generated
vendored
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
'use client';
|
||||
|
||||
import _extends from "@babel/runtime/helpers/esm/extends";
|
||||
import * as React from 'react';
|
||||
import useEventCallback from '@mui/utils/useEventCallback';
|
||||
import useControlled from '@mui/utils/useControlled';
|
||||
import { DEFAULT_STEP_NAVIGATION } from "../utils/createStepNavigation.js";
|
||||
let warnedOnceNotValidView = false;
|
||||
export function useViews({
|
||||
onChange,
|
||||
onViewChange,
|
||||
openTo,
|
||||
view: inView,
|
||||
views,
|
||||
autoFocus,
|
||||
focusedView: inFocusedView,
|
||||
onFocusedViewChange,
|
||||
getStepNavigation
|
||||
}) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (!warnedOnceNotValidView) {
|
||||
if (inView != null && !views.includes(inView)) {
|
||||
console.warn(`MUI X: \`view="${inView}"\` is not a valid prop.`, `It must be an element of \`views=["${views.join('", "')}"]\`.`);
|
||||
warnedOnceNotValidView = true;
|
||||
}
|
||||
if (inView == null && openTo != null && !views.includes(openTo)) {
|
||||
console.warn(`MUI X: \`openTo="${openTo}"\` is not a valid prop.`, `It must be an element of \`views=["${views.join('", "')}"]\`.`);
|
||||
warnedOnceNotValidView = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
const previousOpenTo = React.useRef(openTo);
|
||||
const previousViews = React.useRef(views);
|
||||
const defaultView = React.useRef(views.includes(openTo) ? openTo : views[0]);
|
||||
const [view, setView] = useControlled({
|
||||
name: 'useViews',
|
||||
state: 'view',
|
||||
controlled: inView,
|
||||
default: defaultView.current
|
||||
});
|
||||
const defaultFocusedView = React.useRef(autoFocus ? view : null);
|
||||
const [focusedView, setFocusedView] = useControlled({
|
||||
name: 'useViews',
|
||||
state: 'focusedView',
|
||||
controlled: inFocusedView,
|
||||
default: defaultFocusedView.current
|
||||
});
|
||||
const stepNavigation = getStepNavigation ? getStepNavigation({
|
||||
setView,
|
||||
view,
|
||||
defaultView: defaultView.current,
|
||||
views
|
||||
}) : DEFAULT_STEP_NAVIGATION;
|
||||
React.useEffect(() => {
|
||||
// Update the current view when `openTo` or `views` props change
|
||||
if (previousOpenTo.current && previousOpenTo.current !== openTo || previousViews.current && previousViews.current.some(previousView => !views.includes(previousView))) {
|
||||
setView(views.includes(openTo) ? openTo : views[0]);
|
||||
previousViews.current = views;
|
||||
previousOpenTo.current = openTo;
|
||||
}
|
||||
}, [openTo, setView, view, views]);
|
||||
const viewIndex = views.indexOf(view);
|
||||
const previousView = views[viewIndex - 1] ?? null;
|
||||
const nextView = views[viewIndex + 1] ?? null;
|
||||
const handleFocusedViewChange = useEventCallback((viewToFocus, hasFocus) => {
|
||||
if (hasFocus) {
|
||||
// Focus event
|
||||
setFocusedView(viewToFocus);
|
||||
} else {
|
||||
// Blur event
|
||||
setFocusedView(prevFocusedView => viewToFocus === prevFocusedView ? null : prevFocusedView // If false the blur is due to view switching
|
||||
);
|
||||
}
|
||||
onFocusedViewChange?.(viewToFocus, hasFocus);
|
||||
});
|
||||
const handleChangeView = useEventCallback(newView => {
|
||||
// always keep the focused view in sync
|
||||
handleFocusedViewChange(newView, true);
|
||||
if (newView === view) {
|
||||
return;
|
||||
}
|
||||
setView(newView);
|
||||
if (onViewChange) {
|
||||
onViewChange(newView);
|
||||
}
|
||||
});
|
||||
const goToNextView = useEventCallback(() => {
|
||||
if (nextView) {
|
||||
handleChangeView(nextView);
|
||||
}
|
||||
});
|
||||
const setValueAndGoToNextView = useEventCallback((value, currentViewSelectionState, selectedView) => {
|
||||
const isSelectionFinishedOnCurrentView = currentViewSelectionState === 'finish';
|
||||
const hasMoreViews = selectedView ?
|
||||
// handles case like `DateTimePicker`, where a view might return a `finish` selection state
|
||||
// but when it's not the final view given all `views` -> overall selection state should be `partial`.
|
||||
views.indexOf(selectedView) < views.length - 1 : Boolean(nextView);
|
||||
const globalSelectionState = isSelectionFinishedOnCurrentView && hasMoreViews ? 'partial' : currentViewSelectionState;
|
||||
onChange(value, globalSelectionState, selectedView);
|
||||
|
||||
// The selected view can be different from the active view,
|
||||
// This can happen if multiple views are displayed, like in `DesktopDateTimePicker` or `MultiSectionDigitalClock`.
|
||||
let currentView = null;
|
||||
if (selectedView != null && selectedView !== view) {
|
||||
currentView = selectedView;
|
||||
} else if (isSelectionFinishedOnCurrentView) {
|
||||
currentView = view;
|
||||
}
|
||||
if (currentView == null) {
|
||||
return;
|
||||
}
|
||||
const viewToNavigateTo = views[views.indexOf(currentView) + 1];
|
||||
if (viewToNavigateTo == null || !stepNavigation.areViewsInSameStep(currentView, viewToNavigateTo)) {
|
||||
return;
|
||||
}
|
||||
handleChangeView(viewToNavigateTo);
|
||||
});
|
||||
return _extends({}, stepNavigation, {
|
||||
view,
|
||||
setView: handleChangeView,
|
||||
focusedView,
|
||||
setFocusedView: handleFocusedViewChange,
|
||||
nextView,
|
||||
previousView,
|
||||
// Always return up-to-date default view instead of the initial one (i.e. defaultView.current)
|
||||
defaultView: views.includes(openTo) ? openTo : views[0],
|
||||
goToNextView,
|
||||
setValueAndGoToNextView
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue