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
11 changes: 10 additions & 1 deletion src/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { getDefaultFormat, getInputSize, elementsContains } from './utils/uiUtil
import usePickerInput from './hooks/usePickerInput';
import useTextValueMapping from './hooks/useTextValueMapping';
import useValueTexts from './hooks/useValueTexts';
import useHoverPlaceholder from './hooks/useHoverPlaceholder';

export interface PickerRefConfig {
focus: () => void;
Expand Down Expand Up @@ -435,6 +436,12 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
};
const popupPlacement = direction === 'rtl' ? 'bottomRight' : 'bottomLeft';

const [hoverPlaceholder, onEnter, onLeave] = useHoverPlaceholder(placeholder, text, {
formatList,
generateConfig,
locale,
});

return (
<PanelContext.Provider
value={{
Expand All @@ -444,6 +451,8 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
onSelect: onContextSelect,
open: mergedOpen,
defaultOpenValue,
onDateMouseEnter: onEnter,
onDateMouseLeave: onLeave,
}}
>
<PickerTrigger
Expand Down Expand Up @@ -483,7 +492,7 @@ function InnerPicker<DateType>(props: PickerProps<DateType>) {
triggerTextChange(e.target.value);
}}
autoFocus={autoFocus}
placeholder={placeholder}
placeholder={hoverPlaceholder}
ref={inputRef}
title={text}
{...inputProps}
Expand Down
60 changes: 46 additions & 14 deletions src/RangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import getExtraFooter from './utils/getExtraFooter';
import getRanges from './utils/getRanges';
import useRangeViewDates from './hooks/useRangeViewDates';
import { DateRender } from './panels/DatePanel/DateBody';
import useHoverPlaceholder from './hooks/useHoverPlaceholder';

function reorderValues<DateType>(
values: RangeValue<DateType>,
Expand Down Expand Up @@ -284,18 +285,6 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
},
});

const [rangeHoverValue, setRangeHoverValue] = useState<RangeValue<DateType>>(null);

// ========================== Hover Range ==========================
const [hoverRangedValue, setHoverRangedValue] = useState<RangeValue<DateType>>(null);

const onDateMouseEnter = (date: DateType) => {
setHoverRangedValue(updateValues(selectedValue, date, mergedActivePickerIndex));
};
const onDateMouseLeave = () => {
setHoverRangedValue(updateValues(selectedValue, null, mergedActivePickerIndex));
};

// ============================= Modes =============================
const [mergedModes, setInnerModes] = useMergedState<[PanelMode, PanelMode]>([picker, picker], {
value: mode,
Expand Down Expand Up @@ -546,6 +535,49 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
onTextChange: newText => onTextChange(newText, 1),
});

const [rangeHoverValue, setRangeHoverValue] = useState<RangeValue<DateType>>(null);

// ========================== Hover Range ==========================
const [hoverRangedValue, setHoverRangedValue] = useState<RangeValue<DateType>>(null);

const [startPlaceholder, onStartEnter, onStartLeave] = useHoverPlaceholder(
getValue(placeholder, 0) || '',
startText,
{
formatList,
generateConfig,
locale,
},
);

const [endPlaceholder, onEndEnter, onEndLeave] = useHoverPlaceholder(
getValue(placeholder, 1) || '',
endText,
{
formatList,
generateConfig,
locale,
},
);

const onDateMouseEnter = (date: DateType) => {
setHoverRangedValue(updateValues(selectedValue, date, mergedActivePickerIndex));
if (mergedActivePickerIndex === 0) {
onStartEnter(date);
} else {
onEndEnter(date);
}
};

const onDateMouseLeave = () => {
setHoverRangedValue(updateValues(selectedValue, null, mergedActivePickerIndex));
if (mergedActivePickerIndex === 0) {
onStartLeave(null);
} else {
onEndLeave(null);
}
};

// ============================= Input =============================
const getSharedInputHookProps = (index: 0 | 1, resetText: () => void) => ({
blurToCancel: needConfirmButton,
Expand Down Expand Up @@ -1040,7 +1072,7 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
triggerStartTextChange(e.target.value);
}}
autoFocus={autoFocus}
placeholder={getValue(placeholder, 0) || ''}
placeholder={startPlaceholder}
ref={startInputRef}
{...startInputProps}
{...inputSharedProps}
Expand All @@ -1063,7 +1095,7 @@ function InnerRangePicker<DateType>(props: RangePickerProps<DateType>) {
onChange={e => {
triggerEndTextChange(e.target.value);
}}
placeholder={getValue(placeholder, 1) || ''}
placeholder={endPlaceholder}
ref={endInputRef}
{...endInputProps}
{...inputSharedProps}
Expand Down
31 changes: 15 additions & 16 deletions src/generate/dayjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,13 @@ const localeMap: IlocaleMapObject = {

const parseLocale = (locale: string) => {
const mapLocale = localeMap[locale];
return mapLocale || locale.split('_')[0];
return (mapLocale || locale.split('_')[0]) as LocalePresetType;
Copy link
Member

Choose a reason for hiding this comment

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

ci 报错了。

src/generate/dayjs.ts(38,49): error TS2304: Cannot find name 'LocalePresetType'.

Copy link
Member

Choose a reason for hiding this comment

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

估计 dayjs 又改了 = =

};

const parseNoMatchNotice = () => {
/* istanbul ignore next */
noteOnce(
false,
'Not match any format. Please help to fire a issue about this.',
);
}
noteOnce(false, 'Not match any format. Please help to fire a issue about this.');
};

const generateConfig: GenerateConfig<Dayjs> = {
// get
Expand Down Expand Up @@ -92,24 +89,26 @@ const generateConfig: GenerateConfig<Dayjs> = {
.locale(parseLocale(locale))
.localeData()
.monthsShort(),
format: (locale, date, format) =>
date.locale(parseLocale(locale)).format(format),
format: (locale, date, format) => date.locale(parseLocale(locale)).format(format),
parse: (locale, text, formats) => {
const localeStr = parseLocale(locale)
const localeStr = parseLocale(locale);
for (let i = 0; i < formats.length; i += 1) {
const format = formats[i];
const formatText = text;
if (format.includes('wo') || format.includes('Wo')) { // parse Wo
const year = formatText.split('-')[0]
const weekStr = formatText.split('-')[1]
const firstWeek = dayjs(year, 'YYYY').startOf('year').locale(localeStr)
if (format.includes('wo') || format.includes('Wo')) {
// parse Wo
const year = formatText.split('-')[0];
const weekStr = formatText.split('-')[1];
const firstWeek = dayjs(year, 'YYYY')
.startOf('year')
.locale(localeStr);
for (let j = 0; j <= 52; j += 1) {
const nextWeek = firstWeek.add(j, 'week')
const nextWeek = firstWeek.add(j, 'week');
if (nextWeek.format('Wo') === weekStr) {
return nextWeek
return nextWeek;
}
}
parseNoMatchNotice()
parseNoMatchNotice();
return null;
}
const date = dayjs(formatText, format).locale(localeStr);
Expand Down
28 changes: 28 additions & 0 deletions src/hooks/useHoverPlaceholder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useState } from 'react';
import useValueTexts, { ValueTextConfig } from './useValueTexts';

export default function useHoverPlaceholder<DateType>(
placeholder: string,
text: string,
{ formatList, generateConfig, locale }: ValueTextConfig<DateType>,
): [string, (date: DateType) => void, (date: DateType) => void] {
const [value, setValue] = useState(null);

const [valueTexts] = useValueTexts(value, {
formatList,
generateConfig,
locale,
});

function onEnter(date: DateType) {
if (!text) {
setValue(date);
}
}

function onLeave() {
setValue(null);
}

return [(valueTexts && valueTexts[0]) || placeholder, onEnter, onLeave];
}
2 changes: 1 addition & 1 deletion src/hooks/useValueTexts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import useMemo from 'rc-util/lib/hooks/useMemo';
import { GenerateConfig } from '../generate';
import { Locale } from '../interface';

interface ValueTextConfig<DateType> {
export interface ValueTextConfig<DateType> {
formatList: string[];
generateConfig: GenerateConfig<DateType>;
locale: Locale;
Expand Down
30 changes: 30 additions & 0 deletions tests/picker.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -729,4 +729,34 @@ describe('Picker.Basic', () => {
const wrapper = mount(<MomentPicker open panelRender={() => <h1>Light</h1>} />);
expect(wrapper.render()).toMatchSnapshot();
});

describe('hover placeholder', () => {
const placeholder = 'custom placeholder';
it('placeholder should be origin value when input value is not empty', () => {
const wrapper = mount(
<MomentPicker placeholder={placeholder} open defaultValue={getMoment('2020-07-22')} />,
);
const cell = wrapper.findCell(24);
cell.simulate('mouseEnter');
expect(wrapper.find('input').prop('placeholder')).toBe(placeholder);
});

it('placeholder should be target date when input value is empty', () => {
const wrapper = mount(
<MomentPicker placeholder={placeholder} defaultValue={getMoment('2020-07-22')} />,
);
wrapper.openPicker();
wrapper.find('input').simulate('change', {
target: {
value: '',
},
});
const cell = wrapper.findCell(24);
cell.simulate('mouseEnter');
expect(wrapper.find('input').prop('placeholder')).toBe('2020-07-24');
cell.simulate('mouseLeave');
expect(wrapper.find('input').prop('placeholder')).toBe(placeholder);
wrapper.closePicker();
});
});
});
75 changes: 75 additions & 0 deletions tests/range.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1426,4 +1426,79 @@ describe('Picker.Range', () => {
);
});
});

describe('hover placeholder', () => {
const placeholder: [string, string] = ['custom placeholder1', 'custom placeholder2'];
const defaultValue: [Moment, Moment] = [getMoment('2020-07-22'), getMoment('2020-08-22')];

it('placeholder should be target date when input value is empty', () => {
const wrapper = mount(
<MomentRangePicker placeholder={placeholder} defaultValue={defaultValue} />,
);
wrapper.openPicker(0);
wrapper.inputValue('');
// left
const leftCell = wrapper.findCell('24');
leftCell.simulate('mouseEnter');
expect(
wrapper
.find('input')
.first()
.prop('placeholder'),
).toBe('2020-07-24');
expect(
wrapper
.find('input')
.last()
.prop('placeholder'),
).toBe(placeholder[1]);
leftCell.simulate('mouseLeave');
expect(
wrapper
.find('input')
.first()
.prop('placeholder'),
).toBe(placeholder[0]);
expect(
wrapper
.find('input')
.last()
.prop('placeholder'),
).toBe(placeholder[1]);
wrapper.closePicker(0);

// right
wrapper.openPicker(1);
wrapper.inputValue('', 1);

const rightCell = wrapper.findCell('24', 1);
rightCell.simulate('mouseEnter');
expect(
wrapper
.find('input')
.last()
.prop('placeholder'),
).toBe('2020-08-24');
expect(
wrapper
.find('input')
.first()
.prop('placeholder'),
).toBe(placeholder[0]);
rightCell.simulate('mouseLeave');
expect(
wrapper
.find('input')
.first()
.prop('placeholder'),
).toBe(placeholder[0]);
expect(
wrapper
.find('input')
.last()
.prop('placeholder'),
).toBe(placeholder[1]);
wrapper.closePicker(1);
});
});
});