diff --git a/src/interface.ts b/src/interface.ts index 537ca4968..9f6f682e7 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -112,3 +112,10 @@ export interface PresetDate { label: React.ReactNode; value: T; } + +// https://stackoverflow.com/a/39495173; need TypeScript >= 4.5 +type Enumerate = Acc['length'] extends N + ? Acc[number] + : Enumerate + +export type IntRange = Exclude, Enumerate> diff --git a/src/panels/TimePanel/TimeBody.tsx b/src/panels/TimePanel/TimeBody.tsx index 186182a4e..533415a77 100644 --- a/src/panels/TimePanel/TimeBody.tsx +++ b/src/panels/TimePanel/TimeBody.tsx @@ -24,7 +24,8 @@ function generateUnits( disabledUnits: number[] | undefined, ) { const units: Unit[] = []; - for (let i = start; i <= end; i += step) { + const integerStep = step >= 1 ? step | 0 : 1 + for (let i = start; i <= end; i += integerStep) { units.push({ label: leftPad(i, 2), value: i, diff --git a/src/panels/TimePanel/index.tsx b/src/panels/TimePanel/index.tsx index 8025a3a14..a402523ef 100644 --- a/src/panels/TimePanel/index.tsx +++ b/src/panels/TimePanel/index.tsx @@ -3,7 +3,7 @@ import classNames from 'classnames'; import TimeHeader from './TimeHeader'; import type { BodyOperationRef } from './TimeBody'; import TimeBody from './TimeBody'; -import type { PanelSharedProps, DisabledTimes } from '../../interface'; +import type { PanelSharedProps, DisabledTimes, IntRange } from '../../interface'; import { createKeyDownHandler } from '../../utils/uiUtil'; export type SharedTimeProps = { @@ -13,9 +13,9 @@ export type SharedTimeProps = { showMinute?: boolean; showSecond?: boolean; use12Hours?: boolean; - hourStep?: number; - minuteStep?: number; - secondStep?: number; + hourStep?: IntRange<1, 23>; + minuteStep?: IntRange<1, 59>; + secondStep?: IntRange<1, 59>; hideDisabledOptions?: boolean; defaultValue?: DateType; diff --git a/tests/__snapshots__/picker.spec.tsx.snap b/tests/__snapshots__/picker.spec.tsx.snap index 11780579a..81d64bd6d 100644 --- a/tests/__snapshots__/picker.spec.tsx.snap +++ b/tests/__snapshots__/picker.spec.tsx.snap @@ -103,3 +103,288 @@ exports[`Picker.Basic should render correctly in rtl 1`] = ` `; + +exports[`Picker.Basic time step should show integer when step is not integer (hour) 1`] = ` +
    +
  • +
    + 00 +
    +
  • +
  • +
    + 05 +
    +
  • +
  • +
    + 10 +
    +
  • +
  • +
    + 15 +
    +
  • +
  • +
    + 20 +
    +
  • +
+`; + +exports[`Picker.Basic time step should show integer when step is not integer (minute) 1`] = ` +
    +
  • +
    + 00 +
    +
  • +
  • +
    + 05 +
    +
  • +
  • +
    + 10 +
    +
  • +
  • +
    + 15 +
    +
  • +
  • +
    + 20 +
    +
  • +
  • +
    + 25 +
    +
  • +
  • +
    + 30 +
    +
  • +
  • +
    + 35 +
    +
  • +
  • +
    + 40 +
    +
  • +
  • +
    + 45 +
    +
  • +
  • +
    + 50 +
    +
  • +
  • +
    + 55 +
    +
  • +
+`; + +exports[`Picker.Basic time step should show integer when step is not integer (second) 1`] = ` +
    +
  • +
    + 00 +
    +
  • +
  • +
    + 05 +
    +
  • +
  • +
    + 10 +
    +
  • +
  • +
    + 15 +
    +
  • +
  • +
    + 20 +
    +
  • +
  • +
    + 25 +
    +
  • +
  • +
    + 30 +
    +
  • +
  • +
    + 35 +
    +
  • +
  • +
    + 40 +
    +
  • +
  • +
    + 45 +
    +
  • +
  • +
    + 50 +
    +
  • +
  • +
    + 55 +
    +
  • +
+`; diff --git a/tests/picker.spec.tsx b/tests/picker.spec.tsx index c41044171..d870aabef 100644 --- a/tests/picker.spec.tsx +++ b/tests/picker.spec.tsx @@ -616,6 +616,25 @@ describe('Picker.Basic', () => { ); spy.mockRestore(); }); + + // https://github.com/ant-design/ant-design/issues/40914 + ['hour', 'minute', 'second'].forEach((unit, index) => { + it(`should show integer when step is not integer (${unit})`, () => { + const props = { + [`${unit}Step`]: 5.5, + } + const { container } = render(); + openPicker(container); + expect(document.querySelectorAll('.rc-picker-time-panel-column')[index]).toMatchSnapshot(); + }); + }); + + it('should work when hourStep < 0', () => { + // @ts-ignore + const { container } = render(); + openPicker(container); + expect(document.querySelectorAll('.rc-picker-time-panel-column')[0].children.length).toBe(24); + }); }); it('pass data- & aria- & role', () => {