Skip to content

Commit

Permalink
chore: tmp of submit
Browse files Browse the repository at this point in the history
  • Loading branch information
zombieJ committed Nov 2, 2023
1 parent f03259c commit c76e512
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 73 deletions.
45 changes: 41 additions & 4 deletions src/NewPicker/PickerInput/Popup/PopupPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,56 @@ export type PopupPanelProps<DateType = any> = MustProp &
};

export default function PopupPanel<DateType = any>(props: PopupPanelProps<DateType>) {
const { internalMode, picker, multiple } = props;
const { prefixCls } = React.useContext(PickerContext);
const { internalMode, picker, multiple, pickerValue, onPickerValueChange } = props;

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable internalMode.
const { prefixCls, generateConfig } = React.useContext(PickerContext);

console.log('????', internalMode, picker);
const offsetDate = React.useCallback(
(date: DateType, offset: number) => {
switch (picker) {
case 'date':
return generateConfig.addMonth(date, offset);

case 'month':
case 'quarter':
return generateConfig.addYear(date, offset);

case 'year':
return generateConfig.addYear(date, offset * 10);

case 'decade':
return generateConfig.addYear(date, offset * 100);

default:
return date;
}
},
[generateConfig, picker],
);

const nextPickerValue = React.useMemo(
() => offsetDate(pickerValue, 1),
[pickerValue, offsetDate],
);

const onNextPickerValueChange = (nextDate: DateType) => {
onPickerValueChange(offsetDate(nextDate, -1));
};

// ======================== Render ========================
// Multiple
if (multiple) {
return (
<div className={`${prefixCls}-panels`}>
<PickerPanel {...props} />
<PickerPanel {...props} />
<PickerPanel
{...props}
pickerValue={nextPickerValue}
onPickerValueChange={onNextPickerValueChange}
/>
</div>
);
}

// Single
return <PickerPanel {...props} />;
}
115 changes: 46 additions & 69 deletions src/NewPicker/PickerInput/RangePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useMergedState } from 'rc-util';
import * as React from 'react';
import { isSameTimestamp } from '../../utils/dateUtil';
import type {
InternalMode,
OnOpenChange,
Expand All @@ -14,6 +13,7 @@ import PickerTrigger from '../PickerTrigger';
import PickerContext from './context';
import { useFieldFormat } from './hooks/useFieldFormat';
import useOpen from './hooks/useOpen';
import useRangeValue from './hooks/useRangeValue';
import useShowNow from './hooks/useShowNow';
import Popup from './Popup';
import RangeSelector from './Selector/RangeSelector';
Expand Down Expand Up @@ -43,6 +43,12 @@ export interface RangePickerProps<DateType> extends SharedPickerProps<DateType>
},
) => void;

// Picker Value
defaultPickerValue?: [DateType, DateType] | null;
pickerValue?: [DateType, DateType] | null;
onPickerValueChange?: (date: [DateType, DateType]) => void;

// MISC
order?: boolean;

disabled?: boolean | [boolean, boolean];
Expand Down Expand Up @@ -87,6 +93,11 @@ export default function Picker<DateType = any>(props: RangePickerProps<DateType>
showNow,
showToday,

// Picker Value
defaultPickerValue,
pickerValue,
onPickerValueChange,

// Format
format,

Expand Down Expand Up @@ -161,81 +172,44 @@ export default function Picker<DateType = any>(props: RangePickerProps<DateType>
const mergedAllowEmpty = separateConfig(allowEmpty, true);

// ======================== Value =========================
const valueConfig = {
const [mergedValue, setMergedValue, submitValue, setSubmitValue, triggerChange] = useRangeValue(

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable setMergedValue.

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable submitValue.

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable setSubmitValue.
value,
postState: (valList: RangeValueType<DateType>): RangeValueType<DateType> =>
valList || [null, null],
};

// Used for internal value management.
// It should always use `mergedValue` in render logic
const [mergedValue, setMergedValue] = useMergedState(defaultValue, valueConfig);

// Used for trigger `onChange` event.
// Record current submitted value.
const [submitValue, setSubmitValue] = useMergedState(defaultValue, valueConfig);

// ======================== Change ========================
const getDateTexts = (dateList: RangeValueType<DateType>) => {
return dateList.map((date) =>
date ? generateConfig.locale.format(locale.locale, date, formatList[0]) : '',
) as [string, string];
};

const isSameDates = (source: RangeValueType<DateType>, target: RangeValueType<DateType>) => {
const [prevSubmitStart, prevSubmitEnd] = source;

const isSameStart = isSameTimestamp(generateConfig, prevSubmitStart, target[0]);
const isSameEnd = isSameTimestamp(generateConfig, prevSubmitEnd, target[1]);

return [isSameStart && isSameEnd, isSameStart, isSameEnd];
};

const triggerChange = ([start, end]: RangeValueType<DateType>, source?: 'submit') => {
const clone: RangeValueType<DateType> = [start, end];

// Only when exist value to sort
if (order && source === 'submit' && clone[0] && clone[1]) {
clone.sort((a, b) => (generateConfig.isAfter(a, b) ? 1 : -1));
}
defaultValue,
generateConfig,
locale,
formatList,
mergedAllowEmpty,
order,
onCalendarChange,
onChange,
);

// Update merged value
const [isSameMergedDates, isSameStart] = isSameDates(mergedValue, clone);
// ===================== Picker Value =====================
const [mergedStartPickerValue, setStartPickerValue] = useMergedState(
() => defaultPickerValue?.[0] || mergedValue?.[0] || generateConfig.getNow(),
{
value: pickerValue?.[0],
},
);

if (!isSameMergedDates) {
setMergedValue(clone);
const [mergedEndPickerValue, setEndPickerValue] = useMergedState(
() => defaultPickerValue?.[1] || mergedValue?.[1] || generateConfig.getNow(),
{
value: pickerValue?.[1],
},
);

// Trigger calendar change event
if (onCalendarChange) {
onCalendarChange(clone, getDateTexts(clone), {
range: isSameStart ? 'end' : 'start',
});
}
}
const currentPickerValue = [mergedStartPickerValue, mergedEndPickerValue][activeIndex];
const setCurrentPickerValue = (nextPickerValue: DateType) => {
const updater = [setStartPickerValue, setEndPickerValue][activeIndex];
updater(nextPickerValue);

// Update `submitValue` to trigger event by effect
if (source === 'submit') {
setSubmitValue(clone);

// Trigger `onChange` if needed
const [isSameSubmitDates] = isSameDates(submitValue, clone);

const startEmpty = !clone[0];
const endEmpty = !clone[1];

if (
onChange &&
!isSameSubmitDates &&
// Validate start
(!startEmpty || mergedAllowEmpty[0]) &&
// Validate end
(!endEmpty || mergedAllowEmpty[1])
) {
onChange(clone, getDateTexts(clone));
}
}
const clone: [DateType, DateType] = [mergedStartPickerValue, mergedEndPickerValue];
clone[activeIndex] = nextPickerValue;
onPickerValueChange?.(clone);
};

// ======================== Change ========================
const fillMergedValue = (date: DateType, index: number) => {
// Trigger change only when date changed
const [prevStart, prevEnd] = mergedValue;
Expand Down Expand Up @@ -349,6 +323,9 @@ export default function Picker<DateType = any>(props: RangePickerProps<DateType>
value={panelValue}
onChange={null}
onCalendarChange={onPanelCalendarChange}
// PickerValue
pickerValue={currentPickerValue}
onPickerValueChange={setCurrentPickerValue}
// Submit
needConfirm={needConfirm}
onSubmit={submitAndFocusNext}
Expand Down
110 changes: 110 additions & 0 deletions src/NewPicker/PickerInput/hooks/useRangeValue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { useMergedState } from 'rc-util';
import type { GenerateConfig } from '../../../generate';
import { isSameTimestamp } from '../../../utils/dateUtil';
import type { Locale } from '../../interface';
import type { RangePickerProps, RangeValueType } from '../RangePicker';

// Submit Logic (with order):
// * All the input is filled step by step
// * None of the Picker has focused anymore

type SetValue<DateType> = (val: RangeValueType<DateType>) => void;

type TriggerChange<DateType> = ([start, end]: RangeValueType<DateType>, source?: 'submit') => void;

export default function useRangeValue<DateType = any>(
value: RangeValueType<DateType>,
defaultValue: RangeValueType<DateType>,
generateConfig: GenerateConfig<DateType>,
locale: Locale,
formatList: string[],
allowEmpty: [boolean | undefined, boolean | undefined],
order: boolean,
onCalendarChange?: RangePickerProps<DateType>['onCalendarChange'],
onChange?: RangePickerProps<DateType>['onChange'],
): [
mergedValue: RangeValueType<DateType>,
setMergedValue: SetValue<DateType>,
submitValue: RangeValueType<DateType>,
setSubmitValue: SetValue<DateType>,
triggerChange: TriggerChange<DateType>,
] {
// ============================ Values ============================
const valueConfig = {
value,
postState: (valList: RangeValueType<DateType>): RangeValueType<DateType> =>
valList || [null, null],
};

// Used for internal value management.
// It should always use `mergedValue` in render logic
const [mergedValue, setMergedValue] = useMergedState(defaultValue, valueConfig);

// Used for trigger `onChange` event.
// Record current submitted value.
const [submitValue, setSubmitValue] = useMergedState(defaultValue, valueConfig);

// ============================ Change ============================
const getDateTexts = (dateList: RangeValueType<DateType>) => {
return dateList.map((date) =>
date ? generateConfig.locale.format(locale.locale, date, formatList[0]) : '',
) as [string, string];
};

const isSameDates = (source: RangeValueType<DateType>, target: RangeValueType<DateType>) => {
const [prevSubmitStart, prevSubmitEnd] = source;

const isSameStart = isSameTimestamp(generateConfig, prevSubmitStart, target[0]);
const isSameEnd = isSameTimestamp(generateConfig, prevSubmitEnd, target[1]);

return [isSameStart && isSameEnd, isSameStart, isSameEnd];
};

const triggerChange = ([start, end]: RangeValueType<DateType>, source?: 'submit') => {
const clone: RangeValueType<DateType> = [start, end];

// Only when exist value to sort
if (order && source === 'submit' && clone[0] && clone[1]) {
clone.sort((a, b) => (generateConfig.isAfter(a, b) ? 1 : -1));
}

// Update merged value
const [isSameMergedDates, isSameStart] = isSameDates(mergedValue, clone);

if (!isSameMergedDates) {
setMergedValue(clone);

// Trigger calendar change event
if (onCalendarChange) {
onCalendarChange(clone, getDateTexts(clone), {
range: isSameStart ? 'end' : 'start',
});
}
}

// Update `submitValue` to trigger event by effect
if (source === 'submit') {
setSubmitValue(clone);

// Trigger `onChange` if needed
const [isSameSubmitDates] = isSameDates(submitValue, clone);

const startEmpty = !clone[0];
const endEmpty = !clone[1];

if (
onChange &&
!isSameSubmitDates &&
// Validate start
(!startEmpty || allowEmpty[0]) &&
// Validate end
(!endEmpty || allowEmpty[1])
) {
onChange(clone, getDateTexts(clone));
}
}
};

// ============================ Return ============================
return [mergedValue, setMergedValue, submitValue, setSubmitValue, triggerChange];
}

0 comments on commit c76e512

Please sign in to comment.