UNPKG

@octopusdeploy/design-system-components

Version:
126 lines (125 loc) • 7.61 kB
"use strict"; 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"); const formFieldMaxWidth_1 = require("../formFieldMaxWidth"); /** * TimePicker component * * @remarks Only use in pre-approved areas, as in #project-form-uplift if unsure before using. * */ 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: formFieldMaxWidth_1.formFieldMaxWidth, "& *": { 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", }, }, });