@octopusdeploy/design-system-components
Version:
The design systems component library.
127 lines (126 loc) • 7.63 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TimePicker = TimePicker;
const jsx_runtime_1 = require("react/jsx-runtime");
const css_1 = require("@emotion/css");
const design_system_icons_1 = require("@octopusdeploy/design-system-icons");
const design_system_tokens_1 = require("@octopusdeploy/design-system-tokens");
const React = __importStar(require("react"));
const Button_1 = require("../../Button/Button");
const Dropdown_1 = require("../../Dropdown");
const FormDescription_1 = require("../Primitives/FormDescription");
const Input_1 = require("../Primitives/Input");
const InputLabel_1 = __importDefault(require("../Primitives/InputLabel"));
const InputValidationMessage_1 = require("../Primitives/InputValidationMessage");
const Listbox_1 = require("../Primitives/Listbox");
const SelectDropdown_1 = require("../Select/SelectDropdown");
const SelectOption_1 = require("../Select/SelectOption");
const SelectOptionLayout_1 = require("../Select/SelectOptionLayout");
/**
* TimePicker component
*
* @remarks Rollout currently paused — do not use in new code until further notice.
* Use `<TimeSpanSelector>` instead.
* @see <TimeSpanSelector> from @octopusdeploy/design-system-octopus-components
*
*/
function TimePicker({ increment = "hourly", value, onChange, label, placeholder, description, validationMessage, disabled = false, hasRequiredMarker = false, hasOptionalMarker = false, hasDefaultMarker = false, popover, autoFocus = false, readOnly = false, name, prefix, }) {
const dropdownButtonState = (0, Dropdown_1.useDropdownButton)({ trapFocus: false, dropdownAriaRole: "listbox" });
const { isOpen, closeDropdown, setButtonRef, toggleDropdown, setDropdownRef, dropdownAttributes, buttonAriaAttributes } = dropdownButtonState;
const [anchorElement, setAnchorElement] = React.useState(null);
const baseId = React.useId();
const inputId = `timepicker-${name ? name + "-" : ""}${baseId}`;
const getOptionHtmlId = (index) => `${dropdownAttributes.dropdownId}-option-${index}`;
const options = React.useMemo(() => {
if (increment === "half-hourly") {
return generateTimeOptions(30);
}
return generateTimeOptions(60);
}, [increment]);
const handleInputChange = (newValue) => {
onChange(newValue);
};
const handleOptionClick = (option) => {
onChange(option.value);
closeDropdown({ moveFocusToButton: true });
};
const handleButtonClick = (event) => {
event.stopPropagation();
toggleDropdown();
};
const dropdownButton = ((0, jsx_runtime_1.jsx)(Button_1.Button, { ref: setButtonRef, icon: isOpen ? (0, jsx_runtime_1.jsx)(design_system_icons_1.ChevronUpIcon, { size: 20 }) : (0, jsx_runtime_1.jsx)(design_system_icons_1.ChevronDownIcon, { size: 20 }), onClick: handleButtonClick, importance: "ghost", size: "medium", accessibleName: "Toggle time options", ...buttonAriaAttributes }));
return ((0, jsx_runtime_1.jsxs)("div", { className: containerStyles, children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(InputLabel_1.default, { label: label, htmlFor: inputId, isDisabled: disabled, hasRequiredMarker: hasRequiredMarker, hasOptionalMarker: hasOptionalMarker, hasDefaultMarker: hasDefaultMarker, popover: popover }), description && (0, jsx_runtime_1.jsx)(FormDescription_1.FormDescription, { id: `${inputId}-description`, description: description, isDisabled: disabled })] }), (0, jsx_runtime_1.jsxs)("div", { ref: setAnchorElement, className: inputContainerStyles, children: [(0, jsx_runtime_1.jsx)(Input_1.Input, { id: inputId, type: "time", value: value, onChange: handleInputChange, placeholder: placeholder, disabled: disabled, required: hasRequiredMarker, readOnly: readOnly, autoFocus: autoFocus, name: name, prefix: prefix, suffix: dropdownButton, "aria-describedby": [description ? `${inputId}-description` : null, validationMessage ? `${inputId}-validation` : null].filter(Boolean).join(" ") || undefined, validationDisplayState: validationMessage ? "error" : "none" }), isOpen && ((0, jsx_runtime_1.jsx)(SelectDropdown_1.SelectDropdown, { ref: setDropdownRef, dropdownButtonState: dropdownButtonState, anchorElement: anchorElement, children: (0, jsx_runtime_1.jsx)(Listbox_1.Listbox, { value: value, getOptionHeight: () => SelectOptionLayout_1.selectOptionHeight, options: options, onOptionSelected: handleOptionClick, getOptionHtmlId: getOptionHtmlId, accessibleName: "Select a time", renderOption: (option, selected) => (0, jsx_runtime_1.jsx)(SelectOption_1.SelectOption, { option: option, selected: selected }), focusType: "focus" }) }))] }), (0, jsx_runtime_1.jsx)(InputValidationMessage_1.InputValidationMessage, { message: validationMessage, displayState: "error", id: `${inputId}-validation` })] }));
}
const generateTimeOptions = (intervalMinutes) => {
const options = [];
const totalMinutesInDay = 24 * 60; // 1440 minutes
for (let minutes = 0; minutes < totalMinutesInDay; minutes += intervalMinutes) {
const hours = Math.floor(minutes / 60);
const mins = minutes % 60;
const hourStr = hours.toString().padStart(2, "0");
const minStr = mins.toString().padStart(2, "0");
const value = `${hourStr}:${minStr}`;
// Convert to 12-hour format for display
const displayHours = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours;
const ampm = hours < 12 ? "AM" : "PM";
const label = `${displayHours}:${minStr} ${ampm}`;
options.push({ value, label });
}
return options;
};
const containerStyles = (0, css_1.css)({
position: "relative",
display: "flex",
flexDirection: "column",
gap: design_system_tokens_1.space[8],
maxWidth: "600px",
"& *": {
boxSizing: "border-box",
},
});
const inputContainerStyles = (0, css_1.css)({
width: "12.5rem",
// Hide native calendar/clock icons in all browsers
"input[type='time']": {
justifyContent: "flex-start",
"&::-webkit-calendar-picker-indicator": {
display: "none",
},
},
});