@hitachivantara/uikit-react-core
Version:
Core React components for the NEXT Design System.
219 lines (218 loc) • 7.65 kB
JavaScript
import { jsxs, jsx } from "react/jsx-runtime";
import { forwardRef, useRef, useState, useMemo } from "react";
import { Time } from "@internationalized/date";
import { useForkRef } from "@mui/material/utils";
import { useTimeField } from "@react-aria/datepicker";
import { useTimeFieldState } from "@react-stately/datepicker";
import { useDefaultProps } from "@hitachivantara/uikit-react-utils";
import { DEFAULT_LOCALE } from "../Calendar/utils.js";
import { HvLabelContainer } from "../FormElement/LabelContainer.js";
import { useControlled } from "../hooks/useControlled.js";
import { useUniqueId } from "../hooks/useUniqueId.js";
import { HvIcon } from "../icons.js";
import { setId } from "../utils/setId.js";
import { Placeholder } from "./Placeholder.js";
import { useClasses } from "./TimePicker.styles.js";
import { staticClasses } from "./TimePicker.styles.js";
import { Unit } from "./Unit/Unit.js";
import { HvFormElement } from "../FormElement/FormElement.js";
import { HvBaseDropdown } from "../BaseDropdown/BaseDropdown.js";
import { HvWarningText } from "../FormElement/WarningText/WarningText.js";
const toTime = (value) => {
if (!value) return value;
const { hours, minutes, seconds } = value;
return new Time(hours, minutes, seconds);
};
const HvTimePicker = forwardRef(
function HvTimePicker2(props, ref) {
const {
classes: classesProp,
className,
id: idProp,
name,
required,
disabled,
readOnly,
label,
"aria-label": ariaLabel,
"aria-labelledby": ariaLabelledBy,
description,
"aria-describedby": ariaDescribedBy,
status,
statusMessage,
"aria-errormessage": ariaErrorMessage,
placeholder,
hoursPlaceholder = "hh",
minutesPlaceholder = "mm",
secondsPlaceholder = "ss",
value: valueProp,
defaultValue: defaultValueProp,
timeFormat,
showSeconds,
disableExpand,
locale = DEFAULT_LOCALE,
onToggle,
onChange,
// misc properties:
disablePortal = true,
escapeWithReference = true,
dropdownProps = {},
...others
} = useDefaultProps("HvTimePicker", props);
const id = useUniqueId(idProp);
const { classes, cx } = useClasses(classesProp);
const timeFieldRef = useRef(null);
const { ref: refProp, ...otherDropdownProps } = dropdownProps;
const dropdownForkedRef = useForkRef(ref, refProp);
const stateProps = {
value: toTime(valueProp),
defaultValue: toTime(defaultValueProp),
label,
locale,
isRequired: required,
isReadOnly: readOnly,
isDisabled: disabled,
granularity: showSeconds === false ? "minute" : "second",
hourCycle: timeFormat === "12" ? 12 : 24,
onChange: (value) => {
if (!value) return;
const { hour: hours, minute: minutes, second: seconds } = value;
onChange?.({ hours, minutes, seconds });
}
};
const state = useTimeFieldState(stateProps);
const { labelProps, fieldProps, descriptionProps } = useTimeField(
{
...stateProps,
id,
"aria-label": ariaLabel,
"aria-labelledby": ariaLabelledBy,
"aria-describedby": ariaDescribedBy
},
state,
timeFieldRef
);
const [open, setOpen] = useState(false);
const [validationMessage] = useControlled(statusMessage, "Required");
const [validationState] = useControlled(status, "standBy");
const placeholders = useMemo(
() => ({
hour: hoursPlaceholder,
minute: minutesPlaceholder,
second: secondsPlaceholder
}),
[hoursPlaceholder, minutesPlaceholder, secondsPlaceholder]
);
const canShowError = ariaErrorMessage == null && (status !== void 0 && statusMessage !== void 0 || status === void 0 && required);
const isStateInvalid = validationState === "invalid";
const errorMessageId = isStateInvalid ? canShowError ? setId(id, "error") : ariaErrorMessage : void 0;
return /* @__PURE__ */ jsxs(
HvFormElement,
{
name,
required,
disabled,
status: validationState,
className: cx(classes.root, className),
...others,
children: [
/* @__PURE__ */ jsx(
HvLabelContainer,
{
label,
description,
classes: {
root: classes.labelContainer,
label: classes.label,
description: classes.description
},
labelProps,
descriptionProps
}
),
/* @__PURE__ */ jsx(
HvBaseDropdown,
{
ref: dropdownForkedRef,
role: "combobox",
variableWidth: true,
disabled,
readOnly,
placeholder: placeholder && !state.value ? placeholder : /* @__PURE__ */ jsx(
Placeholder,
{
ref: timeFieldRef,
name,
state,
placeholders,
className: cx(classes.placeholder, {
[classes.placeholderDisabled]: disabled
}),
...fieldProps
}
),
classes: {
header: cx(classes.dropdownHeader, {
[classes.dropdownHeaderInvalid]: isStateInvalid
}),
panel: classes.dropdownPanel,
headerOpen: classes.dropdownHeaderOpen
},
placement: "right",
adornment: /* @__PURE__ */ jsx(HvIcon, { name: "Time", className: classes.icon }),
expanded: open,
onToggle: (evt, newOpen) => {
if (disableExpand) return;
setOpen(newOpen);
onToggle?.(evt, newOpen);
},
onContainerCreation: (containerRef) => {
containerRef?.getElementsByTagName("input")[0]?.focus();
},
"aria-haspopup": "dialog",
"aria-label": ariaLabel,
"aria-labelledby": fieldProps["aria-labelledby"],
"aria-describedby": fieldProps["aria-describedby"],
"aria-invalid": isStateInvalid ? true : void 0,
"aria-errormessage": errorMessageId,
disablePortal,
popperProps: {
modifiers: [
{ name: "preventOverflow", enabled: escapeWithReference }
]
},
...otherDropdownProps,
children: /* @__PURE__ */ jsx("div", { ref: timeFieldRef, className: classes.timePopperContainer, children: state.segments.map((segment, i) => /* @__PURE__ */ jsx(
Unit,
{
state,
segment,
placeholder: placeholders[segment.type],
onAdd: () => state.increment(segment.type),
onSub: () => state.decrement(segment.type),
onChange: (evt, val) => {
state.setSegment(segment.type, Number(val));
}
},
i
)) })
}
),
canShowError && /* @__PURE__ */ jsx(
HvWarningText,
{
id: setId(id, "error"),
disableBorder: true,
className: classes.error,
children: validationMessage
}
)
]
}
);
}
);
export {
HvTimePicker,
staticClasses as timePickerClasses
};