Skip to content

Commit 9283926

Browse files
authored
feat: support semantic for time panel (#926)
1 parent 6a0b120 commit 9283926

File tree

9 files changed

+115
-14
lines changed

9 files changed

+115
-14
lines changed

docs/examples/time.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ import zhCN from '../../src/locale/zh_CN';
66
import '../../assets/index.less';
77

88
const defaultValue = moment('2019-11-28 01:02:03');
9+
const testClassNames = {
10+
input: 'test-input',
11+
prefix: 'test-prefix',
12+
suffix: 'test-suffix',
13+
popupContent: 'test-popup-content',
14+
popupItem: 'test-popup-item',
15+
}
916

1017
export default () => {
1118
return (
@@ -24,6 +31,9 @@ export default () => {
2431

2532
<h3>TimePicker</h3>
2633
<Picker
34+
classNames={testClassNames}
35+
prefix="prefix"
36+
suffixIcon="suffix"
2737
defaultValue={defaultValue}
2838
picker="time"
2939
locale={zhCN}

src/PickerInput/Selector/Icon.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as React from 'react';
22
import PickerContext from '../context';
3+
import classNames from 'classnames';
34

45
export interface IconProps extends React.HtmlHTMLAttributes<HTMLElement> {
56
icon?: React.ReactNode;
@@ -8,11 +9,14 @@ export interface IconProps extends React.HtmlHTMLAttributes<HTMLElement> {
89

910
export default function Icon(props: IconProps) {
1011
const { icon, type, ...restProps } = props;
11-
12-
const { prefixCls } = React.useContext(PickerContext);
12+
const { prefixCls, classNames: iconClassNames, styles } = React.useContext(PickerContext);
1313

1414
return icon ? (
15-
<span className={`${prefixCls}-${type}`} {...restProps}>
15+
<span
16+
className={classNames(`${prefixCls}-${type}`, iconClassNames?.suffix)}
17+
style={styles?.suffix}
18+
{...restProps}
19+
>
1620
{icon}
1721
</span>
1822
) : null;

src/PickerInput/Selector/Input.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,12 @@ const Input = React.forwardRef<InputRef, InputProps>((props, ref) => {
7272
} = props;
7373
const { value, onFocus, onBlur, onMouseUp } = props;
7474

75-
const { prefixCls, input: Component = 'input' } = React.useContext(PickerContext);
75+
const {
76+
prefixCls,
77+
input: Component = 'input',
78+
classNames: inputClassNames,
79+
styles,
80+
} = React.useContext(PickerContext);
7681
const inputPrefixCls = `${prefixCls}-input`;
7782

7883
// ======================== Value =========================
@@ -380,12 +385,14 @@ const Input = React.forwardRef<InputRef, InputProps>((props, ref) => {
380385
ref={holderRef}
381386
className={classNames(
382387
inputPrefixCls,
388+
inputClassNames?.input,
383389
{
384390
[`${inputPrefixCls}-active`]: active && showActiveCls,
385391
[`${inputPrefixCls}-placeholder`]: helped,
386392
},
387393
className,
388394
)}
395+
style={styles?.input}
389396
>
390397
<Component
391398
ref={inputRef}

src/PickerInput/Selector/RangeSelector.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ function RangeSelector<DateType extends object = any>(
121121
const rtl = direction === 'rtl';
122122

123123
// ======================== Prefix ========================
124-
const { prefixCls } = React.useContext(PickerContext);
124+
const { prefixCls, classNames: selectorClassNames, styles } = React.useContext(PickerContext);
125125

126126
// ========================== Id ==========================
127127
const ids = React.useMemo(() => {
@@ -238,7 +238,14 @@ function RangeSelector<DateType extends object = any>(
238238
onMouseDown?.(e);
239239
}}
240240
>
241-
{prefix && <div className={`${prefixCls}-prefix`}>{prefix}</div>}
241+
{prefix && (
242+
<div
243+
className={classNames(`${prefixCls}-prefix`, selectorClassNames?.prefix)}
244+
style={styles?.prefix}
245+
>
246+
{prefix}
247+
</div>
248+
)}
242249
<Input
243250
ref={inputStartRef}
244251
{...getInputProps(0)}

src/PickerInput/Selector/SingleSelector/index.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ function SingleSelector<DateType extends object = any>(
110110
const rtl = direction === 'rtl';
111111

112112
// ======================== Prefix ========================
113-
const { prefixCls } = React.useContext(PickerContext);
113+
const { prefixCls, classNames: selectorClassNames, styles } = React.useContext(PickerContext);
114114

115115
// ========================= Refs =========================
116116
const rootRef = React.useRef<HTMLDivElement>();
@@ -225,7 +225,14 @@ function SingleSelector<DateType extends object = any>(
225225
onMouseDown?.(e);
226226
}}
227227
>
228-
{prefix && <div className={`${prefixCls}-prefix`}>{prefix}</div>}
228+
{prefix && (
229+
<div
230+
className={classNames(`${prefixCls}-prefix`, selectorClassNames?.prefix)}
231+
style={styles?.prefix}
232+
>
233+
{prefix}
234+
</div>
235+
)}
229236
{selectorNode}
230237
</div>
231238
);

src/PickerPanel/TimePanel/TimePanelBody/TimeColumn.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import classNames from 'classnames';
22
import useLayoutEffect from '@rc-component/util/lib/hooks/useLayoutEffect';
33
import * as React from 'react';
4-
import { usePanelContext } from '../../context';
4+
import { PickerHackContext, usePanelContext } from '../../context';
55
import useScrollTo from './useScrollTo';
66

77
const SCROLL_DELAY = 300;
@@ -33,6 +33,7 @@ export default function TimeColumn<DateType extends object>(props: TimeUnitColum
3333
props;
3434

3535
const { prefixCls, cellRender, now, locale } = usePanelContext<DateType>();
36+
const { classNames: pickerClassNames, styles } = React.useContext(PickerHackContext);
3637

3738
const panelPrefixCls = `${prefixCls}-time-panel`;
3839
const cellPrefixCls = `${prefixCls}-time-panel-cell`;
@@ -103,7 +104,8 @@ export default function TimeColumn<DateType extends object>(props: TimeUnitColum
103104
return (
104105
<li
105106
key={unitValue}
106-
className={classNames(cellPrefixCls, {
107+
style={styles?.popupItem}
108+
className={classNames(cellPrefixCls, pickerClassNames?.popupItem, {
107109
[`${cellPrefixCls}-selected`]: value === unitValue,
108110
[`${cellPrefixCls}-disabled`]: disabled,
109111
})}

src/PickerPanel/TimePanel/TimePanelBody/index.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { SharedPanelProps, SharedTimeProps } from '../../../interface';
44
import { formatValue } from '../../../utils/dateUtil';
55
import { PickerHackContext, usePanelContext } from '../../context';
66
import TimeColumn, { type Unit } from './TimeColumn';
7+
import classNames from 'classnames';
78

89
function isAM(hour: number) {
910
return hour < 12;
@@ -38,7 +39,11 @@ export default function TimePanelBody<DateType extends object = any>(
3839

3940
const value = values?.[0] || null;
4041

41-
const { onCellDblClick } = React.useContext(PickerHackContext);
42+
const {
43+
onCellDblClick,
44+
classNames: pickerClassNames,
45+
styles,
46+
} = React.useContext(PickerHackContext);
4247

4348
// ========================== Info ==========================
4449
const [getValidTime, rowHourUnits, getMinuteUnits, getSecondUnits, getMillisecondUnits] =
@@ -268,7 +273,10 @@ export default function TimePanelBody<DateType extends object = any>(
268273
};
269274

270275
return (
271-
<div className={`${prefixCls}-content`}>
276+
<div
277+
className={classNames(`${prefixCls}-content`, pickerClassNames?.popupContent)}
278+
style={styles?.popupContent}
279+
>
272280
{showHour && (
273281
<TimeColumn
274282
units={hourUnits}

src/interface.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ export type Components<DateType extends object = any> = Partial<
281281
>;
282282

283283
// ========================= Picker =========================
284-
export type SemanticStructure = 'popup' | 'popupBody' | 'popupContent' | 'popupItem';
284+
export type SemanticStructure = 'popup' | 'popupBody' | 'popupContent' | 'popupItem' | 'suffix' | 'prefix' | 'input';
285285

286286
export type CustomFormat<DateType> = (value: DateType) => string;
287287

tests/picker.spec.tsx

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import KeyCode from '@rc-component/util/lib/KeyCode';
88
import { spyElementPrototypes } from '@rc-component/util/lib/test/domHook';
99
import { resetWarned } from '@rc-component/util/lib/warning';
1010
import React from 'react';
11-
import { PickerPanel, type PickerRef } from '../src';
11+
import Picker, { PickerPanel, type PickerRef } from '../src';
1212
import type { PanelMode, PickerMode } from '../src/interface';
1313
import momentGenerateConfig from '../src/generate/moment';
1414
import enUS from '../src/locale/en_US';
@@ -1406,6 +1406,62 @@ describe('Picker.Basic', () => {
14061406
expect(item).toHaveClass(customClassNames.popupItem);
14071407
expect(item).toHaveStyle(customStyles.popupItem);
14081408
});
1409+
it('classNames and styles should support time panel', async () => {
1410+
const testClassNames = {
1411+
input: 'test-input',
1412+
prefix: 'test-prefix',
1413+
suffix: 'test-suffix',
1414+
popupContent: 'custom-content',
1415+
popupItem: 'custom-item',
1416+
};
1417+
const testStyles = {
1418+
input: { color: 'red' },
1419+
prefix: { color: 'green' },
1420+
suffix: { color: 'blue' },
1421+
popupContent: { color: 'blue' },
1422+
popupItem: { color: 'yellow' },
1423+
};
1424+
const defaultValue = moment('2019-11-28 01:02:03');
1425+
const { container } = render(
1426+
<Picker
1427+
classNames={testClassNames}
1428+
styles={testStyles}
1429+
prefix="prefix"
1430+
suffixIcon="suffix"
1431+
defaultValue={defaultValue}
1432+
picker="time"
1433+
locale={zhCN}
1434+
disabledTime={(now) => ({
1435+
disabledHours: () => [now.hours()],
1436+
})}
1437+
generateConfig={momentGenerateConfig}
1438+
/>,
1439+
);
1440+
const input = container.querySelectorAll('.rc-picker-input')[0];
1441+
const prefix = container.querySelector('.rc-picker-prefix');
1442+
const suffix = container.querySelector('.rc-picker-suffix');
1443+
expect(input).toHaveClass(testClassNames.input);
1444+
expect(input).toHaveStyle(testStyles.input);
1445+
expect(prefix).toHaveClass(testClassNames.prefix);
1446+
expect(prefix).toHaveStyle(testStyles.prefix);
1447+
expect(suffix).toHaveClass(testClassNames.suffix);
1448+
expect(suffix).toHaveStyle(testStyles.suffix);
1449+
const { container: panel } = render(
1450+
<PickerPanel
1451+
classNames={testClassNames}
1452+
styles={testStyles}
1453+
picker="time"
1454+
locale={enUS}
1455+
generateConfig={momentGenerateConfig}
1456+
/>,
1457+
);
1458+
const content = panel.querySelector('.rc-picker-content');
1459+
const item = panel.querySelector('.rc-picker-time-panel-cell');
1460+
expect(content).toHaveClass(testClassNames.popupContent);
1461+
expect(content).toHaveStyle(testStyles.popupContent);
1462+
expect(item).toHaveClass(testClassNames.popupItem);
1463+
expect(item).toHaveStyle(testStyles.popupItem);
1464+
});
14091465
it('showTime config should have format', () => {
14101466
render(
14111467
<DayPicker

0 commit comments

Comments
 (0)