Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 6 additions & 11 deletions examples/basic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,24 +102,19 @@ export default () => {
</div>
<div style={{ margin: '0 8px' }}>
<h3>Week</h3>
<Picker<Moment>
generateConfig={momentGenerateConfig}
locale={enUS}
picker="week"
/>
<Picker<Moment> generateConfig={momentGenerateConfig} locale={enUS} picker="week" />
</div>
<div style={{ margin: '0 8px' }}>
<h3>Quarter</h3>
<Picker<Moment> generateConfig={momentGenerateConfig} locale={enUS} picker="quarter" />
</div>
<div style={{ margin: '0 8px' }}>
<h3>Time</h3>
<Picker<Moment> {...sharedProps} locale={zhCN} picker="time" />
</div>
<div style={{ margin: '0 8px' }}>
<h3>Time 12</h3>
<Picker<Moment>
{...sharedProps}
locale={zhCN}
picker="time"
use12Hours
/>
<Picker<Moment> {...sharedProps} locale={zhCN} picker="time" use12Hours />
</div>
<div style={{ margin: '0 8px' }}>
<h3>Year</h3>
Expand Down
12 changes: 6 additions & 6 deletions examples/panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ export default () => {
<PickerPanel<Moment> {...sharedProps} locale={zhCN} picker="month" />
</div>

<div style={{ margin: '0 8px' }}>
<h3>Quarter Picker</h3>
<PickerPanel<Moment> {...sharedProps} locale={zhCN} picker="quarter" />
</div>

<div style={{ margin: '0 8px' }}>
<h3>Week Picker US</h3>
<PickerPanel<Moment> {...sharedProps} locale={enUS} picker="week" />
Expand All @@ -79,12 +84,7 @@ export default () => {
</div>
<div style={{ margin: '0 8px' }}>
<h3>Uncontrolled</h3>
<PickerPanel<Moment>
{...sharedProps}
locale={jaJP}
value={undefined}
picker="time"
/>
<PickerPanel<Moment> {...sharedProps} locale={jaJP} value={undefined} picker="time" />
</div>
<div style={{ margin: '0 8px' }}>
<h3>Time AM/PM</h3>
Expand Down
64 changes: 25 additions & 39 deletions src/PickerPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import DatetimePanel from './panels/DatetimePanel';
import DatePanel from './panels/DatePanel';
import WeekPanel from './panels/WeekPanel';
import MonthPanel from './panels/MonthPanel';
import QuarterPanel from './panels/QuarterPanel';
import YearPanel from './panels/YearPanel';
import DecadePanel from './panels/DecadePanel';
import { GenerateConfig } from './generate';
Expand Down Expand Up @@ -84,13 +85,11 @@ export interface PickerPanelSharedProps<DateType> {
components?: Components;
}

export interface PickerPanelBaseProps<DateType>
extends PickerPanelSharedProps<DateType> {
export interface PickerPanelBaseProps<DateType> extends PickerPanelSharedProps<DateType> {
picker: Exclude<PickerMode, 'date' | 'time'>;
}

export interface PickerPanelDateProps<DateType>
extends PickerPanelSharedProps<DateType> {
export interface PickerPanelDateProps<DateType> extends PickerPanelSharedProps<DateType> {
picker?: 'date';
showToday?: boolean;

Expand Down Expand Up @@ -149,18 +148,11 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
direction,
} = props as MergedPickerPanelProps<DateType>;

const needConfirmButton: boolean =
(picker === 'date' && !!showTime) || picker === 'time';
const needConfirmButton: boolean = (picker === 'date' && !!showTime) || picker === 'time';

if (process.env.NODE_ENV !== 'production') {
warning(
!value || generateConfig.isValidate(value),
'Invalidate date pass to `value`.',
);
warning(
!value || generateConfig.isValidate(value),
'Invalidate date pass to `defaultValue`.',
);
warning(!value || generateConfig.isValidate(value), 'Invalidate date pass to `value`.');
warning(!value || generateConfig.isValidate(value), 'Invalidate date pass to `defaultValue`.');
}

// ============================ State =============================
Expand All @@ -174,12 +166,7 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
defaultOpenValue,
} = panelContext;

const {
inRange,
panelPosition,
rangedValue,
hoverRangedValue,
} = React.useContext(RangeContext);
const { inRange, panelPosition, rangedValue, hoverRangedValue } = React.useContext(RangeContext);
const panelRef = React.useRef<PanelRefProps>({});

// Handle init logic
Expand All @@ -198,10 +185,7 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
});

// View date control
const [viewDate, setInnerViewDate] = useMergedState<
DateType | null,
DateType
>(null, {
const [viewDate, setInnerViewDate] = useMergedState<DateType | null, DateType>(null, {
value: pickerValue,
defaultValue: defaultPickerValue || mergedValue,
postState: date => date || generateConfig.getNow(),
Expand Down Expand Up @@ -237,22 +221,14 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
},
);

const [sourceMode, setSourceMode] = React.useState<PanelMode>(
() => mergedMode,
);
const [sourceMode, setSourceMode] = React.useState<PanelMode>(() => mergedMode);

const onInternalPanelChange = (
newMode: PanelMode | null,
viewValue: DateType,
) => {
const onInternalPanelChange = (newMode: PanelMode | null, viewValue: DateType) => {
const nextMode = getInternalNextMode(newMode || mergedMode);
setSourceMode(mergedMode);
setInnerMode(nextMode);

if (
onPanelChange &&
(mergedMode !== nextMode || isEqual(generateConfig, viewDate, viewDate))
) {
if (onPanelChange && (mergedMode !== nextMode || isEqual(generateConfig, viewDate, viewDate))) {
onPanelChange(viewValue, nextMode);
}
};
Expand Down Expand Up @@ -392,6 +368,18 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
);
break;

case 'quarter':
panelNode = (
<QuarterPanel<DateType>
{...pickerProps}
onSelect={(date, type) => {
setViewDate(date);
triggerSelect(date, type);
}}
/>
);
break;

case 'week':
panelNode = (
<WeekPanel
Expand Down Expand Up @@ -489,17 +477,15 @@ function PickerPanel<DateType>(props: PickerPanelProps<DateType>) {
<PanelContext.Provider
value={{
...panelContext,
hideHeader:
'hideHeader' in props ? hideHeader : panelContext.hideHeader,
hideHeader: 'hideHeader' in props ? hideHeader : panelContext.hideHeader,
hidePrevBtn: inRange && panelPosition === 'right',
hideNextBtn: inRange && panelPosition === 'left',
}}
>
<div
tabIndex={tabIndex}
className={classNames(`${prefixCls}-panel`, className, {
[`${prefixCls}-panel-has-range`]:
rangedValue && rangedValue[0] && rangedValue[1],
[`${prefixCls}-panel-has-range`]: rangedValue && rangedValue[0] && rangedValue[1],
[`${prefixCls}-panel-has-range-hover`]:
hoverRangedValue && hoverRangedValue[0] && hoverRangedValue[1],
[`${prefixCls}-panel-rtl`]: direction === 'rtl',
Expand Down
17 changes: 5 additions & 12 deletions src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface Locale {
monthBeforeYear?: boolean;
yearFormat: string;
monthFormat?: string;
quarterFormat?: string;

today: string;
now: string;
Expand Down Expand Up @@ -39,7 +40,7 @@ export interface Locale {
shortMonths?: string[];
}

export type PanelMode = 'time' | 'date' | 'week' | 'month' | 'year' | 'decade';
export type PanelMode = 'time' | 'date' | 'week' | 'month' | 'quarter' | 'year' | 'decade';

export type PickerMode = Exclude<PanelMode, 'datetime' | 'decade'>;

Expand All @@ -51,10 +52,7 @@ export interface PanelRefProps {

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

export type OnSelect<DateType> = (
value: DateType,
type: 'key' | 'mouse' | 'submit',
) => void;
export type OnSelect<DateType> = (value: DateType, type: 'key' | 'mouse' | 'submit') => void;

export interface PanelSharedProps<DateType> {
prefixCls: string;
Expand Down Expand Up @@ -91,15 +89,10 @@ export interface DisabledTimes {

export type DisabledTime<DateType> = (date: DateType | null) => DisabledTimes;

export type OnPanelChange<DateType> = (
value: DateType,
mode: PanelMode,
) => void;
export type OnPanelChange<DateType> = (value: DateType, mode: PanelMode) => void;

export type EventValue<DateType> = DateType | null;
export type RangeValue<DateType> =
| [EventValue<DateType>, EventValue<DateType>]
| null;
export type RangeValue<DateType> = [EventValue<DateType>, EventValue<DateType>] | null;

export interface Components {
button?: React.ComponentType | string;
Expand Down
58 changes: 58 additions & 0 deletions src/panels/QuarterPanel/QuarterBody.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as React from 'react';
import { GenerateConfig } from '../../generate';
import { Locale } from '../../interface';
import { isSameQuarter } from '../../utils/dateUtil';
import RangeContext from '../../RangeContext';
import useCellClassName from '../../hooks/useCellClassName';
import PanelBody from '../PanelBody';

export const QUARTER_COL_COUNT = 4;
const QUARTER_ROW_COUNT = 1;

export interface QuarterBodyProps<DateType> {
prefixCls: string;
locale: Locale;
generateConfig: GenerateConfig<DateType>;
value?: DateType | null;
viewDate: DateType;
disabledDate?: (date: DateType) => boolean;
onSelect: (value: DateType) => void;
}

function QuarterBody<DateType>(props: QuarterBodyProps<DateType>) {
const { prefixCls, locale, value, viewDate, generateConfig } = props;

const { rangedValue, hoverRangedValue } = React.useContext(RangeContext);

const cellPrefixCls = `${prefixCls}-cell`;

const getCellClassName = useCellClassName({
cellPrefixCls,
value,
generateConfig,
rangedValue,
hoverRangedValue,
isSameCell: (current, target) => isSameQuarter(generateConfig, current, target),
isInView: () => true,
offsetCell: (date, offset) => generateConfig.addMonth(date, offset * 3),
});

const baseQuarter = generateConfig.setDate(generateConfig.setMonth(viewDate, 0), 1);

return (
<PanelBody
{...props}
rowNum={QUARTER_ROW_COUNT}
colNum={QUARTER_COL_COUNT}
baseDate={baseQuarter}
getCellText={date =>
generateConfig.locale.format(locale.locale, date, locale.quarterFormat || '\\QQ')
}
getCellClassName={getCellClassName}
getCellDate={(date, offset) => generateConfig.addMonth(date, offset * 3)}
titleCell={date => generateConfig.locale.format(locale.locale, date, 'YYYY-\\QQ')}
/>
);
}

export default QuarterBody;
44 changes: 44 additions & 0 deletions src/panels/QuarterPanel/QuarterHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as React from 'react';
import Header from '../Header';
import { Locale } from '../../interface';
import { GenerateConfig } from '../../generate';
import PanelContext from '../../PanelContext';

export interface QuarterHeaderProps<DateType> {
prefixCls: string;
viewDate: DateType;
locale: Locale;
generateConfig: GenerateConfig<DateType>;

onPrevYear: () => void;
onNextYear: () => void;
onYearClick: () => void;
}

function QuarterHeader<DateType>(props: QuarterHeaderProps<DateType>) {
const {
prefixCls,
generateConfig,
locale,
viewDate,
onNextYear,
onPrevYear,
onYearClick,
} = props;
const { hideHeader } = React.useContext(PanelContext);
if (hideHeader) {
return null;
}

const headerPrefixCls = `${prefixCls}-header`;

return (
<Header prefixCls={headerPrefixCls} onSuperPrev={onPrevYear} onSuperNext={onNextYear}>
<button type="button" key="year" onClick={onYearClick} className={`${prefixCls}-year-btn`}>
{generateConfig.locale.format(locale.locale, viewDate, locale.yearFormat)}
</button>
</Header>
);
}

export default QuarterHeader;
Loading