Skip to content

Commit

Permalink
auto switch start & end
Browse files Browse the repository at this point in the history
  • Loading branch information
zombieJ committed Nov 25, 2019
1 parent f3b2ed1 commit c2ccfc3
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 24 deletions.
33 changes: 27 additions & 6 deletions examples/range.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,23 @@ import momentGenerateConfig from '../src/generate/moment';
import zhCN from '../src/locale/zh_CN';
import '../assets/index.less';

// const defaultValue = moment('2019-09-03 05:02:03');
const defaultValue = moment('2019-11-28 01:02:03');
const defaultStartValue = moment('2019-09-03 05:02:03');
const defaultEndValue = moment('2019-11-28 01:02:03');

function formatDate(date: Moment | null) {
return date ? date.format('YYYY-MM-DD HH:mm:ss') : 'null';
}

export default () => {
const [value, setValue] = React.useState<Moment | null>(defaultValue);
const [value, setValue] = React.useState<
[Moment | null, Moment | null] | null
>([defaultStartValue, defaultEndValue]);

const onChange = (newValue: Moment | null, formatString?: string) => {
console.log('Change:', newValue, formatString);
const onChange = (
newValue: [Moment | null, Moment | null] | null,
formatStrings?: string[],
) => {
console.log('Change:', newValue, formatStrings);
setValue(newValue);
};

Expand All @@ -24,13 +33,25 @@ export default () => {

return (
<div>
<h1>Value: {value ? value.format('YYYY-MM-DD HH:mm:ss') : 'null'}</h1>
<h1>
Value:{' '}
{value ? `${formatDate(value[0])} ~ ${formatDate(value[1])}` : 'null'}
</h1>

<div style={{ display: 'flex', flexWrap: 'wrap' }}>
<div style={{ margin: '0 8px' }}>
<h3>Basic</h3>
<RangePicker<Moment> {...sharedProps} locale={zhCN} />
</div>

<div style={{ margin: '0 8px' }}>
<h3>Uncontrolled</h3>
<RangePicker<Moment>
{...sharedProps}
value={undefined}
locale={zhCN}
/>
</div>
</div>
</div>
);
Expand Down
19 changes: 13 additions & 6 deletions src/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import classNames from 'classnames';
import PickerPanel from './PickerPanel';
import PickerTrigger from './PickerTrigger';
import { GenerateConfig } from './generate';
import { Locale, PanelMode, GetNextMode } from './interface';
import { Locale, PanelMode, GetNextMode, NullableDateType } from './interface';
import { isEqual } from './utils/dateUtil';
import { toArray } from './utils/miscUtil';
import PanelContext, { ContextOperationRefProps } from './PanelContext';
Expand All @@ -17,7 +17,8 @@ export interface PickerProps<DateType> {
allowClear?: boolean;
autoFocus?: boolean;
showTime?: boolean | SharedTimeProps;
value?: DateType | null;
value?: NullableDateType<DateType>;
defaultValue?: NullableDateType<DateType>;
open?: boolean;
format?: string | string[];
mode?: PanelMode;
Expand All @@ -39,6 +40,7 @@ function Picker<DateType>(props: PickerProps<DateType>) {
showTime,
format = showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD',
value,
defaultValue,
open,
clearIcon,
onChange,
Expand All @@ -49,10 +51,15 @@ function Picker<DateType>(props: PickerProps<DateType>) {
const formatList = toArray(format);

// Real value
const [innerValue, setInnerValue] = React.useState<DateType | null>(
() => ('value' in props ? value : generateConfig.getNow()) || null,
);
const mergedValue = ('value' in props ? value : innerValue) || null;
const [innerValue, setInnerValue] = React.useState<DateType | null>(() => {
if (value !== undefined) {
return value;
} if (defaultValue !== undefined) {
return defaultValue;
}
return generateConfig.getNow();
});
const mergedValue = value !== undefined ? value : innerValue;

// Selected value
const [
Expand Down
88 changes: 81 additions & 7 deletions src/RangePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,99 @@
import * as React from 'react';
import Picker, { PickerProps } from './Picker';
import { NullableDateType } from './interface';
import { toArray } from './utils/miscUtil';

// TODO: 'before - 2010-11-11' or '2011-11-11 - forever'
type RangeValue<DateType> = [DateType | null, DateType | null] | null;

export interface RangePickerProps<DateType>
extends Omit<PickerProps<DateType>, 'value'> {
value?: [DateType | null, DateType | null] | null;
extends Omit<PickerProps<DateType>, 'value' | 'defaultValue' | 'onChange'> {
value?: RangeValue<DateType>;
defaultValue?: RangeValue<DateType>;
onChange?: (
value: RangeValue<DateType>,
formatString: [string, string],
) => void;
}

function RangePicker<DateType>(props: RangePickerProps<DateType>) {
const { prefixCls = 'rc-picker', value, generateConfig } = props;
const {
prefixCls = 'rc-picker',
value,
defaultValue,
locale,
generateConfig,
showTime,
format = showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD',
onChange,
} = props;

const [innerValue] = React.useState<[DateType | null, DateType | null]>(
() => value || [generateConfig.getNow(), generateConfig.getNow()],
const formatList = toArray(format);

const [innerValue, setInnerValue] = React.useState<RangeValue<DateType>>(
() => {
if (value !== undefined) {
return value;
} if (defaultValue !== undefined) {
return defaultValue;
}
return null;
},
);

const mergedValue = value !== undefined ? value : innerValue;

const value1 = mergedValue ? mergedValue[0] : null;
const value2 = mergedValue ? mergedValue[1] : null;

const formatDate = (date: NullableDateType<DateType>) => (date
? generateConfig.locale.format(locale.locale, date, formatList[0])
: '');

const onInternalChange = (values: NullableDateType<DateType>[]) => {
let startDate: DateType | null = values[0] || null;
let endDate: DateType | null = values[1] || null;

if (startDate && endDate && generateConfig.isAfter(startDate, endDate)) {
startDate = values[1] || null;
endDate = values[0] || null;
}

setInnerValue([startDate, endDate]);

if (onChange) {
onChange(
[startDate, endDate],
[formatDate(startDate), formatDate(endDate)],
);
}
};

// ============================= Render =============================
const pickerProps = {
...props,
defaultValue: undefined,
};

return (
<div className={`${prefixCls}-range`}>
<Picker {...props} prefixCls={prefixCls} value={innerValue[0]} />
<Picker<DateType>
{...pickerProps}
prefixCls={prefixCls}
value={value1}
onChange={date => {
onInternalChange([date, value2]);
}}
/>
~
<Picker {...props} prefixCls={prefixCls} value={innerValue[1]} />
<Picker<DateType>
{...pickerProps}
prefixCls={prefixCls}
value={value2}
onChange={date => {
onInternalChange([value1, date]);
}}
/>
</div>
);
}
Expand Down
3 changes: 3 additions & 0 deletions src/generate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ export interface GenerateConfig<DateType> {
setMinute: (value: DateType, minute: number) => DateType;
setSecond: (value: DateType, second: number) => DateType;

// Compare
isAfter: (date1: DateType, date2: DateType) => boolean;

locale: {
getWeekFirstDay: (locale: string) => number;
getWeek: (locale: string, value: DateType) => number;
Expand Down
3 changes: 3 additions & 0 deletions src/generate/moment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ const generateConfig: GenerateConfig<Moment> = {
return clone;
},

// Compare
isAfter: (date1, date2) => date1.isAfter(date2),

locale: {
getWeekFirstDay: locale => {
const date = moment().locale(locale);
Expand Down
8 changes: 5 additions & 3 deletions src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,17 @@ export interface PanelRefProps {
onClose?: () => void;
}

export type NullableDateType<DateType> = DateType | null | undefined;

export interface PanelSharedProps<DateType> {
prefixCls: string;
generateConfig: GenerateConfig<DateType>;
value?: DateType | null;
value?: NullableDateType<DateType>;
/**
* @private Set another value in the panel to display ranged value style.
* @private Set displayed range value style.
* Panel only has one value, this is only style effect.
*/
rangedValue?: DateType;
rangedValue?: [NullableDateType<DateType>, NullableDateType<DateType>];
viewDate: DateType;
/** [Legacy] Set default display picker view date */
defaultPickerValue?: DateType;
Expand Down
3 changes: 1 addition & 2 deletions src/utils/dateUtil.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { GenerateConfig } from '../generate';
import { NullableDateType } from '../interface';

export const WEEK_DAY_COUNT = 7;

Expand All @@ -12,8 +13,6 @@ export function isNullEqual<T>(value1: T, value2: T): boolean | undefined {
return undefined;
}

type NullableDateType<DateType> = DateType | null | undefined;

export function isSameMonth<DateType>(
generateConfig: GenerateConfig<DateType>,
month1: NullableDateType<DateType>,
Expand Down

1 comment on commit c2ccfc3

@vercel
Copy link

@vercel vercel bot commented on c2ccfc3 Nov 25, 2019

Choose a reason for hiding this comment

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

Please sign in to comment.