Skip to content

Commit 2a939a2

Browse files
authored
refactor: Adjust time panel format fallback logic (#725)
* chore: add fallback logic * chore: refactoring * chore: clean up * chore: tmp of it * refactor: locale format logic * test: coverage
1 parent d8dcbc8 commit 2a939a2

File tree

9 files changed

+201
-141
lines changed

9 files changed

+201
-141
lines changed

docs/examples/debug.tsx

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -149,28 +149,8 @@ export default () => {
149149
<SinglePicker
150150
// Shared
151151
{...sharedLocale}
152-
// multiple
153-
// format="YYYY-MM-DD"
154-
// showTime={{
155-
// defaultValue: dayjs('2000-01-01 03:05:08'),
156-
// }}
157-
// autoFocus
158-
// defaultValue={[
159-
// dayjs(),
160-
// // dayjs('2000-01-01'),
161-
// // dayjs('2000-01-03'),
162-
// // dayjs('2000-01-05'),
163-
// // dayjs('2000-01-07'),
164-
// // dayjs('2000-01-09'),
165-
// ]}
166-
// disabledDate={(date) => date.date() >= 5}
167-
// getPopupContainer={(node) => {
168-
// console.log('Popup!', node);
169-
// return node.parentElement!;
170-
// }}
171-
// picker="time"
172-
showTime={{ showHour: true, showMinute: true }}
173-
defaultPickerValue={dayjs('2000-01-01 03:05:08')}
152+
showTime
153+
// format={(val) => val.format('YYYY-MM-DD')}
174154
presets={[
175155
{
176156
label: 'Good',
@@ -251,22 +231,16 @@ export default () => {
251231
</button>
252232

253233
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 16 }}>
254-
<PickerPanel
234+
{/* <PickerPanel
255235
generateConfig={dayjsGenerateConfig}
256236
locale={zhCN}
257237
value={value}
258-
// multiple
259-
picker="time"
260-
use12Hours
261238
onChange={setSingleValue}
262-
// onPickerValueChange={(pickerValue) => {
263-
// console.log('🎼 PickerValue Change:', pickerValue);
264-
// }}
265239
onPanelChange={(panelValue, mode) => {
266240
console.error('1');
267241
console.log('🎲 PanelValue Change:', panelValue, mode);
268242
}}
269-
/>
243+
/> */}
270244
{/* <CellPicker
271245
picker="time"
272246
locale={{

src/PickerInput/hooks/useFieldFormat.ts

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,6 @@
11
import * as React from 'react';
22
import type { FormatType, InternalMode, Locale, SharedPickerProps } from '../../interface';
3-
import { toArray } from '../../utils/miscUtil';
4-
5-
function getRowFormat(picker: InternalMode, locale: Locale, format?: SharedPickerProps['format']) {
6-
if (format) {
7-
return format;
8-
}
9-
10-
switch (picker) {
11-
// All from the `locale.fieldXXXFormat` first
12-
case 'time':
13-
return locale.fieldTimeFormat;
14-
case 'datetime':
15-
return locale.fieldDateTimeFormat;
16-
case 'month':
17-
return locale.fieldMonthFormat;
18-
case 'year':
19-
return locale.fieldYearFormat;
20-
case 'quarter':
21-
return locale.fieldQuarterFormat;
22-
case 'week':
23-
return locale.fieldWeekFormat;
24-
25-
default:
26-
return locale.fieldDateFormat;
27-
}
28-
}
3+
import { getRowFormat, toArray } from '../../utils/miscUtil';
294

305
export function useFieldFormat<DateType = any>(
316
picker: InternalMode,

src/PickerInput/hooks/useFilledProps.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ export default function useFilledProps<
109109
disabledDate,
110110
minDate,
111111
maxDate,
112+
showTime,
112113

113114
value,
114115
defaultValue,
@@ -123,8 +124,25 @@ export default function useFilledProps<
123124
const pickerValues = useList(pickerValue);
124125
const defaultPickerValues = useList(defaultPickerValue) || defaultOpenValues;
125126

127+
// ======================== Picker ========================
128+
/** Almost same as `picker`, but add `datetime` for `date` with `showTime` */
129+
const internalPicker: InternalMode = picker === 'date' && showTime ? 'datetime' : picker;
130+
131+
/** The picker is `datetime` or `time` */
132+
const complexPicker = internalPicker === 'time' || internalPicker === 'datetime' || multiple;
133+
const mergedNeedConfirm = needConfirm ?? complexPicker;
134+
135+
// ======================= Locales ========================
126136
const mergedLocale = fillLocale(locale);
127-
const mergedShowTime = getTimeConfig(props);
137+
const mergedShowTime = React.useMemo(
138+
() =>
139+
getTimeConfig({
140+
...props,
141+
picker: internalPicker,
142+
locale: mergedLocale,
143+
}),
144+
[props, internalPicker, mergedLocale],
145+
);
128146

129147
// ======================= Warning ========================
130148
if (process.env.NODE_ENV !== 'production' && picker === 'time') {
@@ -168,15 +186,6 @@ export default function useFilledProps<
168186
[props],
169187
);
170188

171-
// ======================== Picker ========================
172-
/** Almost same as `picker`, but add `datetime` for `date` with `showTime` */
173-
const internalPicker: InternalMode =
174-
picker === 'date' && filledProps.showTime ? 'datetime' : picker;
175-
176-
/** The picker is `datetime` or `time` */
177-
const complexPicker = internalPicker === 'time' || internalPicker === 'datetime' || multiple;
178-
const mergedNeedConfirm = needConfirm ?? complexPicker;
179-
180189
// ======================== Format ========================
181190
const [formatList, maskFormat] = useFieldFormat<DateType>(internalPicker, mergedLocale, format);
182191

src/PickerPanel/TimePanel/TimePanelBody/index.tsx

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ export default function TimePanelBody<DateType extends object = any>(
1515
props: SharedTimeProps<DateType>,
1616
) {
1717
const {
18+
// Show Config
19+
showHour,
20+
showMinute,
21+
showSecond,
22+
showMillisecond,
23+
use12Hours: showMeridiem,
24+
1825
// MISC
1926
changeOnScroll,
2027
} = props;
@@ -27,20 +34,8 @@ export default function TimePanelBody<DateType extends object = any>(
2734
const { onCellDblClick } = React.useContext(PickerHackContext);
2835

2936
// ========================== Info ==========================
30-
const [
31-
getValidTime,
32-
33-
showHour,
34-
showMinute,
35-
showSecond,
36-
showMillisecond,
37-
showMeridiem,
38-
39-
rowHourUnits,
40-
getMinuteUnits,
41-
getSecondUnits,
42-
getMillisecondUnits,
43-
] = useTimeInfo(generateConfig, props, value);
37+
const [getValidTime, rowHourUnits, getMinuteUnits, getSecondUnits, getMillisecondUnits] =
38+
useTimeInfo(generateConfig, props, value);
4439

4540
// ========================= Value ==========================
4641
// PickerValue will tell which one to align on the top

src/PickerPanel/index.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ function PickerPanel<DateType extends object = any>(
164164
mode,
165165
onPanelChange,
166166
picker = 'date',
167+
showTime,
167168

168169
// Hover
169170
hoverValue,
@@ -192,8 +193,19 @@ function PickerPanel<DateType extends object = any>(
192193
// ========================= Locale =========================
193194
const filledLocale = useLocale(locale);
194195

196+
// ========================= Picker =========================
197+
const internalPicker: InternalMode = picker === 'date' && showTime ? 'datetime' : picker;
198+
195199
// ======================== ShowTime ========================
196-
const mergedShowTime = getTimeConfig(props);
200+
const mergedShowTime = React.useMemo(
201+
() =>
202+
getTimeConfig({
203+
...props,
204+
picker: internalPicker,
205+
locale: filledLocale,
206+
}),
207+
[props, internalPicker, filledLocale],
208+
);
197209

198210
// ========================== Now ===========================
199211
const now = generateConfig.getNow();
@@ -206,7 +218,6 @@ function PickerPanel<DateType extends object = any>(
206218

207219
const internalMode: InternalMode =
208220
mergedMode === 'date' && mergedShowTime ? 'datetime' : mergedMode;
209-
const internalPicker: InternalMode = picker === 'date' && mergedShowTime ? 'datetime' : picker;
210221

211222
// ========================= Toggle =========================
212223
const toggleDates = useToggleDates(generateConfig, locale, internalPicker);

src/hooks/useTimeConfig.ts

Lines changed: 107 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
import type { PickerMode, SharedTimeProps } from '../interface';
2-
import { pickProps } from '../utils/miscUtil';
1+
import type { InternalMode, Locale, SharedPickerProps, SharedTimeProps } from '../interface';
2+
import { getRowFormat, pickProps, toArray } from '../utils/miscUtil';
3+
4+
function checkShow(format: string, keywords: string[], show?: boolean) {
5+
return show ?? keywords.some((keyword) => format.includes(keyword));
6+
}
37

48
const showTimeKeys = [
59
'format',
@@ -40,23 +44,113 @@ function pickTimeProps<DateType extends object = any>(props: any): SharedTimePro
4044
return timeProps;
4145
}
4246

43-
export function getTimeConfig<DateType extends object>(
44-
componentProps: {
45-
picker?: PickerMode;
46-
showTime?: boolean | Partial<SharedTimeProps<DateType>>;
47-
} = {},
48-
): SharedTimeProps<DateType> {
49-
const { showTime, picker } = componentProps;
47+
function isStringFormat(format: any): format is string {
48+
return format && typeof format === 'string';
49+
}
50+
51+
export function getTimeConfig<DateType extends object>(componentProps: {
52+
picker?: InternalMode;
53+
showTime?: boolean | Partial<SharedTimeProps<DateType>>;
54+
locale: Locale;
55+
format?: SharedPickerProps['format'];
56+
}): SharedTimeProps<DateType> {
57+
const { showTime, picker, locale, format: propFormat } = componentProps;
5058

51-
if (showTime || picker === 'time') {
52-
const timeConfig =
53-
showTime && typeof showTime === 'object' ? showTime : pickTimeProps(componentProps);
59+
const isTimePicker = picker === 'time';
60+
61+
if (showTime || isTimePicker) {
62+
const isShowTimeConfig = showTime && typeof showTime === 'object';
63+
64+
const timeConfig = isShowTimeConfig ? showTime : pickTimeProps(componentProps);
5465

5566
const pickedProps = pickProps(timeConfig);
5667

68+
// ====================== BaseFormat ======================
69+
const showTimeFormat = isShowTimeConfig ? showTime.format : isTimePicker && propFormat;
70+
const defaultFormat = getRowFormat(picker, locale, null) as string;
71+
72+
let baselineFormat = defaultFormat;
73+
74+
const formatList = [showTimeFormat, propFormat];
75+
for (let i = 0; i < formatList.length; i += 1) {
76+
const format = toArray(formatList[i])[0];
77+
78+
if (isStringFormat(format)) {
79+
baselineFormat = format;
80+
break;
81+
}
82+
}
83+
84+
// ========================= Show =========================
85+
let { showHour, showMinute, showSecond, showMillisecond } = pickedProps;
86+
const { use12Hours } = pickedProps;
87+
88+
const showMeridiem = checkShow(baselineFormat, ['a', 'A', 'LT', 'LLL'], use12Hours);
89+
90+
const hasShowConfig = [showHour, showMinute, showSecond, showMillisecond].some(
91+
(show) => show !== undefined,
92+
);
93+
94+
// Fill with format, if needed
95+
if (!hasShowConfig) {
96+
showHour = checkShow(baselineFormat, ['H', 'h', 'k', 'LT', 'LLL']);
97+
showMinute = checkShow(baselineFormat, ['m', 'LT', 'LLL']);
98+
showSecond = checkShow(baselineFormat, ['s', 'LTS']);
99+
showMillisecond = checkShow(baselineFormat, ['SSS']);
100+
}
101+
102+
// Fallback if all can not see
103+
if (!hasShowConfig && !showHour && !showMinute && !showSecond && !showMillisecond) {
104+
showHour = true;
105+
showMinute = true;
106+
showSecond = true;
107+
}
108+
109+
// ======================== Format ========================
110+
let timeFormat = isStringFormat(showTimeFormat) ? showTimeFormat : null;
111+
112+
if (!timeFormat) {
113+
timeFormat = '';
114+
115+
// Base HH:mm:ss
116+
const cells = [];
117+
118+
if (showHour) {
119+
cells.push('HH');
120+
}
121+
if (showMinute) {
122+
cells.push('mm');
123+
}
124+
if (showSecond) {
125+
cells.push('ss');
126+
}
127+
128+
timeFormat = cells.join(':');
129+
130+
// Millisecond
131+
if (showMillisecond) {
132+
timeFormat += '.SSS';
133+
}
134+
135+
// Meridiem
136+
if (showMeridiem) {
137+
timeFormat += ' A';
138+
}
139+
}
140+
141+
// ======================== Props =========================
57142
return {
58-
format: pickedProps.use12Hours ? 'HH:mm:ss A' : 'HH:mm:ss',
59143
...pickedProps,
144+
145+
// Format
146+
format: timeFormat,
147+
148+
// Show Config
149+
showHour,
150+
showMinute,
151+
showSecond,
152+
showMillisecond,
153+
use12Hours: showMeridiem,
60154
};
61155
}
62156

0 commit comments

Comments
 (0)