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
47 changes: 15 additions & 32 deletions packages/lib/src/time-input/TimeInput.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,19 +119,10 @@ const TimePickerExamples = () => {
<ExampleContainer>
<Title title="Time Picker 24h format" theme="light" level={3} />
<DxcContainer width="250px">
<TimePicker onSelectMinutes={() => {}} onSelectHours={() => {}} timeFormat="24" id="testId" tabIndex={0} />
<TimePicker onPickTime={() => {}} timeFormat="24" id="testId" tabIndex={0} />
<TimePicker onPickTime={() => {}} timeFormat="24" id="testId" tabIndex={0} hourValue={15} minuteValue={30} />
<TimePicker
onSelectMinutes={() => {}}
onSelectHours={() => {}}
timeFormat="24"
id="testId"
tabIndex={0}
hourValue={15}
minuteValue={30}
/>
<TimePicker
onSelectMinutes={() => {}}
onSelectHours={() => {}}
onPickTime={() => {}}
timeFormat="24"
id="testId"
tabIndex={0}
Expand All @@ -145,10 +136,9 @@ const TimePickerExamples = () => {
<ExampleContainer>
<Title title="Time Picker 12h format" theme="light" level={3} />
<DxcContainer width="250px">
<TimePicker onSelectMinutes={() => {}} onSelectHours={() => {}} timeFormat="12" id="testId" tabIndex={0} />
<TimePicker onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} />
<TimePicker
onSelectMinutes={() => {}}
onSelectHours={() => {}}
onPickTime={() => {}}
timeFormat="12"
id="testId"
tabIndex={0}
Expand All @@ -157,8 +147,7 @@ const TimePickerExamples = () => {
dayPeriod={1}
/>
<TimePicker
onSelectMinutes={() => {}}
onSelectHours={() => {}}
onPickTime={() => {}}
timeFormat="12"
id="testId"
tabIndex={0}
Expand All @@ -173,10 +162,9 @@ const TimePickerExamples = () => {
<ExampleContainer pseudoState={"pseudo-hover"}>
<Title title="hover" theme="light" level={3} />
<DxcContainer width="250px">
<TimePicker onSelectMinutes={() => {}} onSelectHours={() => {}} timeFormat="12" id="testId" tabIndex={0} />
<TimePicker onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} />
<TimePicker
onSelectMinutes={() => {}}
onSelectHours={() => {}}
onPickTime={() => {}}
timeFormat="12"
id="testId"
tabIndex={0}
Expand All @@ -185,8 +173,7 @@ const TimePickerExamples = () => {
dayPeriod={1}
/>
<TimePicker
onSelectMinutes={() => {}}
onSelectHours={() => {}}
onPickTime={() => {}}
timeFormat="12"
id="testId"
tabIndex={0}
Expand All @@ -201,10 +188,9 @@ const TimePickerExamples = () => {
<ExampleContainer pseudoState={"pseudo-focus"}>
<Title title="focus" theme="light" level={3} />
<DxcContainer width="250px">
<TimePicker onSelectMinutes={() => {}} onSelectHours={() => {}} timeFormat="12" id="testId" tabIndex={0} />
<TimePicker onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} />
<TimePicker
onSelectMinutes={() => {}}
onSelectHours={() => {}}
onPickTime={() => {}}
timeFormat="12"
id="testId"
tabIndex={0}
Expand All @@ -213,8 +199,7 @@ const TimePickerExamples = () => {
dayPeriod={1}
/>
<TimePicker
onSelectMinutes={() => {}}
onSelectHours={() => {}}
onPickTime={() => {}}
timeFormat="12"
id="testId"
tabIndex={0}
Expand All @@ -229,10 +214,9 @@ const TimePickerExamples = () => {
<ExampleContainer pseudoState={"pseudo-active"}>
<Title title="active" theme="light" level={3} />
<DxcContainer width="250px">
<TimePicker onSelectMinutes={() => {}} onSelectHours={() => {}} timeFormat="12" id="testId" tabIndex={0} />
<TimePicker onPickTime={() => {}} timeFormat="12" id="testId" tabIndex={0} />
<TimePicker
onSelectMinutes={() => {}}
onSelectHours={() => {}}
onPickTime={() => {}}
timeFormat="12"
id="testId"
tabIndex={0}
Expand All @@ -241,8 +225,7 @@ const TimePickerExamples = () => {
dayPeriod={1}
/>
<TimePicker
onSelectMinutes={() => {}}
onSelectHours={() => {}}
onPickTime={() => {}}
timeFormat="12"
id="testId"
tabIndex={0}
Expand Down
14 changes: 7 additions & 7 deletions packages/lib/src/time-input/TimeInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,13 @@ describe("DxcTimeInput rendering", () => {
expect(getByText("AM")).toBeTruthy();
const hourbutton = getAllByText("07");
if (hourbutton[0]) userEvent.click(hourbutton[0]);
expect(mockOnChange).toHaveBeenCalledWith("07: ");
expect(mockOnChange).toHaveBeenCalledWith("07:00 AM");
const minuteButton = getAllByText("30");
if (minuteButton[0]) userEvent.click(minuteButton[0]);
expect(mockOnChange).toHaveBeenCalledWith("07:30 ");
const amButton = getByText("AM");
expect(mockOnChange).toHaveBeenCalledWith("07:30 AM");
const amButton = getAllByText("AM")[0];
expect(amButton).toBeTruthy();
userEvent.click(amButton);
if (amButton) userEvent.click(amButton);
expect(mockOnChange).toHaveBeenCalledWith("07:30 AM");
});

Expand All @@ -130,14 +130,14 @@ describe("DxcTimeInput rendering", () => {
userEvent.keyboard("{ArrowDown}");
userEvent.keyboard("{ArrowDown}");
userEvent.keyboard("{Enter}");
expect(mockOnChange).toHaveBeenCalledWith("03: ");
expect(mockOnChange).toHaveBeenCalledWith("03:00 AM");
userEvent.tab();
userEvent.keyboard("{ArrowUp}");
userEvent.keyboard("{Enter}");
expect(mockOnChange).toHaveBeenCalledWith("03:55 ");
expect(mockOnChange).toHaveBeenCalledWith("03:55 AM");
userEvent.keyboard("{ArrowDown}");
userEvent.keyboard(" ");
expect(mockOnChange).toHaveBeenCalledWith("03:00 ");
expect(mockOnChange).toHaveBeenCalledWith("03:00 AM");
userEvent.tab();
userEvent.keyboard("{ArrowDown}");
userEvent.keyboard("{Enter}");
Expand Down
51 changes: 12 additions & 39 deletions packages/lib/src/time-input/TimeInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ const ColonContainer = styled.span`
color: var(--color-fg-neutral-dark);
`;

const isNumber = (value: string) => /^\d{1,2}$/.test(value);

const DxcTimeInput = forwardRef<RefType, TimeInputPropsType>(
(
{
Expand Down Expand Up @@ -95,10 +97,10 @@ const DxcTimeInput = forwardRef<RefType, TimeInputPropsType>(
if (time) {
const numberPart = timeFormat === "12" ? time.split(" ")[0] : time;
if (numberPart) {
const [hour, minute, second] = numberPart.split(":").map(Number);
setHourValue(hour || hour === 0 ? hour : undefined);
setMinuteValue(minute || minute === 0 ? minute : undefined);
setSecondValue(second || second === 0 ? second : undefined);
const [hourStr, minuteStr, secondStr] = numberPart.split(":");
setHourValue(hourStr && isNumber(hourStr) ? Number(hourStr) : undefined);
setMinuteValue(minuteStr && isNumber(minuteStr) ? Number(minuteStr) : undefined);
setSecondValue(secondStr && isNumber(secondStr) ? Number(secondStr) : undefined);
}
if (timeFormat === "12" && time.includes(" ")) {
const dayPeriodValue = time.split(" ")[1] === "AM" ? 0 : time.split(" ")[1] === "PM" ? 1 : undefined;
Expand Down Expand Up @@ -343,44 +345,15 @@ const DxcTimeInput = forwardRef<RefType, TimeInputPropsType>(
<DxcPopover
popoverContent={
<TimePicker
onSelectHours={(value) => {
if (!isControlled) {
setHourValue(value);
}
if (typeof onChange === "function") {
onChange(
generateEventValue(value, minuteValue, secondValue, dayPeriodValue, showSeconds, timeFormat)
);
}
}}
onSelectMinutes={(value) => {
if (!isControlled) {
setMinuteValue(value);
}
if (typeof onChange === "function") {
onChange(
generateEventValue(hourValue, value, secondValue, dayPeriodValue, showSeconds, timeFormat)
);
}
}}
onSelectSeconds={(value) => {
if (!isControlled) {
setSecondValue(value);
}
if (typeof onChange === "function") {
onChange(
generateEventValue(hourValue, minuteValue, value, dayPeriodValue, showSeconds, timeFormat)
);
}
}}
onSelectDayPeriod={(value: number) => {
onPickTime={(hour, minute, second, dayPeriod) => {
if (!isControlled) {
setDayPeriodValue(value);
setDayPeriodValue(dayPeriod);
setSecondValue(second);
setMinuteValue(minute);
setHourValue(hour);
}
if (typeof onChange === "function") {
onChange(
generateEventValue(hourValue, minuteValue, secondValue, value, showSeconds, timeFormat)
);
onChange(generateEventValue(hour, minute, second, dayPeriod, showSeconds, timeFormat));
}
}}
timeFormat={timeFormat}
Expand Down
71 changes: 46 additions & 25 deletions packages/lib/src/time-input/TimePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { TimePickerPropsType } from "./types";
import { useEffect, useState } from "react";
import TimePickerColumn from "./TimePickerColumn";
import { handleColumnKeyDown } from "./utils";

// Array to be used in seconds and minutes.
const STEP = 5;
const ARRAY_OF_60 = Array.from({ length: 60 / STEP }, (_, index) => index * STEP);
Expand All @@ -15,10 +14,7 @@ const TimePickerContainer = styled.div`
`;

const TimePicker = ({
onSelectHours,
onSelectMinutes,
onSelectSeconds,
onSelectDayPeriod,
onPickTime,
timeFormat,
showSeconds,
hourValue,
Expand All @@ -28,12 +24,25 @@ const TimePicker = ({
id,
tabIndex = 0,
}: TimePickerPropsType) => {
const [hourToFocus, setHourToFocus] = useState(hourValue || 1);
const [minuteToFocus, setMinuteToFocus] = useState(minuteValue || 0);
const [secondToFocus, setSecondToFocus] = useState(secondValue || 0);
const [dayPeriodToFocus, setDayPeriodToFocus] = useState(dayPeriod || 0);
const [hourToFocus, setHourToFocus] = useState(hourValue ?? (timeFormat === "12" ? 1 : 0));
const [minuteToFocus, setMinuteToFocus] = useState(minuteValue ?? 0);
const [secondToFocus, setSecondToFocus] = useState(secondValue ?? 0);
const [dayPeriodToFocus, setDayPeriodToFocus] = useState(dayPeriod ?? 0);
const totalHours = timeFormat === "12" ? 12 : 24;

const onPickerSelect = (value: number, type: "hour" | "minute" | "second" | "dayPeriod") => {
const hourVal = type === "hour" ? value : (hourValue ?? (timeFormat === "12" ? 1 : 0));
const minuteVal = type === "minute" ? value : (minuteValue ?? 0);
const secondVal = type === "second" ? value : (secondValue ?? 0);
const dayPeriodVal = type === "dayPeriod" ? value : (dayPeriod ?? 0);

setDayPeriodToFocus(dayPeriodVal);
setSecondToFocus(secondVal);
setMinuteToFocus(minuteVal);
setHourToFocus(hourVal);
onPickTime(hourVal, minuteVal, secondVal, dayPeriodVal);
};

useEffect(() => {
if (dayPeriodToFocus !== undefined && id) {
document.getElementById(`${id}-dayPeriod-${dayPeriodToFocus}`)?.focus();
Expand Down Expand Up @@ -65,11 +74,12 @@ const TimePicker = ({
tabIndex={tabIndex}
dataType="hour"
onClick={(value: number) => {
onSelectHours(value);
setHourToFocus(value);
onPickerSelect(value, "hour");
}}
onKeyboardEvent={(event: React.KeyboardEvent, value: number) =>
handleColumnKeyDown(event, "hour", value, totalHours, setHourToFocus, onSelectHours)
handleColumnKeyDown(event, "hour", value, totalHours, setHourToFocus, (value) =>
onPickerSelect(value, "hour")
)
}
/>
<TimePickerColumn
Expand All @@ -80,11 +90,18 @@ const TimePicker = ({
tabIndex={tabIndex}
dataType="minute"
onClick={(value: number) => {
onSelectMinutes(value);
setMinuteToFocus(value);
onPickerSelect(value, "minute");
}}
onKeyboardEvent={(event: React.KeyboardEvent, value: number) =>
handleColumnKeyDown(event, "minute", value, 60, setMinuteToFocus, onSelectMinutes, STEP)
handleColumnKeyDown(
event,
"minute",
value,
60,
setMinuteToFocus,
(value) => onPickerSelect(value, "minute"),
STEP
)
}
/>
{showSeconds && (
Expand All @@ -96,13 +113,18 @@ const TimePicker = ({
tabIndex={tabIndex}
dataType="second"
onClick={(value: number) => {
if (typeof onSelectSeconds === "function") {
onSelectSeconds(value);
setSecondToFocus(value);
}
onPickerSelect(value, "second");
}}
onKeyboardEvent={(event: React.KeyboardEvent, value: number) =>
handleColumnKeyDown(event, "second", value, 60, setSecondToFocus, onSelectSeconds, STEP)
handleColumnKeyDown(
event,
"second",
value,
60,
setSecondToFocus,
(value) => onPickerSelect(value, "second"),
STEP
)
}
/>
)}
Expand All @@ -115,13 +137,12 @@ const TimePicker = ({
tabIndex={tabIndex}
dataType="dayPeriod"
onClick={(value: number) => {
if (typeof onSelectDayPeriod === "function") {
onSelectDayPeriod(value);
setDayPeriodToFocus(value);
}
onPickerSelect(value, "dayPeriod");
}}
onKeyboardEvent={(event: React.KeyboardEvent, value: number) =>
handleColumnKeyDown(event, "dayPeriod", value, 2, setDayPeriodToFocus, onSelectDayPeriod)
handleColumnKeyDown(event, "dayPeriod", value, 2, setDayPeriodToFocus, (value) =>
onPickerSelect(value, "dayPeriod")
)
}
/>
)}
Expand Down
5 changes: 1 addition & 4 deletions packages/lib/src/time-input/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,7 @@ export type TimeSpinButtonPropsType = {
};

export type TimePickerPropsType = {
onSelectHours: (hours: number) => void;
onSelectMinutes: (minutes: number) => void;
onSelectSeconds?: (seconds: number) => void;
onSelectDayPeriod?: (isPM: number) => void;
onPickTime: (hours: number, minutes: number, seconds?: number, dayPeriod?: number) => void;
timeFormat: "12" | "24";
showSeconds?: boolean;
hourValue?: number;
Expand Down
1 change: 0 additions & 1 deletion packages/lib/src/time-input/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ export const handleKeyDown = (
rawInput.current = (rawInput.current + newDigit.current).slice(-maxValue.toString().length);
newValue = resolveValue(rawInput.current, maxValue, minValue);
// If the raw input has reached the max length or exceeds the max value with the new digit, consider it complete and move to the next field.
console.log("rawInput:", rawInput.current, "newDigit:", newDigit.current, "newValue:", newValue);
if (checkCompletion(rawInput.current, maxValue)) {
rawInput.current = pad(newValue);
if (typeof onComplete === "function") {
Expand Down
Loading